一、需求
制定数据结构,用饼图可视化数据。
1.渲染饼图并带有顺时针旋转展示效果
2.鼠标经过每一项时,该项半径变大,离开时恢复
3.鼠标经过在鼠标位置出现tip 框(我用backbone实现,不作为讲解重点)
4.图例legend
二、分析需求
1.需要的数据:
{ type 图表类型 title 图表名称 legend 图例数据 tooltip 提示 durationTime 动画持续时间 series 图表数据 }
三、数据结构
** 所有图形的数据结构都暂定为如下格式,对于饼图xAxis、yAxis则为null**
'pie':{
type:'pie',
title:{
text:'this is a demo' //图标名称
},
legend:{
orient:'vertical',//horizontal||vertical 横排或者竖排
x:300, //在svg中的位置
y:100,
width:16,
height:16,
padding:5,
// data:['直接访问','邮件销售','联盟广告','视频广告','搜索引擎']
},
tooltip:{
dataLabels:{
color:'#fff',
bgColor:'red'
}
},
durationTime:100, //动画的持续时间
xAxis:null, //x轴数据
yAxis:null, //y轴数据
series:{
title:'数据来源',
radius:{
outerRadius:70,
innerRadius:0
},
center:{
x:100,
y:100
},
data:[
{value:10,data:'直接访问'},
{value:20,data:'邮件销售'},
{value:30,data:'联盟广告'},
{value:30,data:'视频广告'},
{value:30,data:'搜索引擎'}
]
}
}
四、分解
1.渲染饼图
2.添加动画
3.增加hover效果
3.渲染legend
五、实现
1.渲染饼图
在渲染饼图时我们需要做:
1.1、用d3提供的 layout将数据转换为pie所需要的数据格式
this._pie = d3.layout.pie()
.sort()
.value(function(d){
return d.value
})
.startAngle()
.endAngle()
sort:和js 中的sort方法一直,接受一个排序函数。不一样之处为它的排序对每一项数据的startAngle和endAngle起作用。
value 是用来划分每一项在圆环上所占的比例
startAngle和endAngle分别表示整个饼图的起始弧度和终止弧度
1.2、设置arc
this._arc = d3.svg.arc()
.innerRadius()
.outerRadius()
.padRadius()
.startAngle()
.endAngle()
我们可以想想一下:
但我们画圆环时,是不是需要用svg 的path实现,path标签的d属性时不时会很难,d3.svg.arc()可以根据pie转换后的数据计算出d的取值。
1.3、设置颜色构造器
this._color = d3.scale.category20()
1.4、绘制
d3.svg.append('g')
.append('path)
.attr({
d:function(d,i){
return self._arc(d)
}
color:function(d,i){
return self._color(i)
}
})
上面演示了 arc 和color的用法
1.5、动画
.transition()
.delay()
.duration()
.ease('linear')
.attrTween('d',function(d,i){
var fn = d3.interpolateObject({
endAngle:d.startAngle
},d)
return function(t){
return self._arc(fn(t))
}
})
为了制作连贯的动画,需要在startAngle和endAngle中间插入一些过度值,d3提供了interpolateObject(a,b)方法,根据a,b在a,b之间插入中间值。
1.6、legend
legend制作的难点在于 如果将所有的图例都水平排列,如果确定每一个图例的大小,由于svg 在绘制每一个元素时都是以左上角为起始,需要translate,因此我们需要获得每一个图例的宽度。
svg中的g类似与div 它的宽高为其内容的宽高,但是不能够用$(div).width()获得,d3提供了这样的方法。
d3.select('g').getBBox().width