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 相关文章推荐
关于锚点跳转及jQuery下相关操作与插件
Oct 01 Javascript
JS对select控件option选项的增删改查示例代码
Oct 21 Javascript
JavaScript操作DOM元素的childNodes和children区别
Apr 01 Javascript
JavaScript高级程序设计(第三版)学习笔记1~5章
Mar 11 Javascript
利用iscroll4实现轮播图效果实例代码
Jan 11 Javascript
IntersectionObserver实现图片懒加载的示例
Sep 29 Javascript
看看“疫苗查询”小程序有温度的代码
Jul 31 Javascript
如何用原生js写一个弹窗消息提醒插件
May 24 Javascript
浅谈Express.js解析Post数据类型的正确姿势
May 30 Javascript
Angular6使用forRoot() 注册单一实例服务问题
Aug 27 Javascript
Vue-cli3项目引入Typescript的实现方法
Oct 18 Javascript
js实现计算器功能
Aug 10 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
PHP4实际应用经验篇(1)
2006/10/09 PHP
浅析php中jsonp的跨域实例
2013/06/21 PHP
详解 PHP加密解密字符串函数附源码下载
2015/12/18 PHP
PHP7.1新功能之Nullable Type用法分析
2016/09/26 PHP
兼容FireFox 的 js 日历 支持时间的获取
2009/03/04 Javascript
jquery ajax属性async(同步异步)示例
2013/11/05 Javascript
JS Replace 全部替换字符的用法小结
2013/12/24 Javascript
Area 区域实现post提交数据的js写法
2014/04/22 Javascript
JS判断字符串包含的方法
2015/05/05 Javascript
jQuery模仿阿里云购买服务器选择购买时间长度的代码
2016/04/29 Javascript
JS简单获取客户端IP地址的方法【调用搜狐接口】
2016/09/05 Javascript
微信小程序 wxapp内容组件 text详细介绍
2016/10/31 Javascript
jQuery实现的仿百度,仿谷歌搜索下拉框效果示例
2016/12/30 Javascript
Vue.js学习记录之在元素与template中使用v-if指令实例
2017/06/27 Javascript
Node.js Buffer模块功能及常用方法实例分析
2019/01/05 Javascript
js实现京东秒杀倒计时功能
2019/01/21 Javascript
微信小程序实现带参数的分享功能(两种方法)
2019/05/17 Javascript
详解JavaScript执行模型
2020/11/16 Javascript
[14:57]DOTA2 HEROS教学视频教你分分钟做大人-幽鬼
2014/06/13 DOTA
Python 匹配任意字符(包括换行符)的正则表达式写法
2009/10/29 Python
python并发编程之多进程、多线程、异步和协程详解
2016/10/28 Python
python模拟事件触发机制详解
2018/01/19 Python
Python+selenium实现自动循环扔QQ邮箱漂流瓶
2018/05/29 Python
Python模拟简单电梯调度算法示例
2018/08/20 Python
python 通过SSHTunnelForwarder隧道连接redis的方法
2019/02/19 Python
线程安全及Python中的GIL原理分析
2019/10/29 Python
关于tf.TFRecordReader()函数的用法解析
2020/02/17 Python
pycharm 2020.2.4 pip install Flask 报错 Error:Non-zero exit code的问题
2020/12/04 Python
院药学专业个人求职信
2013/09/21 职场文书
经典婚礼主持开场白
2014/03/13 职场文书
竞赛口号大全
2014/06/16 职场文书
工伤事故赔偿协议书(标准)
2014/09/29 职场文书
个人房屋转让协议书范本
2014/10/26 职场文书
2014年学校禁毒工作总结
2014/12/23 职场文书
道歉的话语大全
2015/05/12 职场文书
小学语文教学反思范文
2016/03/03 职场文书