"The King of Data Visualization Library" D3.js gets started with Vue application quickly

"The King of Data Visualization Library" D3.js gets started with Vue application quickly

Preface

D3In recent years has been JavaScriptone of the most important data visualization library, the creator of the MikeBostockmaintenance, the outlook remains immeasurable, at least for now there is no play of:

  • D3The difference from many other libraries is the unlimited customization capability (direct operation SVG).
  • Its underlying APIprovides native SVGdirect control element, but it also brings high cost learning curve.
  • We will D3and Vuetogether - using Vuedynamic data binding, clean syntax and modular structure, can give full play to D3the best performance.

According to the broad definition, D3 can be divided into the following sub-libraries:

  1. Most of the D3courses or books, will focus on explaining its DOMoperation function, but obviously contrary to the concept of web frameworks in recent years.
  2. For data visualization D3, the core is decorated using the drawing instruction data, create new data can be drawn from the source data, generating a SVGpath from the data and methods as well as DOMcreating data visualization function elements (e.g., shaft) of.
  1. There are many tools for managing DOM, all of these tools are available in the D3visualization capabilities to integrate data. It is also D3capable of and Vueone of the reasons seamless combination.

Here, we do not need from D3 DOMthe beginning to learn the operating functions directly to the entry by example D3.

D3.js gradually enters the door

The templates of the following examples are in the following form:

<html>
    <head>
        <link rel="stylesheet" href="index.css">
        <title>Learn D3.js</title>
    </head>
    <body>
        <!--or other tags-->
        <h1>First heading</h1>

        <script src="https://d3js.org/d3.v4.min.js"></script>
        <script src="index.js"></script>
    </body>
</html>

1. Selection and operation

The first thing you need to learn is how to use D3.js to select and manipulate DOM elements. The library is actually very powerful in terms of operating DOM, so in theory it can be used as a jQuerysubstitute. Please add and run the following code line by line.

//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('2.Paragraph');
d3.select('body').append('p').text('Third Paragraph');

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

2. Data loading and binding

When you are creating a visualization, it is important to understand how to load data and bind it to the DOM. So in this example, you will learn these two points.

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. Create a simple histogram

1. we need to add a svgtag

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

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

Then index.jsadd the (critical comments have been added):

//data set
let dataset = [80, 100, 56, 120, 180, 30, 40, 120, 160];
//Define the width and height of the svg graphic, and the spacing of the histogram
let svgWidth = 500, svgHeight = 300, barPadding = 5;
//Calculate the width of each column by graph
let barWidth = (svgWidth/dataset.length);

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

//rect, rectangle
//Document: http://www.w3school.com.cn/svg/svg_rect.asp

let barChart = svg.selectAll("rect")
    .data(dataset)//Bind array
    .enter()//Specify the enter part of the selection set
    .append("rect")//add a sufficient number of rectangles
    .attr("y", d => svgHeight-d)//d is the value of each item in the data set, take the y coordinate
    .attr("height", d => d)//set height
    .attr("width", barWidth-barPadding)//set the width
    .attr("transform", (d, i) => {
        let translate = [barWidth * i, 0]; 
        return "translate("+ translate +")";
    });//Actually calculate the x coordinate of each item value

4. Display the value above the graph

Then you need to create in the above code svgin the texttext

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");

The process is relatively simple, that is, return the text, calculate the x/y coordinates, and fill in the color.

5 scales.: Scale function

D3An important concept in this is scale. The scale is a function that maps a set of input domains to output domains. Mapping is the relationship between the elements of two data sets corresponding to each other. For example, if the input is 1, the output is 100, the input is 5, and the output is 10000, then the mapping relationship is the scale you defined.

D3There are various scales functions, continuity and non-continuity, in this example, you will learn d3.scaleLinear(), the linear scale .

5.1 d3.scaleLinear(), linear scale

Use d3.scaleLinear()to create a linear scale, in which:

  • domain()Is the input field
  • range()Is the output domain
  • Corresponds to domainthe data sets are mapped to rangethe data set.
let scale = d3.scaleLinear().domain([1,5]).range([0,100])

Mapping relations:

It is noted that the above code simply defines a mapping rule , the entered values are not limited to the domain()input field of.

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

So we have to transform 3~4the examples:

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 +")";
    });

Then you will get the following graphics:

6. Axes:Axis

The axis is an integral part of any chart. In this example, the scale function mentioned above will be used.

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);

//The first is to take the maximum value to construct the x-axis coordinate
let xScale = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([0, svgWidth]);

//Next is the reverse value, which is used as the y-axis coordinate.
let yScale = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([svgHeight, 0]);

//API usage of horizontal axis
let x_axis = d3.axisBottom()
    .scale(xScale);

//API usage of vertical axis
let y_axis = d3.axisLeft()
    .scale(yScale);

//An element that organizes multiple elements together, such as the g element, is provided in the svg.
//Grouped by g elements, the same color can be set, coordinate transformation can be performed, etc., similar to the <template> in Vue

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. Create simple SVGelements

In it, you will create <rect>, <circle>and <line>the elements

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. Create a pie chart

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() Ordinal scale
//schemeCategory10, color scale
//D3 provides some color scales, 10 is 10 colors, 20 is 20 colors:
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. Create a line chart

Finally, you will learn how to create a line chart to show Bitcoin prices in the past four months. To get the data, you will use an external API. This project also combines many of the concepts you have learned throughout the course, so this is a good visualization course to end.

//External API, pay attention to the date and remember to fill in zero
const api ='https://api.coindesk.com/v1/bpi/historical/close.json?start=2019-03-31&end=2019-07-01';

/**
 * When the dom content is loaded, load the data from the 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))
});

/**
 * Parse data into key-value pairs
 */
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;
}

/**
 * Create a chart
 */
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);
}

The original examples above are from: Learn D3 for free. scrimba is a very amazing website. It is built using interactive coding screenshot tools.

All operations are:

Pause the screencast video → edit the code → run it! → View changes

Very worthy of Amway wave. Next to the second part: Vueuse inD3.js correct posture

2. VueUsed inD3.js correct posture

We will use D3and Vuebuild a basic component histogram. There are a bunch of examples online, but we will focus on writingVue instead of misusing D3.

1. Installation dependencies

1. we need to install dependencies for the project. We can simply install and useD3 the entire library:

npm i d3

But as I mentioned earlier, actually D3 a collection of several sub-libraries, taking into account the optimization of the project, we only install the modules required.

use VueCli initialize the project can be.

2. Create a histogram

3. Import the histogram module

4. Create svgelements

Due to the Vuecharacteristics of the data in response, we do not need the D3operation DOMthat set the chain of creation.

5. Data and window size response

In the mountedhook, we'll resize the window to add an event listener, it will trigger drawn animation and <svg>size to the proportion of the new window. We do not rendered immediately, but wait 300milliseconds, to ensure complete resize the window.

The following is complete BarChart.vue, please eat with notes:

<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: {
   //draw a column
    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]);
        });
    },
   //Redraw the chart 300 milliseconds after adjusting the window size
   //Responsive drawing
    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];
          })
        );
    },
   //Automatically generated by linear scale
    yScale() {
      return scaleLinear()
        .rangeRound([this.svgHeight, 0])
        .domain([this.dataMin> 0? 0: this.dataMin, this.dataMax]);
    },
    svgHeight() {
      return this.svgWidth/1.61803398875;//golden ratio
    }
  }
};
</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>

We will parent component App.vueto obtain data:

<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: "Zhang San",
        amount: 25
      },
      {
        name: "Li Si",
        amount: 40
      },
      {
        name: "Old King",
        amount: 15
      },
      {
        name: "Old Lai",
        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>

This time yarn run serveafter'll see:

It seems that there is still a shortcoming to display the value, considering that the height of the map is generated according to the scale, we adjust the y coordinate:

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

In AnimateLoad()the end add:

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

In the last <g>element added:

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

3. Reference articles

  • D3 is not a Data Visualization Library
  • Scale bars commonly used in D3
  • D3 vs G2 vs Echarts
  • Dynamic Data Visualizations With Vue.js and D3

4. Summary

The library with almost MikeBostocksingle-handedly completed, and enjoy a great reputation in the academic, professional team.

  • D3It is closer to the bottom layer, and can be directly operated with g2and echartsdifferent, so it has a great degree of freedom, and almost any 2d design requirement can be realized.d3svg
  • As its name DataDrivenDocuments, the nature of the data to the DOMbinding, and the data mapped to DOMthe attribute.
  • D3Visualization longer, rather than limited to visualization, is also provided 数据处理, 数据分析, DOMoperation, and many other functions.
  • If you want to deepen the front-end of data visualization, you D3have to learn it.

Master D3, the only limit is the imagination of the level of work rather than technical.

Source address: click here

Author Nuggets Article Collection

If you need to repost it to the official account, just call me to add the whitelist.

  • "True® Full Stack Road" Back-end guide for web front-end development
  • "Vue Practice" A Vue CLI plug-in in 5 minutes
  • "Vue practice" arm your front-end project
  • "Intermediate and advanced front-end interview" JavaScript handwritten code invincible cheats
  • ``Learn from the source code'' Vue question answers that interviewers don't know
  • "Learn from the source code" JS Sao operation in Vue source code
  • "Learn from the source code" thoroughly understand the Vue option Props
  • The correct posture of the "Vue practice" project to upgrade vue-cli3
  • Why can't you understand the JavaScript scope chain?
Reference: https://cloud.tencent.com/developer/article/1488441 "The King of Data Visualization Library" D3.js to quickly get started with Vue applications-Cloud + Community-Tencent Cloud