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动态呼叫函数(两种方式)
May 03 Javascript
jquery中focus()函数实现当对象获得焦点后自动把光标移到内容最后
Sep 29 Javascript
js控制再次点击按钮之间的间隔时间可防止重复提交
Aug 01 Javascript
Ext4.2的Ext.grid.plugin.RowExpander无法触发事件解决办法
Aug 15 Javascript
javascript比较两个日期相差天数的方法
Jul 24 Javascript
第三章之Bootstrap 表格与按钮功能
Apr 25 Javascript
基于jQuery实现左侧菜单栏可折叠功能
Dec 27 Javascript
vuejs2.0实现分页组件使用$emit进行事件监听数据传递的方法
Feb 22 Javascript
关于vue v-for循环解决img标签的src动态绑定问题
Sep 18 Javascript
详解Vue路由自动注入实践
Apr 17 Javascript
JS中的模糊查询功能
Dec 08 Javascript
小程序接入腾讯位置服务的详细流程
Mar 03 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
基于PHP实现简单的随机抽奖小程序
2016/01/05 PHP
PHP实现的简单sha1加密功能示例
2017/08/27 PHP
jQuery创建平滑的页面滚动(顶部或底部)
2013/02/26 Javascript
js将iframe中控件的值传到主页面控件中的实现方法
2013/03/11 Javascript
表单类各种类型(文本框)失去焦点效果jquery代码
2013/04/26 Javascript
在ASP.NET MVC项目中使用RequireJS库的用法示例
2016/02/15 Javascript
javascript实现不同颜色Tab标签切换效果
2016/04/27 Javascript
bootstrap datetimepicker实现秒钟选择下拉框
2017/01/05 Javascript
BootStrap便签页的简单应用
2017/01/06 Javascript
JS匹配日期和时间的正则表达式示例
2017/05/12 Javascript
Bootstrap Table列宽拖动的方法
2018/08/15 Javascript
vue.js父子组件通信动态绑定的实例
2018/09/28 Javascript
微信小程序日历组件使用方法详解
2018/12/29 Javascript
[01:19:11]Ti4 循环赛第二日 NaVi.us vs iG
2014/07/11 DOTA
python计算最大优先级队列实例
2013/12/18 Python
python求解水仙花数的方法
2015/05/11 Python
Python中基础的socket编程实战攻略
2016/06/01 Python
python实现随机森林random forest的原理及方法
2017/12/21 Python
python搭建服务器实现两个Android客户端间收发消息
2018/04/12 Python
Python 利用scrapy爬虫通过短短50行代码下载整站短视频
2018/10/29 Python
详解python做UI界面的方法
2019/02/27 Python
python命令 -u参数用法解析
2019/10/24 Python
使用python+whoosh实现全文检索
2019/12/09 Python
Python交互环境下打印和输入函数的实例内容
2020/02/16 Python
python实现逢七拍腿小游戏的思路详解
2020/05/26 Python
python自动打开浏览器下载zip并提取内容写入excel
2021/01/04 Python
食堂采购员岗位职责
2014/03/17 职场文书
《画风》教学反思
2014/04/16 职场文书
工人先锋号事迹材料
2014/12/24 职场文书
文言文辞职信
2015/02/28 职场文书
敬业奉献模范事迹材料(2016精选版)
2016/02/26 职场文书
Python编程源码报错解决方法总结经验分享
2021/10/05 Python
Apache POI的基本使用详解
2021/11/07 Servers
Nginx 路由转发和反向代理location配置实现
2021/11/11 Servers
【海涛dota解说】海涛小满开黑4v5被破两路翻盘潮汐第一视角解说
2022/04/01 DOTA
详解Spring Security如何在权限中使用通配符
2022/06/28 Java/Android