«Король библиотеки визуализации данных» D3.js Быстрое начало работы с приложением Vue

Vue.js d3.js
«Король библиотеки визуализации данных» D3.js Быстрое начало работы с приложением Vue

предисловие

D3В последние годы былоJavaScriptОдна из самых важных библиотек визуализации данных, созданнаяMike BostockПри содержании перспективы пока безграничны, по крайней мере сейчас некого бить:

  • D3Что отличает ее от многих других библиотек, так это возможность неограниченной настройки (прямое манипулированиеSVG).
  • его нижний слойAPIпредоставить роднойSVGПрямой контроль над элементами, но это также достигается за счет высокой кривой обучения.
  • мы положимD3а такжеVueкомбинировать - использоватьVueДинамическая привязка данных, четкий синтаксис и модульная структура позволяют в полной мере использоватьD3лучшее выступление.

Согласно широкому определению, D3 можно разделить на следующие подбиблиотеки:

  1. подавляющее большинствоD3Курсы или книги, посвященныеDOMС точки зрения эксплуатации это явно противоречит концепции веб-фреймворков последних лет.
  2. для визуализации данныхD3, суть которого заключается в украшении данных инструкциями по рисованию, создании новых рисуемых данных из исходных данных, созданииSVGпуть и из данных и методов вDOMВозможность создавать элементы визуализации данных, такие как оси, в формате .

3. Существует множество инструментов для управления DOM, все из которых можно найти вD3Интегрированные возможности визуализации данных. Это тожеD3может работать сVueОдна из причин бесшовной интеграции.

Для этого нам не нужноD3 DOMНачните изучать функцию работы и начните работу непосредственно с примераD3.

1. D3.js шаг за шагом

Шаблоны для следующих примеров имеют следующий вид:

<html>
    <head>
        <link rel="stylesheet" href="index.css">
        <title>Learn D3.js</title>
    </head>
    <body>
        <!--或其它标签-->
        <h1>First heading</h1>
        
        <script src="https://d3js.org/d3.v4.min.js"></script>
        <script src="index.js"></script>
    </body>
</html>

1. Выбор и работа

Первое, чему вам нужно научиться, это как пользоватьсяD3.jsвыбрать и работатьDOMэлемент. Библиотека работаетDOMАспекты на самом деле довольно мощные, так что теоретически их можно использовать какjQueryзамена.Пожалуйста, добавьте и запустите следующий код построчно.

// index.js
d3.select();
d3.selectAll();

d3.select('h1').style('color', 'red')
.attr('class', 'heading')
.text('Updated h1 tag');

d3.select('body').append('p').text('First Paragraph');
d3.select('body').append('p').text('Second Paragraph');
d3.select('body').append('p').text('Third Paragraph');

d3.selectAll('p').style('')

2. Загрузка и привязка данных

При создании визуализаций важно понимать, как данные загружаются и привязываются к модели DOM. Итак, в этом примере вы узнаете и то, и другое.

let dataset = [1, 2, 3, 4, 5];

d3.select('body')
    .selectAll('p')
    .data(dataset)
    .enter()
    .append('p') // appends paragraph for each data element
    .text('D3 is awesome!!');
    //.text(function(d) { return d; });

3. Создайте простую гистограмму

Сначала нужно добавитьsvgЭтикетка

<h1>Bar Chart using D3.js</h1>

<svg class="bar-chart"></svg>

затем вindex.jsДобавлено (ключевые примечания добавлены):

// 数据集
let dataset = [80, 100, 56, 120, 180, 30, 40, 120, 160];
// 定义svg图形宽高,以及柱状图间距
let svgWidth = 500, svgHeight = 300, barPadding = 5;
// 通过图形计算每个柱状宽度
let barWidth = (svgWidth / dataset.length);

// 绘制图形
let svg = d3.select('svg')
    .attr("width", svgWidth)
    .attr("height", svgHeight);

// rect,长方形
// 文档:http://www.w3school.com.cn/svg/svg_rect.asp

let barChart = svg.selectAll("rect")
    .data(dataset) //绑定数组
    .enter() // 指定选择集的enter部分
    .append("rect") // 添加足够数量的矩形
    .attr("y", d => svgHeight - d ) // d为数据集每一项的值, 取y坐标
    .attr("height", d => d) // 设定高度
    .attr("width", barWidth - barPadding) // 设定宽度
    .attr("transform", (d, i) =>  {
        let translate = [barWidth * i, 0]; 
        return "translate("+ translate +")";
    }); // 实际是计算每一项值的x坐标

4. Отобразите значение над графиком

Затем вам нужно создать в приведенном выше кодеsvgизtextтекст

let text = svg.selectAll("text")
    .data(dataset)
    .enter()
    .append("text")
    .text(d => d)
    .attr("y", (d, i) => svgHeight - d - 2)
    .attr("x", (d, i) =>  barWidth * i)
    .attr("fill", "#A64C38");

Процесс относительно прост, то есть вернуть текст, вычислить координаты x/y и заполнить цветом.

5. scales: функция масштаба

D3Важным понятием здесь является масштаб. Масштаб — это функция, которая отображает набор входных доменов в выходной домен. Отображение — это отношение между элементами в двух наборах данных, которые соответствуют друг другу. Например, если ввод равен 1, вывод равен 100, ввод равен 5, а вывод равен 10000, то соотношением отображения является определяемый вами масштаб.

D3Существуют различные масштабные функции, непрерывные и прерывистые, в этом примере вы узнаетеd3.scaleLinear(),Линейная шкала.

5.1 d3.scaleLinear(), линейная шкала

использоватьd3.scaleLinear()Создайте линейную шкалу, где:

  • domain()поле ввода
  • range()это выходной домен
  • эквивалентноdomainНабор данных в сопоставлен сrangeНабор данных.
let scale = d3.scaleLinear().domain([1,5]).range([0,100])

Картографические отношения:

Стоит отметить, что приведенный выше код простоопределяет правило сопоставления, входное значение отображения не ограничиваетсяdomain()поле ввода в .

scale(1) // 输出:0
scale(4) // 输出:75
scale(5) // 输出:100
scale(-1) // 输出:-50
scale(10) // 输出:225

Итак, давайте превратим3~4Пример:

let dataset = [1,2,3,4,5];

let svgWidth = 500, svgHeight = 300, barPadding = 5;
let barWidth = (svgWidth / dataset.length);


let svg = d3.select('svg')
    .attr("width", svgWidth)
    .attr("height", svgHeight);
    
let yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset)])
    .range([0, svgHeight]);
        
let barChart = svg.selectAll("rect")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("y", d => svgHeight - yScale(d))
    .attr("height", d => yScale(d))
    .attr("width", barWidth - barPadding)
    .attr("transform", (d, i) => {
        let translate = [barWidth * i, 0]; 
        return "translate("+ translate +")";
    });

Тогда вы получите следующий график:

6. Axes:ось

Оси являются неотъемлемой частью любой диаграммы, и в этом примере будет использоваться описанная выше функция масштабирования.

let data= [80, 100, 56, 120, 180, 30, 40, 120, 160];

let svgWidth = 500, svgHeight = 300;

let svg = d3.select('svg')
    .attr("width", svgWidth)
    .attr("height", svgHeight);

// 首先是拿最大值构建x轴坐标
let xScale = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([0, svgWidth]);
         
// 接下来是反转值,用作y轴坐标。
let yScale = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([svgHeight, 0]);

// 横轴的API使用
let x_axis = d3.axisBottom()
    .scale(xScale);
    
// 纵轴的API使用
let y_axis = d3.axisLeft()
    .scale(yScale);
    
// 在svg中提供了如g元素这样的将多个元素组织在一起的元素。
// 由g元素编组在一起的可以设置相同的颜色,可以进行坐标变换等,类似于Vue中的 <template>

svg.append("g")
    .attr("transform", "translate(50, 10)")
    .call(y_axis);
         
let xAxisTranslate = svgHeight - 20;
         
svg.append("g")
    .attr("transform", "translate(50, " + xAxisTranslate  +")")
    .call(x_axis);

7. Создавайте простыеSVGэлемент

В нем вы создадите<rect>,<circle>а также<line>элемент

let svgWidth = 600, svgHeight = 500;
let svg = d3.select("svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight)
    .attr("class", "svg-container")
    
let line = svg.append("line")
    .attr("x1", 100)
    .attr("x2", 500)
    .attr("y1", 50)
    .attr("y2", 50)
    .attr("stroke", "red");
    
let rect = svg.append("rect")
    .attr("x", 100)
    .attr("y", 100)
    .attr("width", 200)
    .attr("height", 100)
    .attr("fill", "#9B95FF");
    
let circle = svg.append("circle")
    .attr("cx", 200)
    .attr("cy", 300)
    .attr("r", 80)
    .attr("fill", "#7CE8D5");

8. Создайте круговую диаграмму

let data = [
    {"platform": "Android", "percentage": 40.11}, 
    {"platform": "Windows", "percentage": 36.69},
    {"platform": "iOS", "percentage": 13.06}
];

let svgWidth = 500, svgHeight = 300, radius =  Math.min(svgWidth, svgHeight) / 2;
let svg = d3.select('svg')
    .attr("width", svgWidth)
    .attr("height", svgHeight);

//Create group element to hold pie chart    
let g = svg.append("g")
    .attr("transform", "translate(" + radius + "," + radius + ")") ;

// d3.scaleOrdinal() 序数比例尺
// schemeCategory10, 颜色比例尺
// D3提供了一些颜色比例尺,10就是10种颜色,20就是20种:
let color = d3.scaleOrdinal(d3.schemeCategory10);

let pie = d3.pie().value(d => d.percentage);

let path = d3.arc()
    .outerRadius(radius)
    .innerRadius(0);
 
let arc = g.selectAll("arc")
    .data(pie(data))
    .enter()
    .append("g");

arc.append("path")
    .attr("d", path)
    .attr("fill", d => color(d.data.percentage));
        
let label = d3.arc()
    .outerRadius(radius)
    .innerRadius(0);
            
arc.append("text")
    .attr("transform",  d => `translate(${label.centroid(d)})`)
    .attr("text-anchor", "middle")
    .text(d => `${d.data.platform}:${d.data.percentage}%`);

9. Создайте линейную диаграмму

Наконец, вы узнаете, как создать линейный график, показывающий цену биткойна за последние четыре месяца. Для получения данных вы будете использовать внешний API. Проект также объединяет многие концепции, которые вы узнали в ходе курса, так что это отличное визуальное завершение курса.

// 外部API,注意日期记得补零
const api = 'https://api.coindesk.com/v1/bpi/historical/close.json?start=2019-03-31&end=2019-07-01';

/**
 * dom内容加载完毕时,从API中加载数据
 */
document.addEventListener("DOMContentLoaded", function(event) {
fetch(api)
    .then(response => response.json())
    .then(data => {
        let parsedData = parseData(data);
        drawChart(parsedData);
    })
    .catch(err =>  console.log(err))
});

/**
 * 将数据解析为键值对
 */
parseData = data =>{
    let arr = [];
    for (let i in data.bpi) {
        arr.push({
            date: new Date(i), //date
            value: +data.bpi[i] //convert string to number
        });
    }
    return arr;
}

/**
 * 创建图表
 */
drawChart  = data => {
let svgWidth = 600, svgHeight = 400;
let margin = { top: 20, right: 20, bottom: 30, left: 50 };
let width = svgWidth - margin.left - margin.right;
let height = svgHeight - margin.top - margin.bottom;

let svg = d3.select('svg')
    .attr("width", svgWidth)
    .attr("height", svgHeight);
    
let g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

let x = d3.scaleTime()
    .rangeRound([0, width]);

let y = d3.scaleLinear()
    .rangeRound([height, 0]);

let line = d3.line()
    .x(d=> x(d.date))
    .y(d=> y(d.value))
    x.domain(d3.extent(data, function(d) { return d.date }));
    y.domain(d3.extent(data, function(d) { return d.value }));

g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x))
    .select(".domain")
    .remove();

g.append("g")
    .call(d3.axisLeft(y))
    .append("text")
    .attr("fill", "#000")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", "0.71em")
    .attr("text-anchor", "end")
    .text("Price ($)");

g.append("path")
    .datum(data)
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .attr("stroke-width", 1.5)
    .attr("d", line);
}

Все исходные примеры выше взяты из:Learn D3 for free.

scrimbaэто очень удивительный сайт. Он построен с использованием интерактивного инструмента для создания снимков экрана.

Все операции:

Приостановить скринкаст → отредактировать код → запустить его! → Просмотр изменений

Хорошо стоит волна Amway. Затем перейдите ко второй части:Vueиспользуется вD3.jsправильная осанка

2. Vueиспользуется вD3.jsправильная осанка

мы будем использоватьD3а такжеVueСоздайте базовый компонент гистограммы. В сети есть куча примеров, но мы сосредоточимся на написанииVue, а не злоупотреблятьD3.

1. Установите зависимости

Во-первых, нам нужно установить зависимости для проекта. Мы можем просто установить и использоватьD3Вся библиотека:

npm i d3

Но, как я уже говорил, на самом делеD3Представляет собой набор из нескольких подбиблиотек.Учитывая оптимизацию проекта, мы устанавливаем только необходимые модули.

использоватьVue CliПросто инициализируйте проект.

2. Создайте гистограмму

3. Импорт модуля гистограммы

4. Создатьsvgэлемент

потому чтоVueХарактеристики ответа данных нам не нужно использоватьD3действоватьDOMНабор для создания цепочки.

5. Ответ данных и размера окна

существуетmountedВ хук мы добавим прослушиватель события изменения размера окна, который вызовет анимацию рисования и<svg>Размер устанавливается в пропорции нового окна. Не рендерим сразу, а ждем300миллисекунд, чтобы обеспечить полное изменение размера окна.

Следующее завершеноBarChart.vue, пожалуйста, ешьте с примечаниями:

<template>
  <div id="container" class="svg-container" align="center">
    <h1>{{ title }}</h1>
    <svg v-if="redrawToggle === true" :width="svgWidth" :height="svgHeight">
      <g>
        <rect
          v-for="item in data"
          class="bar-positive"
          :key="item[xKey]"
          :x="xScale(item[xKey])"
          :y="yScale(0)"
          :width="xScale.bandwidth()"
          :height="0"
        ></rect>
      </g>
    </svg>
  </div>
</template>

<script>
import { scaleLinear, scaleBand } from "d3-scale";
import { max, min } from "d3-array";
import { selectAll } from "d3-selection";
import { transition } from "d3-transition";

export default {
  name: "BarChart",
  props: {
    title: String,
    xKey: String,
    yKey: String,
    data: Array
  },
  mounted() {
    this.svgWidth = document.getElementById("container").offsetWidth * 0.75;
    this.AddResizeListener();
    this.AnimateLoad();
  },
  data: () => ({
    svgWidth: 0,
    redrawToggle: true
  }),
  methods: {
    // 绘制柱形
    AnimateLoad() {
      selectAll("rect")
        .data(this.data)
        .transition()
        .delay((d, i) => {
          return i * 150;
        })
        .duration(1000)
        .attr("y", d => {
          return this.yScale(d[this.yKey]);
        })
        .attr("height", d => {
          return this.svgHeight - this.yScale(d[this.yKey]);
        });
    },
    // 调整窗口大小后300毫秒重新绘制图表
    // 即响应式绘制
    AddResizeListener() {
      window.addEventListener("resize", () => {
        this.$data.redrawToggle = false;
        setTimeout(() => {
          this.$data.redrawToggle = true;
          this.$data.svgWidth =
            document.getElementById("container").offsetWidth * 0.75;
          this.AnimateLoad();
        }, 300);
      });
    }
  },
  computed: {
    dataMax() {
      return max(this.data, d => {
        return d[this.yKey];
      });
    },
    dataMin() {
      return min(this.data, d => {
        return d[this.yKey];
      });
    },
    xScale() {
      return scaleBand()
        .rangeRound([0, this.svgWidth])
        .padding(0.1)
        .domain(
          this.data.map(d => {
            return d[this.xKey];
          })
        );
    },
    // 通过线性比例尺自动生成
    yScale() {
      return scaleLinear()
        .rangeRound([this.svgHeight, 0])
        .domain([this.dataMin > 0 ? 0 : this.dataMin, this.dataMax]);
    },
    svgHeight() {
      return this.svgWidth / 1.61803398875; // 黄金比例
    }
  }
};
</script>

<style scoped>
.bar-positive {
  fill: steelblue;
  transition: r 0.2s ease-in-out;
}

.bar-positive:hover {
  fill: brown;
}

.svg-container {
  display: inline-block;
  position: relative;
  width: 100%;
  padding-bottom: 1%;
  vertical-align: top;
  overflow: hidden;
}
</style>

Мы начнем с родительского компонентаApp.vueполучить данные:

<template>
  <div id="app">
    <BarChart title="Bar Chart" xKey="name" yKey="amount" :data="barChartData"/>
  </div>
</template>

<script>
import BarChart from "./components/BarChart.vue";

export default {
  name: "App",
  components: {
    BarChart
  },
  data: () => ({
    barChartData: [
      {
        name: "张三",
        amount: 25
      },
      {
        name: "李四",
        amount: 40
      },
      {
        name: "老王",
        amount: 15
      },
      {
        name: "老赖",
        amount: 9
      }
    ]
  })
};
</script>

<style>
#app {
  font-family: "Open Sans", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #282f36;
  margin-top: 30px;
}
</style>

В этот моментyarn run serveЗатем вы увидите:

Кажется, что есть еще недостаток для отображения значения.Учитывая, что высота изображения генерируется в соответствии с масштабом, мы корректируем координату y:

yScale() {
  return scaleLinear()
    .rangeRound([this.svgHeight, 0])
    .domain([this.dataMin > 0 ? 0 : this.dataMin + 2, this.dataMax + 2]);
},

существуетAnimateLoad()Добавьте в конце:

selectAll("text")
  .data(this.data)
  .enter()

Наконец в<g>Добавить к элементу:

<text
  v-for="item in data"
  :key="item[xKey].amount"
  :x="xScale(item[xKey]) + 30"
  :y="yScale(item[yKey]) - 2"
  fill="red"
>{{ item[xKey]}} {{ item[yKey]}}
</text>

3. Справочные статьи

4. Резюме

Библиотека почтиMike BostockВыполняется одним человеком и пользуется отличной репутацией в академических кругах и профессиональных командах.

  • D3ближе к низу, сg2,echartsразные,d3может работать напрямуюsvg, поэтому он имеет большую степень свободы и может реализовать практически любые требования к 2D-дизайну.
  • Как его названиеData Driven Documents, суть которого заключается в объединении данных сDOMсвязывать и сопоставлять данные сDOMхарактеристики.
  • D3Дольше, чем визуализация, не более, чем визуализация, также обеспечивает数据处理,数据分析,DOMуправление и многие другие функции.
  • Если у вас есть интерфейс, который хочет углубиться в визуализацию данных,D3должны учиться.

владелецD3В конце концов, только воображение, а не технология, ограничивает уровень работы.

Адрес источника:кликните сюда

❤️ После прочтения трех вещей

Если вы найдете этот контент вдохновляющим, я хотел бы пригласить вас сделать мне три небольших одолжения:

  1. Ставьте лайк, чтобы больше людей увидело этот контент
  2. Обратите внимание на паблик «Учитель фронтенд-убеждения», и время от времени делитесь оригинальными знаниями.
  3. Также смотрите другие статьи

](nuggets.capable/post/684490…)