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


Posted in Javascript onSeptember 21, 2016

前言

小编在之前已经跟大家分享过关于怎样用柱状图和折线图这两种基本图表。这两种图表都是有坐标轴的,现在来说一种没有坐标轴的图表——饼图。

饼状图实现

还是和之前一样,我们先把简单的画图框架搭起来,添加SVG画布。但是这里需要注意的是,为了方便后面画饼图上的弧形,我们把组合这些元素的g元素移动到画布的中心:

<!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>
  window.onload = function() {
  var width = 600, height = 300;
  // 创建一个分组用来组合要画的图表元素
  var main = d3.select('.container svg').append('g')
   .classed('main', true)
   // 注意这里和前面几种图表的差别
   .attr('transform', "translate(" + width/2 + ',' + height/2 + ')');

  };
 </script>
 </body>
</html>

模拟数据并转化

为了画饼图,我们模拟了一些这样的数据。

// 模拟数据
var dataset = [
 {name: '购物', value: 983},
 {name: '日常饮食', value: 300},
 {name: '医药', value: 1400},
 {name: '交通', value: 402},
 {name: '杂费', value: 134}
];

在柱状图等有坐标轴的图表中,我们通过创建合适的比例尺来将模拟好的数据转化成适合画图的数据,那在饼图里,又用什么来转化呢?看这里~

// 转换原始数据为能用于绘图的数据
var pie = d3.layout.pie()
  .sort(null)
  .value(function(d) {
   return d.value;
  });
// pie是一个函数 
var pieData = pie(dataset);

layout叫做布局,在D3.js中它提供了一些转化成特定图表数据的函数,如其中就包括饼图。它提供一个基础的转化函数,在此基础上我们根据自己的需要再对该函数进行进一步的设置,就得到了如上述代码中pie变量保存的函数一样的转化工具,通过把原始的数据dataset传入pie中就能得到绘图数据pieData。

具体的变化我们可以看下图。

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

左边是转化前的原始的数据结构,右边是转化后的适合绘图的数据结构。可以看到,在保留原本的数据的基础上,转化后的数据新增了该项在整个饼图中的起始角度(startAngle和endAngle),以及弧形之间的间隙角度(padAngle)。

计算弧形路径

在饼图中,我们用SVG中的path元素来表示每一块弧形,而从pieData到path元素的d属性还是有一定的距离,所以我还需要再通过一步操作来用pieData计算出d属性可用的值。

// 创建计算弧形路径的函数
var radius = 100;
var arc = d3.svg.arc()
 .innerRadius(0)
 .outerRadius(radius);

添加弧形

上面的代码用svg.arc()创建了一个计算弧形路径的函数,通过这个函数就可以计算出path的d属性的值,就像下面这样。

// 添加弧形
main.selectAll('g')
 .data(pieData)
 .enter()
 .append('path')
 .attr('fill', function(d, i) {
  return getColor(i);
 })
 .attr('d', function(d){
  return arc(d);
 });

好了,饼图就这样画好了。

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

下面给大家分享个实例代码,实现饼图中加上下图这样的文字标签。

效果图

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

实例代码

<!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;
  }
  polyline {
  fill: none;
  stroke: #000000;
  stroke-width: 2px;
  stroke-dasharray: 5px;
  }
 </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>
  window.onload = function() {
  var width = 600, height = 300;
  // 创建一个分组用来组合要画的图表元素
  var main = d3.select('.container svg').append('g')
   .classed('main', true)
   .attr('transform', "translate(" + width/2 + ',' + height/2 + ')');
  // 模拟数据
  var dataset = [
   {name: '购物', value: 983},
   {name: '日常饮食', value: 300},
   {name: '医药', value: 1400},
   {name: '交通', value: 402},
   {name: '杂费', value: 134}
  ];
  // 转换原始数据为能用于绘图的数据
  var pie = d3.layout.pie()
   .sort(null)
   .value(function(d) {
    return d.value;
   });
  // pie是一个函数
  var pieData = pie(dataset);
  // 创建计算弧形路径的函数
  var radius = 100;
  var arc = d3.svg.arc()
   .innerRadius(0)
   .outerRadius(radius);
  var outerArc = d3.svg.arc()
   .innerRadius(1.2 * radius)
   .outerRadius(1.2 * radius);
  var oArc = d3.svg.arc()
   .innerRadius(1.1 * radius)
   .outerRadius(1.1 * radius);
  var slices = main.append('g').attr('class', 'slices');
  var lines = main.append('g').attr('class', 'lines');
  var labels = main.append('g').attr('class', 'labels');
  // 添加弧形元素(g中的path)
  var arcs = slices.selectAll('g')
   .data(pieData)
   .enter()
   .append('path')
   .attr('fill', function(d, i) {
    return getColor(i);
   })
   .attr('d', function(d){
    return arc(d);
   });
  // 添加文字标签
  var texts = labels.selectAll('text')
   .data(pieData)
   .enter()
   .append('text')
   .attr('dy', '0.35em')
   .attr('fill', function(d, i) {
    return getColor(i);
   })
   .text(function(d, i) {
    return d.data.name;
   })
   .style('text-anchor', function(d, i) {
    return midAngel(d)<Math.PI ? 'start' : 'end';
   })
   .attr('transform', function(d, i) {
    // 找出外弧形的中心点
    var pos = outerArc.centroid(d);
    // 改变文字标识的x坐标
    pos[0] = radius * (midAngel(d)<Math.PI ? 1.5 : -1.5);

    return 'translate(' + pos + ')';
   })
   .style('opacity', 1);

  var polylines = lines.selectAll('polyline')
   .data(pieData)
   .enter()
   .append('polyline')
   .attr('points', function(d) {
    return [arc.centroid(d), arc.centroid(d), arc.centroid(d)];
   })
   .attr('points', function(d) {
    var pos = outerArc.centroid(d);
    pos[0] = radius * (midAngel(d)<Math.PI ? 1.5 : -1.5);
    return [oArc.centroid(d), outerArc.centroid(d), pos];
   })
   .style('opacity', 0.5);
  };
  function midAngel(d) {
  return d.startAngle + (d.endAngle - d.startAngle)/2;
  }
  function getColor(idx) {
  var palette = [
   '#2ec7c9', '#b6a2de', '#5ab1ef', '#ffb980', '#d87a80',
   '#8d98b3', '#e5cf0d', '#97b552', '#95706d', '#dc69aa',
   '#07a2a4', '#9a7fd1', '#588dd5', '#f5994e', '#c05050',
   '#59678c', '#c9ab00', '#7eb00a', '#6f5553', '#c14089'
  ]
  return palette[idx % palette.length];
  }
 </script>
 </body>
</html>

总结

以上就是利用D3.js实现饼图的全部内容,希望这篇文章对大家的学习和工作能有所帮助。如果有疑问大家可以留言交流,小编还会陆续更新关于D3.js的文章,请大家继续关注三水点靠木。

Javascript 相关文章推荐
javascript 日期常用的方法
Nov 11 Javascript
js 调用本地exe的例子(支持IE内核的浏览器)
Dec 26 Javascript
基于jQuery中对数组进行操作的方法
Apr 16 Javascript
引用外部脚本时script标签关闭的写法
Jan 20 Javascript
javascript页面倒计时实例
Jul 25 Javascript
jQuery实现两款有动画功能的导航菜单代码
Sep 16 Javascript
学习javascript面向对象 javascript实现继承的方式
Jan 04 Javascript
Bootstrap安装环境配置教程分享
May 27 Javascript
jQuery 生成svg矢量二维码
Aug 09 Javascript
ES6中Set和Map数据结构,Map与其它数据结构互相转换操作实例详解
Feb 28 Javascript
原生js通过一行代码实现简易轮播图
Jun 05 Javascript
layui 弹出层回调获取弹出层数据的例子
Sep 02 Javascript
angularJS Provider、factory、service详解及实例代码
Sep 21 #Javascript
JS实现图文并茂的tab选项卡效果示例【附demo源码下载】
Sep 21 #Javascript
AngularJS ngModel实现指令与输入直接的数据通信
Sep 21 #Javascript
D3.js实现折线图的方法详解
Sep 21 #Javascript
利用BootStrap弹出二级对话框的简单实现方法
Sep 21 #Javascript
angular route中使用resolve在uglify压缩后问题解决
Sep 21 #Javascript
使用bootstrap validator的remote验证代码经验分享(推荐)
Sep 21 #Javascript
You might like
Look And Say 序列php实现代码
2011/05/22 PHP
php whois查询API制作方法
2011/06/23 PHP
CI框架的安全性分析
2016/05/18 PHP
php中关于长度计算容易混淆的问题分析
2016/05/27 PHP
PHP实现批量删除(封装)
2017/04/28 PHP
javascript YUI 读码日记之 YAHOO.util.Dom - Part.4
2008/03/22 Javascript
JS动画效果代码3
2008/04/03 Javascript
滚动图片效果 jquery实现回旋滚动效果
2013/01/08 Javascript
跟我学习javascript的浮点数精度
2015/11/16 Javascript
js将json格式的对象拼接成复杂的url参数方法
2016/05/25 Javascript
JQuery ZTree使用方法详解
2017/01/07 Javascript
JS实现商品筛选功能
2020/08/19 Javascript
微信小程序HTTP接口请求封装的实现
2019/02/21 Javascript
jQuery轮播图功能制作方法详解
2019/12/03 jQuery
JS实现TITLE悬停长久显示效果完整示例
2020/02/11 Javascript
vue 函数调用加括号与不加括号的区别
2020/10/29 Javascript
python list使用示例 list中找连续的数字
2014/01/27 Python
python调用短信猫控件实现发短信功能实例
2014/07/04 Python
Python获取暗黑破坏神3战网前1000命位玩家的英雄技能统计
2016/07/04 Python
Python实现的逻辑回归算法示例【附测试csv文件下载】
2018/12/28 Python
pandas 对日期类型数据的处理方法详解
2019/08/08 Python
python之生成多层json结构的实现
2020/02/27 Python
让ie浏览器成为支持html5的浏览器的解决方法(使用html5shiv)
2014/04/08 HTML / CSS
HTML5中form如何关闭自动完成功能的方法
2018/07/02 HTML / CSS
美国维生素、补充剂、保健食品购物网站:Vitacost
2016/08/05 全球购物
个人自荐书
2013/12/20 职场文书
物业总经理岗位职责
2014/02/28 职场文书
基督教婚礼主持词
2014/03/14 职场文书
春节联欢晚会主持词范文
2014/03/24 职场文书
民政局个人整改措施
2014/09/24 职场文书
2014年中学生检讨书大全
2014/10/09 职场文书
优秀教师申报材料
2014/12/16 职场文书
班主任经验交流材料
2014/12/16 职场文书
成绩报告单家长评语
2014/12/30 职场文书
司机岗位职责范本
2015/04/10 职场文书
解除处分决定书
2015/06/25 职场文书