"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, it has been one of the JavaScriptmost important data visualization libraries. Under Mike Bostockthe maintenance of the creator , the prospects are still boundless, at least there is no one that can be used for now:

  • D3The difference from many other libraries is the unlimited customization capability (direct operation SVG).
  • Its bottom layer APIprovides SVGdirect control over native elements, but it also brings high learning curve costs.
  • We will combine D3and Vuetogether-the use Vueof dynamic data binding, clear 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 D3courses or books will focus on their DOMoperational functions, but this is obviously contrary to the concept of web frameworks in recent years.
  2. For data visualization D3, its core is to use drawing instructions to decorate data, create new drawable data from source data, generate SVGpaths, and DOMcreate data visualization elements (such as axes) from data and methods .

3. There are many tools for managing DOM, all of which can D3integrate data visualization functions in it. It is also D3capable of and Vueone of the reasons seamless combination.

At this point, we don't need to start from the D3 DOMoperation function, and get started directly through examples D3.

1. 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>
        <!-- -->
        <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.jsselection and manipulation DOMelements. The library DOMis actually very powerful in terms of operation , so theoretically it can be used as jQuerya substitute. 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

First you need to add a svglabel

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

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

Then index.jsadd in (key notes have been added):

// 
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. 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 to d3.scaleLinear()create a linear scale, where:

  • domain()Is the input field
  • range()Is the output domain
  • It is equivalent to domainthe data set in which the data set in is mapped range.
let scale = d3.scaleLinear().domain([1,5]).range([0,100])
 

Mapping relations:

It is worth noting that the above code only defines a mapping rule , and the input value of the mapping is not limited domain()to the input field in.

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

So let's transform 3 4the example:

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

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

In it, you will create <rect>, <circle>and <line>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()  
//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. 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 integrates many of the concepts you have learned throughout the course, so this is a good visualization course to end.

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

 

The original examples above are all from: Learn D3 for free .

scrimbaIt 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

It's worthy of Amway's wave. Next to the second part: the correct posture Vueused D3.jsin

2. The correct posture Vueused D3.jsin

We will use D3and Vuebuild a basic histogram component. There are a bunch of examples online, but we will focus on writing Vue, not abuse D3.

1. Installation dependencies

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

npm i d3
 

But as I mentioned earlier, it D3is actually a collection of several sub-libraries. Considering the optimization of the project, we only install the required modules.

Use to Vue Cliinitialize the project.

2. Create a histogram

3. Import the histogram module

4. Create svgElements

Due Vueto the characteristics of data response, we don't need to use the chained creation of D3operations DOM.

5. Data and window size response

In the mountedhook, we will add a listener for the window resize event, which will trigger the drawing animation and set the <svg>size to the proportion of the new window. Instead of rendering immediately, we wait for 300milliseconds to ensure that the window is fully resized.

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: {
   // 
    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>
 

We will App.vueget the data from the parent component :

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

After this time yarn run serve, you will 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]);
},
 

AnimateLoad()Add at the end:

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

Finally <g>, add in the element:

<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. Reference articles

4. Summary

The library with almost Mike Bostocksingle-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 can almost achieve any 2d design requirements.d3svg
  • As its name Data Driven Documents, 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

After watching three things

If you think this content is quite inspiring for you, I would like to invite you to do three small favors for me:

  1. Like it, so that more people can see this content (If you don t like it, it s a hooligan-_-)
  2. Pay attention to the public account "Front-end adviser" and share original knowledge from time to time.
  3. Also look at other articles

]( juejin.im/post/684490 )