饼状图是数据统计中常常用到的另外一类图表,饼图能够直观地显示一个数据系列中各项的大小与各项总和的比例,本文将使用D3上手制做一个简单的饼状图数组
布局是D3中很是重要的内容,有了布局D3才能画出复杂的矢量图。但布局并非直接绘制图形,只是将初始数据转换成容易画图的图形语言,画图工具能读懂图形语言来进行绘制。浏览器
在绘制饼状图中,例若有一组数据[1, 2, 3],只依靠这些数据是画不出的,须要将这些数据转化为圆形的起始角度和终止角度,第一块的角度区域为[0, π/3],第二块的角度区域为[π/3, π]……绘制工具能根据这些角度值进行绘制。布局只进行数据转换app
D3还提供其余经常使用图表的布局函数,好比力导向图(Force)、弦图(Chord)、树状图(Tree)、直方图(Histogram)、分区图(Partition)等,每种布局有对应的APIsvg
表格数据是来自w3schools的2016年9月的浏览器使用率函数
浏览器 | 占比 |
---|---|
Chrome | 72.5% |
IE | 5.3% |
Firefox | 16.3% |
Safari | 3.5% |
Opera | 1.0% |
Others | 1.4% |
对此设定如下二维数组装载这些数据工具
var dataset = [['Chrome', 72.5], ['IE', 5.3], ['Firefox', 16.3], ['Safari', 3.5], ['Opera', 1.0], ['Others', 1.4]];
复制代码
构建一个饼布局并接收数据布局
var pie = d3.pie()
.sort(null) // 在建立布局的时候,默认排序数据从大到小,设为null能够按照数组默认顺序排序
.value(function(d){
return d[1]
});
复制代码
把数据转换为饼图绘制所须要的数据ui
var piedata = pie(dataset);
console.log(piedata);
复制代码
在控制台输出piedata,看看转换后的数据spa
能够看到,原来的数据已经被转换成6组适合画图的数据code
虽然有了角度,但目前仍是很难画出咱们想要的饼图,还要用到D3中的路径生成器。在svg中,path标签的路径数值每每十分复杂,手动去生成是不现实的,尤为是要生成各类复杂曲线的时候,好在D3提供了基本的路径生成器,有线段、区域、弧生成器等。画饼图的时候须要用到弧生成器,帮助咱们把转换后的数据真正绘制出来
这里把画布的四分之一做为外部半径,内部半径设为0就是饼图,没错,设置大于0就是圆环图
var outerRadius = width / 4;
var innerRadius = 0;
var arc = d3.arc()
.outerRadius(outerRadius)
.innerRadius(innerRadius);
复制代码
跟以前同样,建立g组合标签后,把piedata数据绑定至g标签,这里要用到D3的内置颜色,d3.schemeCategory10选了10种颜色,方便咱们随时使用,为饼图的不一样区域填色,没必要为想不出好的颜色搭配而烦恼,固然也能够自定义颜色
var arcs = svg.selectAll('g')
.data(piedata)
.enter()
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
// 调用内置颜色序列
var colors = d3.schemeCategory10;
arcs.append('path')
.attr('fill', function(d, i){
return colors[i];
})
.attr('d', function(d){
return arc(d);
});
复制代码
在path标签中,给d属性赋予数据通过弧生成器处理的值,这样一个没有标注的饼图就完成了
接下来给饼图加一些标注,以便更好地阅读图形,主要用到弧中心的概念,以下图,黑点就是每一个弧的中心,利用**arc.centroid()**能够获取弧中心的坐标,而且这个坐标是相对圆形的相对坐标。有了这个坐标,能够很方便地在每一个弧上添加文字标注
arc.centroid(d)是一个包含横坐标和纵坐标的数组[x, y],给坐标乘以2倍以上的数值就把文字移到圆形外边
arcs.append('text')
.attr('transform', function(d, i){
var x = arc.centroid(d)[0] * 2.8;
var y = arc.centroid(d)[1] * 2.8;
return 'translate(' + x + ', ' + y + ')';
})
.attr('text-anchor', 'middle')
.text(function(d){
var percent = Number(d.value) / d3.sum(dataset, function(d){
return d[1];
}) * 100;
return d.data[0] + ' ' + percent.toFixed(1) + '%';
})
复制代码
最后再加一些连线
arcs.append('line')
.attr('stroke', 'black')
.attr('x1', function(d){ return arc.centroid(d)[0] * 2; })
.attr('y1', function(d){ return arc.centroid(d)[1] * 2; })
.attr('x2', function(d, i){
return arc.centroid(d)[0] * 2.5;
})
.attr('y2', function(d, i){
return arc.centroid(d)[1] * 2.5;
});
复制代码
因为最后几个数据过小,标注文字会重叠到一块儿,这里作了一个判断处理来错开数据值较小的文字,最后的效果图以下所示