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 相关文章推荐
提高 DHTML 页面性能
Dec 25 Javascript
Mootools 1.2教程 类(一)
Sep 15 Javascript
node.js实现逐行读取文件内容的代码
Jun 27 Javascript
jquery幻灯片插件bxslider样式改进实例
Oct 15 Javascript
JQuery勾选指定name的复选框集合并显示的方法
May 18 Javascript
CSS中position属性之fixed实现div居中
Dec 14 Javascript
ashx文件获取$.ajax()方法发送的数据
May 26 Javascript
BootstrapValidator超详细教程(推荐)
Dec 07 Javascript
jQuery常见的遍历DOM操作详解
Sep 05 jQuery
webpack3升级到webpack4遇到问题总结
Sep 30 Javascript
使用Vue+Django+Ant Design做一个留言评论模块的示例代码
Jun 01 Javascript
Ajax请求超时与网络异常处理图文详解
May 23 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
PHP新手上路(三)
2006/10/09 PHP
同一空间绑定多个域名而实现访问不同页面的PHP代码
2006/12/06 PHP
初学CAKEPHP 基础教程
2009/11/02 PHP
PHP获取表单textarea数据中的换行问题
2010/09/10 PHP
php取整函数ceil,floo,round的用法及介绍
2013/08/31 PHP
php对象在内存中的存在形式分析
2015/02/03 PHP
PHP输出Excel PHPExcel的方法
2018/07/26 PHP
Laravel 6.2 中添加了可调用容器对象的方法
2019/10/22 PHP
javaScript 简单验证代码(用户名,密码,邮箱)
2009/09/28 Javascript
js自定义事件代码说明
2011/01/31 Javascript
JavaScript 一道字符串分解的题目
2011/08/03 Javascript
jquery上传插件fineuploader上传文件使用方法(jquery图片上传插件)
2013/12/05 Javascript
jQuery根据ID获取input、checkbox、radio、select的示例
2014/08/11 Javascript
基于jquery实现的自动补全功能
2015/03/12 Javascript
基于JavaScript实现右键菜单和拖拽功能
2016/11/28 Javascript
xmlplus组件设计系列之列表(4)
2017/04/26 Javascript
Vue2.x中的父组件传递数据至子组件的方法
2017/05/01 Javascript
vue-router 中router-view不能渲染的解决方法
2017/05/23 Javascript
ES6基础之展开语法(Spread syntax)
2019/02/21 Javascript
JavaScript遍历查找数组中最大值与最小值的方法示例
2019/05/24 Javascript
[02:15]2014DOTA2国际邀请赛 赛后退役选手回顾
2014/08/01 DOTA
[04:51]TI10典藏宝瓶Ⅱ外观视频展示
2020/08/15 DOTA
Python验证文件是否可读写代码分享
2017/12/11 Python
python列表生成器迭代器实例解析
2019/12/19 Python
python中的逆序遍历实例
2019/12/25 Python
解决Jupyter Notebook使用parser.parse_args出现错误问题
2020/04/20 Python
REN Clean Skincare官网:英国本土有机护肤品牌
2019/02/23 全球购物
德尔福集团DELPHI的笔试题
2012/02/22 面试题
大专毕业生自我评价分享
2013/11/10 职场文书
有兼职工作经历的简历自我评价
2014/03/07 职场文书
《歌唱二小放牛郎》教学反思
2014/04/19 职场文书
副科竞争上岗演讲稿
2014/05/12 职场文书
无子女夫妻离婚协议书(4篇)
2014/10/20 职场文书
2014年保安个人工作总结
2014/11/13 职场文书
2015年学生管理工作总结
2015/05/26 职场文书
python中sqllite插入numpy数组到数据库的实现方法
2021/06/21 Python