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 05 Javascript
一个简单的js树形菜单
Dec 09 Javascript
js图片自动切换效果处理代码
May 07 Javascript
js实现照片墙功能实例
Feb 05 Javascript
jquery使用slideDown实现模块缓慢拉出效果的方法
Mar 27 Javascript
使用jQuery实现更改默认alert框体
Apr 13 Javascript
jQuery实现鼠标跟随提示层效果代码(可显示文本,Div,Table,Html等)
Apr 18 Javascript
Angularjs中使用轮播图指令swiper
May 30 Javascript
基于JQuery的Ajax方法使用详解
Aug 16 jQuery
vue-cli构建项目下使用微信分享功能
May 28 Javascript
详解如何解决Vue和vue-template-compiler版本之间的问题
Sep 17 Javascript
JS中验证整数和小数的正则表达式
Oct 08 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设计模式 Interpreter(解释器模式)
2011/06/26 PHP
深入php define()函数以及defined()函数的用法详解
2013/06/05 PHP
codeigniter框架The URI you submitted has disallowed characters错误解决方法
2014/05/06 PHP
PHP判断手机是IOS还是Android
2015/12/09 PHP
YiiFramework入门知识点总结(图文教程)
2015/12/28 PHP
PHP+Apache环境中如何隐藏Apache版本
2017/11/24 PHP
jquery ready()的几种实现方法小结
2010/06/18 Javascript
JavaScript中数组的排序、乱序和搜索实现代码
2011/11/30 Javascript
tuzhu_req.js 实现仿百度图片首页效果
2015/08/11 Javascript
js实现点击获取验证码倒计时效果
2021/01/28 Javascript
BootStrap 页签切换失效的解决方法
2017/08/17 Javascript
JS实现登录页密码的显示和隐藏功能
2017/12/06 Javascript
vue实现组件之间传值功能示例
2018/07/13 Javascript
JavaScript Dom 绑定事件操作实例详解
2019/10/02 Javascript
Vue作用域插槽实现方法及作用详解
2020/07/08 Javascript
vue 动态组件(component :is) 和 dom元素限制(is)用法说明
2020/09/04 Javascript
[40:17]2018DOTA2亚洲邀请赛 4.5 淘汰赛 LGD vs Liquid 第一场
2018/04/06 DOTA
Python使用Scrapy爬取妹子图
2015/05/28 Python
巧用python和libnmapd,提取Nmap扫描结果
2016/08/23 Python
python基础教程之Filter使用方法
2017/01/17 Python
Python对文件和目录进行操作的方法(file对象/os/os.path/shutil 模块)
2017/05/08 Python
numpy.transpose对三维数组的转置方法
2018/04/17 Python
Django为窗体加上防机器人的验证码功能过程解析
2019/08/14 Python
Python selenium 自动化脚本打包成一个exe文件(推荐)
2020/01/14 Python
Python实现不规则图形填充的思路
2020/02/02 Python
基于python爬取链家二手房信息代码示例
2020/10/21 Python
Python3使用Selenium获取session和token方法详解
2021/02/16 Python
Auguste The Label官网:澳大利亚一家精品女装时尚品牌
2020/06/14 全球购物
如何查找和删除数据库中的重复数据
2014/11/05 面试题
优秀村官事迹材料
2014/01/10 职场文书
党的群众路线教育实践活动实施方案
2014/10/31 职场文书
个人租房协议书
2014/11/28 职场文书
军训通讯稿范文
2015/07/18 职场文书
宣传稿格式范文
2015/07/23 职场文书
《别在吃苦的年纪选择安逸》读后感3篇
2019/11/30 职场文书
Go并发4种方法简明讲解
2022/04/06 Golang