In fact, the purpose of data visualization is to visually display data, for example, to convert the amount of data that takes hours or even longer to summarize into indicators that can be read at a glance. The difference between the two groups of data obtained through the calculation of addition, subtraction, multiplication and division and various formulas can be compared in terms of color sensitivity and length. Data visualization is a powerful weapon for communicating complex information. By visualizing information, our brains are better able to capture and retain valid information and increase the impression of information. But if the data visualization is weak, it will have negative effects; Wrong expression often damages the transmission of data and completely misrepresents and misleads users. Therefore, it is more necessary for us to present data in multiple dimensions, not at a single level. At present, there are a variety of third-party libraries to achieve data visualization: Highcharts, Echarts, Chart.js, D3.js, etc. In general, there are currently third-party libraries based on two browser graphics rendering technologies: Canvas and SVG. Canvas and webGL are encapsulated based on openGL. However, webGL has a steep learning curve because it is closer to openGL. Here we will talk about Canvas and SVG. Here is a comparison of the two graphic rendering techniques

SVG Canvas
Resolution independent Resolution dependent
Support event handlers Event handlers are not supported
Best suited for applications with large render areas Weak text rendering capability
High complexity slows down rendering (any application that overuses DOM is not fast) Ability to save the resulting image in.png or.jpg format
Not suitable for game applications Best suited for graphics-intensive games
You can attach a JavaScript event handler to an element. In SVG, every graph that is drawn is treated as an object. Once the graph has been drawn, it does not continue to receive attention from the browser. If its position changes, the entire scene needs to be redrawn.

Echarts

Baidu is an open source data visualization tool, a pure Javascript chart library, can run smoothly on PC and mobile devices, compatible with most current browsers (IE6/7/8/9/10/11, Chrome, Firefox, Safari, etc.), The bottom layer relies on the lightweight Canvas library ZRender. ECharts provides intuitive, vivid, interactive and highly personalized data visualization charts. Here is a simple way to use it:

option = {
    xAxis: {
        type: 'category'.data: ['Mon'.'Tue'.'Wed'.'Thu'.'Fri'.'Sat'.'Sun']},yAxis: {
        type: 'value'
    },
    series: [{
        data: [820.932.901.934.1290.1330.1320].type: 'line'}};Copy the code

How to support multiple rendering methods

Echarts supports SVG, Canvas, VML and other low-level technologies. Echarts will make different rendering implementations according to the specific rendering platform. The bottom layer is a class called PathProxy, which is responsible for the low-level drawing instructions. Depending on the renderer, the underlying implementation is different.

const rect = new zrender.Rect({
  shape: {
    x: 10.y: 10.width: 80.height: 80}});Copy the code

How is event handling supported

It is not possible to bind events to an element on canvas, so we bind events to the entire chart container. When performing event processing, determine whether the mouse is within the graph. Because the graphics are rotated and scaled, you need to switch the mouse coordinates to the graphics coordinate system. After obtaining the coordinate system of the graph, you can know the relationship between the mouse and the graph, and you can handle the corresponding events.

How are SVG renderings partially updated

Once the canvas is changed during rendering, it will be completely redrawn, but it is very efficient. For SVG, if the scatter diagram has a thousand nodes, then the DOM has a thousand nodes. It would be very inefficient to remove and then add DOM elements to each frame. Therefore, virtual-DOM method is used here. By maintaining a list of render objects, each frame diff the list of new render objects with that of the previous frame to obtain the list of newly added, modified and deleted render objects, and adjust Dom related nodes according to the list.

The concrete realization of data visualization

There are two implementations, one canvas and one SVG.

Canvas

Here realized a simple library, can draw bar chart, pie chart, line chart, radar chart. Here’s how to use it:

const canvas = document.getElementById('canvas');
const data = [{
	name: 'basketball'.value: 2260}, {name: 'badminton'.value: 1170}, {name: Table tennis.value: 1230}, {name: 'football'.value: 1450,},];const settings = {
	type: 'bar'
};
new Chart(canvas, data, {
	title: 'Sport'
}, settings);
Copy the code

Below are the renderings

if (settings) {
  Object.keys(settings).map((key) = > {
    this[key] = settings[key];
  });
}
Copy the code

This section will allow the passed parameters to override the existing default Settings, colors, and coordinates. Some Settings need to be computed, such as each unit length marker, to get the ratio of each value. Such as:

this.totalValue = this.getTotalValue();
this.maxValue = this.getMaxValue();
function getTotalValue() {
  let total = 0;
  this.data.map((item) = > {
    total += item.value;
  });
  return total;
}
Copy the code

Here, the total number is calculated first, and then the proportion of each piece of data is calculated when drawing the pie chart, and the plot is carried out. The following section will draw different shapes based on the type passed in. Here is the implementation:

if (this.type === 'bar' || this.type === 'line') {
  this.drawBarUpdate();
} else if (this.type === 'pie' || this.type === 'ring') {
  this.drawPieUpdate();
} else if (this.type === 'radar') {
  this.drawRadarUpdate();
}
Copy the code

Look at the draBarUpdate implementation:

  drawBarUpdate() {
    this.drawAxis();
    this.drawPoint();
    this.drawTitle();
    this.drawBarChart();
  }
Copy the code

The first three functions are used for the basic structure, axis, point, and heading. The fourth function is used to draw graphs. Mainly with the help of several methods of Canvas fillStyle: set the color, gradient or mode of filling painting; StrokeStyle: Set the color, gradient or model of the stroke; BeginPath: Starts a path or resets the current path. Arc (x, y, r, startAngle, endAngle, direction)x and y represent the x and y coordinates of the center of a circle. StartAngle is the startAngle, endAngle is the endAngle, direction represents clockwise or counterclockwise plot. First, according to the length of the data, determine the length and coordinates of each data and then use the following operations to draw.

this.ctx.beginPath();
this.ctx.arc(x, y, radius, startAngle, endAngle, direction);
this.ctx.fill();
Copy the code

So you can draw the graph

SVG

SVG is a language for describing 2D graphics using XML. SVG is based on XML, which means that every element of the SVG DOM is available. You can attach javaScript event handlers to each element. SVG differs from Canvas in that it provides many basic shapes. For example rect: circle; Circle, elliptic; Ellipse: a straight line; Line: line; Polyline: a polygon; Polygon: indicates a path. Use pie.js in the common module. Here’s how to use it:

var myPie = new Pie({
  pieR: 40./ / outer diameter
  donutR: 35./ / inner diameter
  rotation: - 90..// Rotate to start from the positive y direction
  strokeColor: '#FFF'.// Use white stroke
  animation: true.// Enable default display animation
  slices: [{
    color: '#E3E3E3'.// The color of the first piece
    percent: 0.1 // The ratio of all plots
  }, {
    color: '#5FC2F5'.// Second slice color
    percent: 0.2 // Ratio of the second section area
  }, {
    percent: 0.3 // Ratio of the third section area
  }, {
    percent: 0.4 // Ratio of the fourth section area}}]); $('body').append(myPie.getNode()); // Insert pie chart.
Copy the code

Below are the renderings

this.args = $.extend({
  pieR: 100.slices: [{
    percent: 1,
  }],
}, args);
$.each(this.args.slices, function(i, item) {
  item.angle = (item.percent || 0) * 360;
})
Copy the code

We then set the path to which each element should be set, using the following function:

 /** * @param {Number} startAngle Angle * @param {Number} Angle Angle * @param {Number} pieR radius * @param {Number} donutR * @return {Object} Coordinate Object */
getSectorPath(startAngle, angle, pieR, donutR) {
  startAngle = startAngle * Math.PI / 180;
  angle = angle * Math.PI / 180;

  var startAngleTri = {
    cos: Math.cos(startAngle),
    sin: Math.sin(startAngle)
  };

  var angleTri = {
    cos: Math.cos(startAngle + angle),
    sin: Math.sin(startAngle + angle)
  };

  return [
    'M', donutR * startAngleTri.cos, donutR * startAngleTri.sin, / / start point
    'L', pieR * startAngleTri.cos, pieR * startAngleTri.sin, // Start boundary
    'A', pieR, pieR, // External radius
    0.// Rotation on the x axis
    Math.abs(angle) > Math.PI ? 1 : 0.// large-arc-flag
    1.// sweep-flag
    pieR * angleTri.cos, pieR * angleTri.sin, // end point
    'L', donutR * angleTri.cos, donutR * angleTri.sin, // end edge
    'A', donutR, donutR, // inner arc
    0.// Rotation on the x axis
    Math.abs(angle) > Math.PI ? 1 : 0.// large-arc-flag
    0.// sweep-flag
    donutR * startAngleTri.cos, donutR * startAngleTri.sin / / end points
  ].join(' ');
}
Copy the code

The graph is drawn by the path element. The following command can be used for path data:

M = moveto
L = lineto
H = horizontal lineto
V = vertical lineto
C = curveto
S = smooth curveto
Q = quadratic Belzier curve
T = smooth quadratic Belzier curveto
A = elliptical Arc
Z = closepath
Copy the code

An easy way to write this is as follows:

<path d="M250 150 L150 350 L350 350 Z" />
Copy the code

So the pie chart could be written like this:

$(path).attr({
  'd': getSectorPath(startAngle, angle, pieR, donutR)
}).css({
  / / property
})
Copy the code

This is the drawing method of SVG. Compared with canvas painting, SVG is better to draw because it provides some basic graphics components, but each has its own advantages. If we want to make a better graphics library, we need to use a drawing engine, which can use different rendering methods for multiple platforms.