饼图的绘制稍微复杂一点点,主要是网上很多教程还是老版本d3.
这里用的是 D3 4.0 API Reference.
和上几篇文章写到的一样,首先新建svg,考虑缩放问题,
长高"100%"
,提供给后面svg使用.
在这里我直接给了两个list做数据了,一个是用来画饼图的数据,一个是上面的文字.
同时新建一个list存放你想要用的颜色列表.
var width = "100%";
var hight = "100%";
var radius = 150; //饼图半径,后面也用做图像相对于原点的偏移量
var color = ["steelblue","steelblue"]; //颜色列表
var gender_list = ["女性用户","男性用户"];
var gender_list_value = ["30","40"];
接下来新建svg,我在id为gender_plot
的div
下append了这个svg
.
在这里饼图的结构是:<svg>
内部一个<g>
来装载整个饼图,这个<g>
里面有数个<g>
代表饼图的每一小片,而每个小片是由一个<path>
和一个<text>
组成的.
也就是说,饼图的每一部分是一个<path>!所有的样式都要针对<path>来设定.
直方图的话是一个rec
和直方图不同的是,饼图没有比例尺了,
这里直接把数据绑定给svg:.data([gender_list_value])
var gender_svg = d3.select("#gender_plot")
.append("svg") //创建svg
.attr("width", width) //长
.attr("height", hight) //高
.attr("viewBox","0 0 300 300") //视窗,因为上面饼图的半径为150,这里视窗就刚好设定为直径300
.attr("preserveAspectRatio","xMaxYMax meet")
.data([gender_list_value]) //关联数据,注意要加方括号
.append("g") //make a group to hold our pie chart
.attr("transform", "translate(" + radius + "," + radius + ")"); //move the center of the pie chart from 0, 0 to radius, radius
接下来是根据每一片的弧度啊,半径啊,起始角啊什么的计算每一个<path>
的路径.
用的是d3的arc()
方法会帮你计算这些,返回的既是一条path中的d
属性.
d属性具体说明在这里.
从某种意义上来讲,这里的arc()
方法有点类似画直方图时的比例尺,只不过在调用的时候是,输入数据list后输出算出每一部分相应的path路径.
这里必须设定圆弧的外半径和内半径. (不然没法算路径啊是吧...)
外半径就是饼图外圆圈的半径,内径一般为0,表示没有空心,但是如果你想画圆环图,这里的内径相应的给出就好.
var arc = d3.arc() //这里是用arc()方法来创建后面的path
.outerRadius(radius)
.innerRadius(0);
var pie = d3.pie() //pie方法,自动根据原数据list计算每一部分的扇形角度占比
.value(function(d) { return d; }); //用无名函数给pie方法依次传输绑定的数据
var arcs = gender_svg.selectAll("g.slice") //给每个饼图的部分一个类名,叫slice
.data(pie) //把pie方法传进来,用于放置饼图每一部分
.enter() //用enter方法
.append("g") //补足g元素
.attr("class", "slice"); //添加类名
接下来输入数据,根据输出的path路径依次生成path,并加入text部分:
enter方法参考之前的文章d3.js直方图与坐标轴基础.
gender_svg.selectAll("g.slice") //给每个饼图的部分一个类名,叫slice
.data(pie) //把pie方法传进来,用于放置饼图每一部分
.enter() //用enter方法
.append("g") //补足g元素
.attr("class", "slice") //添加类名
.append("path") //加入path元素
.attr("fill", function(d, i) { return color[i]; } )//颜色选择根据数据的索引按顺序给
.attr("stroke","white")//设定描边的颜色,笔画粗线默认
.attr("d", arc) //设定d属性!既Path的路径,由arc方法给出!
.attr("opacity",0.4) //设定透明度
.on("mouseover",function(d,i){ //鼠标交互动态效果
d3.select(this)
.attr("opacity",1);
})
.on("mouseout",function(d,i){
d3.select(this)
.transition()
.duration(500)
.attr("opacity",0.4);
})
.on("click",function () {
});
gender_svg.selectAll("g.slice").append("text") //给饼图的每一部分添加text元素
.attr("transform", function(d) {
d.innerRadius = 0;
d.outerRadius = radius;
return "translate(" + arc.centroid(d) + ")"; //返回path的中心用于设置文字相对于(0,0)的偏移
})
.attr("text-anchor", "middle") //文字居中
.attr("font-size", "80%")//文字大小
.text(function(d, i) { return gender_list[i]; }); //文字内容从数据list中根据index获取
到此,首图上的饼图就应该可以实现啦~
:)
这里是V3版本
主要只有两个地方的不同,既axis的语法和scale的语法.
var width = "100%";
var hight = "100%";
var radius = 150; //radius
var color = ["steelblue","steelblue"]; //builtin range of colors
var genders = {{gender_list}}
if (genders[0]== "f"){
var gender_list = ["女性用户","男性用户"];
}
else if (genders[0]== "m"){
var gender_list = ["男性用户","女性用户"];
}
var gender_list = ["女性用户","男性用户"];
var gender_list_value = {{gender_list_value}};
var gender_svg = d3.select("#gender_plot")
.append("svg")
.attr("width", width)
.attr("height", hight)
.attr("viewBox","0 0 300 350")
.attr("preserveAspectRatio","xMaxYMax meet")
.data([gender_list_value])
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
var arc = d3.svg.arc() //这里语法不同
.outerRadius(radius)
.innerRadius(0);
var pie = d3.layout.pie() //这里语法不同
.value(function(d) { return d; });
gender_svg.selectAll("g.slice")
.data(pie)
.enter()
.append("g")
.attr("class", "slice")
.append("path")
.attr("fill", function(d, i) { return color[i]; } )
.attr("stroke","white")
.attr("d", arc)
.attr("opacity",0.4)
.on("mouseover",function(d,i){
d3.select(this)
.attr("opacity",1);
tooltip.html( parseInt(100*(gender_list_value[i]/(gender_list_value[0]+gender_list_value[1])))+"%")
.style("left", (d3.event.pageX+10) + "px")
.style("top", (d3.event.pageY - 10) + "px")
.style("opacity",1.0);
})
.on("mouseout",function(d,i){
d3.select(this)
.transition()
.duration(500)
.attr("opacity",0.4);
tooltip.style("opacity",0.0);
})
.on("mousemove",function(d){
tooltip.style("left", (d3.event.pageX+ 10) + "px")
.style("top", (d3.event.pageY - 10) + "px");
})
.on("click",function () {
});
gender_svg.selectAll("g.slice").append("text")
.attr("transform", function(d) {
d.innerRadius = 0;
d.outerRadius = radius;
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.attr("font-size", "80%")
.text(function(d, i) { return gender_list[i]; });