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 相关文章推荐
一个可以显示阴历的JS代码
Mar 05 Javascript
jquery ajax 简单范例(界面+后台)
Nov 19 Javascript
jQuery向父辈遍历的简单方法
Sep 18 Javascript
JS常用正则表达式总结【经典】
May 12 Javascript
在vue中获取dom元素内容的方法
Jul 10 Javascript
VueRouter导航守卫用法详解
Dec 25 Javascript
vue实现登录后页面跳转到之前页面
Jan 07 Javascript
Vue引用第三方datepicker插件无法监听datepicker输入框的值的解决
Jan 27 Javascript
Vue.extend实现挂载到实例上的方法
May 01 Javascript
详细教你微信公众号正文页SVG交互开发技巧
Jul 25 Javascript
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
Oct 16 jQuery
vue路由传参三种基本方式详解
Dec 09 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
在SAE上搭建最新wordpress的方法
2014/12/21 PHP
php简单smarty入门程序实例
2015/06/11 PHP
PHP排序算法类实例
2015/06/17 PHP
PHP的压缩函数实现:gzencode、gzdeflate和gzcompress的区别
2016/01/27 PHP
thinkPHP中session()方法用法详解
2016/12/08 PHP
从零开始学习jQuery (十) jQueryUI常用功能实战
2011/02/23 Javascript
使用非html5实现js板连连看游戏示例代码
2013/09/22 Javascript
基于JQuery实现的图片自动进行缩放和裁剪处理
2014/01/31 Javascript
jQuery实现宽屏图片轮播实例教程
2015/11/24 Javascript
jquery获取复选框checkbox的值的简单实现方法
2016/05/26 Javascript
JS HTML5实现拖拽移动列表效果
2020/08/27 Javascript
IONIC自定义subheader的最佳解决方案
2016/09/22 Javascript
arcgis for js 修改infowindow样式的方法
2016/11/02 Javascript
解析Javascript单例模式概念与实例
2016/12/05 Javascript
一句jQuery代码实现返回顶部效果(简单实用)
2016/12/28 Javascript
Node.JS更改Windows注册表Regedit的方法小结
2017/08/18 Javascript
利用Vue2.x开发实现JSON树的方法
2018/01/04 Javascript
JavaScript动态添加数据到表单并提交的几种方式
2019/06/26 Javascript
微信小程序新闻网站详情页实例代码
2020/01/10 Javascript
Python中Class类用法实例分析
2015/11/12 Python
转换科学计数法的数值字符串为decimal类型的方法
2018/07/16 Python
使用python来调用CAN通讯的DLL实现方法
2019/07/03 Python
详解Python并发编程之从性能角度来初探并发编程
2019/08/23 Python
numpy.ndarray 实现对特定行或列取值
2019/12/05 Python
flask 实现上传图片并缩放作为头像的例子
2020/01/09 Python
香港网上花店:FlowerAdvisor香港
2019/05/30 全球购物
澳大利亚领先的亚麻品牌:Bed Threads
2019/12/16 全球购物
澳大利亚最早和最古老的巨型游戏专家:Yardgames
2020/02/20 全球购物
大专生自荐信
2013/10/04 职场文书
天河观后感
2015/06/11 职场文书
大学生心理健康教育心得体会
2016/01/12 职场文书
高端收音机+蓝牙音箱,JBL TUNER FM带收音蓝牙音箱评测
2021/04/24 无线电
SpringBoot+Vue+JWT的前后端分离登录认证详细步骤
2021/09/25 Java/Android
python playwright 自动等待和断言详解
2021/11/27 Python
将MySQL的表数据全量导入clichhouse库中
2022/03/21 MySQL
零基础学java之带返回值的方法的定义和调用
2022/04/10 Java/Android