D3.js实现柱状图的方法详解

D3.js 是一个基于数据操作文档JavaScript库。D3帮助你给数据带来活力通过使用HTML、SVG和CSS。D3重视Web标准为你提供现代浏览器的全部功能,而不是给你一个专有的框架。结合强大的可视化组件和数据驱动方式Dom操作。这里也可以看到它是用SVG来呈现图表的,所以使用D3.js是需要一定的SVG基础的。

如何用D3.js实现柱状图?

柱状图里面有坐标轴和柱子。然而我们还需要SVG画布来画这些东西。先把大概的画图框架搭起来,代码如下(请注意此时我在body标签里添加了D3.js的script标签。这样我们后面才能使用D3的方法):

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>柱状图</title> <style> .container { margin: 30px auto; width: 600px; height: 300px; border: 1px solid #000; } </style> </head> <body> <div> <svg></svg> </div> <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> <script> window.onload = function() { var width = 600, height = 300; // SVG画布边缘与图表内容的距离 var padding = { top: 50, right: 50, bottom: 50, left: 50 }; // 创建一个分组用来组合要画的图表元素 var main = d3.select('.container svg').append('g') // 给这个分组加上main类 .classed('main') // 设置该分组的transform属性 .attr('transform', "translate(" + padding.top + ',' + padding.left + ')'); }; </script> </body> </html>

坐标轴的实现

为了把真实的数据与SVG画布上的坐标轴上的坐标联系起来,我们需要定义比例尺来描述这样的对应关系。D3中常用的比例尺有线性比例尺和序数比例尺,它们的区别如图所示:

D3.js实现柱状图的方法详解

从图上可以看出,线性比例尺的对应关系是连续的,而序数比例尺的对应关系是离散的。分析柱状图的展现意义可以得出x轴应该选用序数比例尺,而y轴选用线性比例尺。

// 模拟数据 var dataset = { x: ["赵","钱","孙","李","周","吴","郑","王"], y: [40, 30, 50, 70, 90, 20, 10, 40] }; // 定义x轴的比例尺(序数比例尺) var xScale = d3.scale.ordinal() .domain(dataset.x) .rangeRoundBands([0, width - padding.left - padding.right],0,0); // 定义y轴的比例尺(线性比例尺) var yScale = d3.scale.linear() .domain([0, d3.max(dataset.y)]) .range([height - padding.top - padding.bottom, 0]); // 定义x轴和y轴 var xAxis = d3.svg.axis() .scale(xScale) .orient('bottom'); var yAxis = d3.svg.axis() .scale(yScale) .orient('left'); // 添加坐标轴元素 main.append('g') .attr('class', 'axis') .attr('transform', 'translate(0,' + (height - padding.bottom - padding.top) + ')') .call(xAxis); main.append('g') .attr('class', 'axis') .call(yAxis);

我们模拟了一些数据,每个姓氏对应了一个数值(从这里也可以看出序数比例尺的定义域上的值不一定是连续关系)。d3.scale.ordinal()创建了一个序数比例尺,而ordinal.domain()设置了该比例尺的定义域,ordinal.rangRoundBands()设置了值域。同理,d3.scale.linear()创建了一个线性比例尺,linear.domain()定义定义域,linear.range()定义值域。接着,我们用d3.svg.axis()创建了两个坐标轴,把比例尺应用到它们上面,并且用axis.orient()设置了坐标轴的刻度尺的方向。最后,添加SVG元素,用call()把定义好的坐标轴与SVG元素联系起来。通过设置它们的transform属性来移动元素,使它们看起来像是一个坐标系。

这里需要注意以下几点:

1、ordinal.domain的参数是一个表示一系列值的数组,而linear.domain的参数是一个表示范围的数组。

2、比例尺的本质是一个函数,它接收定义域上的值来得出对应的值域上的值。

应用序数比例尺的坐标轴与线性比例尺的有很大不同,这里大概说明一下。

D3.js实现柱状图的方法详解

  rangeRoundBands(interval, padding, outerPadding)中的padding和outerPadding都是可选的,默认为0。如上图所示的比例尺的代码是这样的。

var o = d3.scale.ordinal() .domain([0, 1, 2]) .rangeRoundBands([0, 100], 0.4, 0.1);

  domain的参数数组有多少个元素,就会有多少个rangeBand,rangeBand之间的间隔为padding*step(padding取值范围为0到1),它与rangeBand的关系是均分一个step,比如padding为0.4,则rangeBand的长度为0.6*step。根据上述代码可得最终坐标轴的长度等于(0.1 + 2 + 0.6 + 0.1) * step,由此算出step的长度,再推出外间距、rangeBand、内间距的长度。而定义域上的取值刻度定位在每个rangeBand的中间。于是得到了示意图中的坐标轴(红色标注)。

我们接着来画柱状图,给坐标轴设置一下样式:

.axis path, .axis line { stroke: #000; fill: none; }

最终得到的柱状图的坐标轴如下图所示:

D3.js实现柱状图的方法详解

柱子的实现

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzjdsp.html