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


Posted in Javascript onSeptember 21, 2016

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 class="container">
   <svg width="100%" height="100%"></svg>
  </div>
  <script src="http://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实现柱状图的方法详解

柱子的实现

柱子无非就是一个个矩形,在SVG中可以使用rect元素来画。先选择到main下所有bar类的元素(此时选择到的是一个空的集合),把dataset.y绑定到这个集合上,用enter()对比绑定的数组元素个数与集合中的SVG元素个数,与append()搭配使用,会自动补齐至两边个数相等。每一次的append都对应dataset.y中的一个数组元素。利用前面创建的比例尺函数计算出值并赋给举行元素的x、y属性。具体的代码如下:

// 矩形之间的间距
var rectMargin = 10;
// 添加矩形
main.selectAll('.bar')
  .data(dataset.y)
  .enter()
  .append('rect')
  .attr('class', 'bar')
  .attr('x', function(d, i) {
   return xScale(dataset.x[i]) + rectMargin;
  })
  .attr('y', function(d, i) {
   return yScale(d);
  })
  .attr('width', xScale.rangeBand() - 2*rectMargin)
  .attr('height', function(d, i) {
   return height - padding.top - padding.bottom - yScale(d);
  })
  .attr('fill', function(d, i) {
   return getColor(i);
  });

至此,得到了如下图所示的柱状图。

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

总结

以上就是利用D3.js实现柱状图的全部内容,感兴趣的朋友们可以自己动手实践下,这样更利于大家的理解和学习,希望这篇文章对大家的学习和工作能有所帮助。如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持,小编还会陆续更新关于D3.js的文章,请继续关注三水点靠木。

Javascript 相关文章推荐
关于javascript document.createDocumentFragment()
Apr 04 Javascript
javascript 操作select下拉列表框的一点小经验
Mar 20 Javascript
IE无法设置短域名下Cookie
Sep 23 Javascript
自己动手制作jquery插件之自动添加删除行功能介绍
Oct 14 Javascript
基于jquery实现的一个选择中国大学的弹框 (数据、步骤、代码)
Jul 26 Javascript
jqGrid日期格式的判断示例代码(开始日期与结束日期)
Nov 08 Javascript
js获取指定日期周数以及星期几的小例子
Jun 27 Javascript
基于原生JS实现图片裁剪
Aug 01 Javascript
AngularJS 作用域详解及示例代码
Aug 17 Javascript
bootstrap daterangepicker双日历时间段选择控件详解
Jun 15 Javascript
JavaScript编写棋盘覆盖代码详解
Aug 28 Javascript
小程序hover-class点击态效果实现
Feb 26 Javascript
AngularJS ng-style中使用filter
Sep 21 #Javascript
BootStrap与validator 使用笔记(JAVA SpringMVC实现)
Sep 21 #Javascript
JS实现简单的tab切换选项卡效果
Sep 21 #Javascript
详解AngularJs中$sce与$sceDelegate上下文转义服务
Sep 21 #Javascript
JS 获取HTML标签内的子节点的方法
Sep 21 #Javascript
浅谈JS使用[ ]来访问对象属性
Sep 21 #Javascript
js style.display=block显示布局错乱问题的解决方法
Sep 21 #Javascript
You might like
用Flash图形化数据(一)
2006/10/09 PHP
PHP安全技术之 实现php基本安全
2010/09/04 PHP
PHP 实现代码复用的一个方法 traits新特性
2015/02/22 PHP
PHP请求Socket接口测试实例
2016/08/12 PHP
PHP递归遍历指定文件夹内的文件实现方法
2016/11/15 PHP
PHP反射原理与用法深入分析
2019/09/28 PHP
[原创]IE view-source 无法查看看源码 JavaScript看网页源码
2009/07/19 Javascript
使用js对select动态添加和删除OPTION示例代码
2013/08/12 Javascript
浅析javascript操作 cookie对象
2014/12/26 Javascript
SpringMVC框架下JQuery传递并解析Json格式的数据是如何实现的
2015/12/10 Javascript
JS中判断字符串中出现次数最多的字符及出现的次数的简单实例
2016/06/03 Javascript
JS读写CSS样式的方法汇总
2016/08/16 Javascript
JS 循环li添加点击事件 (闭包的应用)
2016/12/10 Javascript
js点击时关闭该范围下拉菜单之外的菜单方法
2018/01/11 Javascript
解决layui-table单元格设置为百分比在ie8下不能自适应的问题
2019/09/28 Javascript
Node.js实现批量下载图片简单操作示例
2020/01/18 Javascript
[48:11]完美世界DOTA2联赛 Magma vs GXR 第二场 11.07
2020/11/10 DOTA
用Python写的图片蜘蛛人代码
2012/08/27 Python
Python中关键字is与==的区别简述
2014/07/31 Python
Python判断列表是否已排序的各种方法及其性能分析
2016/06/20 Python
python多线程并发让两个LED同时亮的方法
2019/02/18 Python
Python实现的微信支付方式总结【三种方式】
2019/04/13 Python
使用Flask-Cache缓存实现给Flask提速的方法详解
2019/06/11 Python
python GUI库图形界面开发之PyQt5切换按钮控件QPushButton详细使用方法与实例
2020/02/28 Python
Pandas把dataframe或series转换成list的方法
2020/06/14 Python
分享unittest单元测试框架中几种常用的用例加载方法
2020/12/02 Python
Python hashlib和hmac模块使用方法解析
2020/12/08 Python
求职推荐信范文
2013/12/01 职场文书
家长会主持词
2014/03/26 职场文书
葬礼司仪主持词
2014/03/31 职场文书
银行求职信怎么写
2019/06/20 职场文书
Mysql数据库命令大全
2021/05/26 MySQL
OpenCV中resize函数插值算法的实现过程(五种)
2021/06/05 Python
Go获取两个时区的时间差
2022/04/20 Golang
分析SQL窗口函数之聚合窗口函数
2022/04/21 Oracle
 python中的元类metaclass详情
2022/05/30 Python