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动态加载以及确定加载完成的代码
Jul 31 Javascript
Jquery实现点击切换图片并隐藏显示内容(2种方法实现)
Apr 11 Javascript
javascript查找字符串中出现最多的字符和次数的小例子
Oct 29 Javascript
jQuery实现公告文字左右滚动的实例代码
Oct 29 Javascript
页面刷新时记住滚动条的位置jquery代码
Jun 17 Javascript
基于Jquery插件Uploadify实现实时显示进度条上传图片
Mar 26 Javascript
微信小程序开发之相册选择和拍照详解及实例代码
Feb 22 Javascript
JS中type=&quot;button&quot;和type=&quot;submit&quot;的区别
Jul 04 Javascript
纯 JS 实现放大缩小拖拽功能(完整代码)
Nov 25 Javascript
JS精确判断数据类型代码实例
Dec 18 Javascript
JavaScript Window浏览器对象模型原理解析
May 30 Javascript
js实现小球在页面规定的区域运动
Jun 16 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
smarty中先strip_tags过滤html标签后truncate截取文章运用
2010/10/25 PHP
phpcms手机内容页面添加上一篇和下一篇
2015/06/05 PHP
使用PHP进行微信公众平台开发的示例
2015/08/21 PHP
利用Homestead快速运行一个Laravel项目的方法详解
2017/11/14 PHP
抽出www.templatemonster.com的鼠标悬停加载大图模板的代码
2007/07/11 Javascript
Javascript条件判断使用小技巧总结
2008/09/08 Javascript
jQuery不间断滚动效果(模拟百度新闻支持文字/图片/垂直滚动)
2013/02/05 Javascript
js 自动播放的实例代码
2013/11/19 Javascript
基于js的变量提升和函数提升(详解)
2017/09/17 Javascript
详解vue-cli 接口代理配置
2017/12/13 Javascript
jquery获取select选中值的文本,并赋值给另一个输入框的方法
2018/08/21 jQuery
Vue使用localStorage存储数据的方法
2019/05/27 Javascript
浅谈Vue.js之初始化el以及数据的绑定说明
2019/11/14 Javascript
vue 使用vant插件做tabs切换和无限加载功能的实现
2020/11/04 Javascript
vue3.0中友好使用antdv示例详解
2021/01/05 Vue.js
[15:28]DOTA2 HEROS教学视频教你分分钟做大人-剧毒术士
2014/06/13 DOTA
python求pi的方法
2014/10/08 Python
巧用python和libnmapd,提取Nmap扫描结果
2016/08/23 Python
Django实现的自定义访问日志模块示例
2017/06/23 Python
python版学生管理系统
2018/01/10 Python
python制作图片缩略图
2019/04/30 Python
python+opencv像素的加减和加权操作的实现
2019/07/14 Python
python3 kubernetes api的使用示例
2021/01/12 Python
canvas环形倒计时组件的示例代码
2018/06/14 HTML / CSS
斯凯奇美国官网:SKECHERS美国
2016/08/20 全球购物
英国领先的男装设计师服装购物网站:Mainline Menswear
2018/02/04 全球购物
King Apparel官网:英国街头服饰品牌
2019/09/05 全球购物
Bed Bath & Beyond加拿大官网:购买床上用品、浴巾、厨房电器等
2019/10/04 全球购物
荷兰DOD药房中文官网:DeOnlineDrogist
2020/12/27 全球购物
怎样在 Applet 中建立自己的菜单(MenuBar/Menu)?
2012/06/20 面试题
医学生个人求职信范文
2013/09/24 职场文书
学校招生宣传广告词
2014/03/19 职场文书
小班下学期幼儿评语
2014/12/30 职场文书
导游词之云南丽江-泸沽湖
2019/09/26 职场文书
nginx+lua单机上万并发的实现
2021/05/31 Servers
python随机打印成绩排名表
2021/06/23 Python