首先我们要明白弦图所要表达的意思是什么?比如我们有以下一组关于地区人口的数据:
var city_name = ["北京","上海","广州","深圳","香港"];
var population = [
[1000,3015,4567,1234,3714],
[3214,2000,2060,124,3234],
[8761,6545,3000,8045,647],
[3211,1067,3214,4000,1006],
[2146,1034,6745,4764,5000]
];
我们可以将上面的数据绘制成如下的表格,比如第2行第4列表示为:上海的人口中有2060人来自广州。所以弦图就是将这些有关联的数据进行可视化。
北京 | 上海 | 广州 | 深圳 | 香港 | |
北京 | 1000 | 3015 | 4567 | 1234 | 3714 |
上海 | 3214 | 2000 | 2060 | 124 | 3234 |
广州 | 8761 | 6545 | 3000 | 8045 | 647 |
深圳 | 3211 | 1067 | 3214 | 4000 | 1006 |
香港 | 2146 | 1034 | 6745 | 4764 | 5000 |
有了数据源之后,还是和之前的一样,我们首先要做的就是使用d3.layout.chord()进行数据转换:
var chord_layout = d3.layout.chord()
.padding (0.03)//取得或设置弦片段间的角填充,也就是每一个弦片段的间距啦
.sortSubgroups(d3.descending) //取得或设置用于子分组的比较器。d3.descending(a, b),如果a > b返回-1,a < b返回1,a = b返回0。 这是固有的比较器方法,也可用于关联内置数组排序的方法来给元素降序排序:
.matrix(population); // 取得或设置布局需要的关联矩阵数据
然后我们来做常规的一些定义:
var width = 600,
height = 600;
var innerRadius = width/2*0.7,
outerRadius = innerRadius*1.1;
var color = d3.scale.category20();
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height)
.append("g")
.attr("transform","translate("+width/2+","+height/2+")");
整个弦图是分为外部弦和内部弦,我们首先进行外部弦的绘制,也就是确定一共有几个分组(几个城市),其实就是之前所做的饼状图:
var outer_arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var g_outer = svg.append("g")
g_outer.selectAll("path")
.data(chord_layout.groups) //返回index(行索引)、subindex(列索引)、startAngle、endAngle、value
.enter()
.append("path")
.style("fill", function (d) {
return color(d.index)
}
)
.style("stroke", function (d) {
return color(d.index)
})
.attr("d",outer_arc)
同时,我们可以在外部弦的圈外添加文字,即各个城市块对应的名称:
g_outer.selectAll("text")
.data(chord_layout.groups)
.enter()
.append("text")
.each(function(d,i){
d.angle = (d.startAngle+ d.endAngle)/2;
d.name = city_name[i];
}) //表示对于任何一个绑定的元素,都执行后面的无名函数 function 的代码,这里的代码为: 计算一个角度,赋值给 d.angle ;获取城市的名称。
.attr("dy",".35em")
.attr("transform",function(d){
return "rotate("+(d.angle*180/Math.PI)+")"+"translate(0,"+-1.0*(outerRadius+10)+")"+((d.angle>Math.PI*3/4 && d.angle translate,最后一行转换代码表示:当角度在135°到225°之间时,旋转180°。否则下方的文字是倒的,不利于观看。
.text(function(d){return d.name;});
最后我们来进行内部弦的绘制同时添加一些鼠标事件效果。这里添加内部弦有专用的函数d3.svg.chord(),只要将转换后的参数传给此函数,即可做内部弦:
var inner_chord = d3.svg.chord()
.radius(innerRadius);
svg.append("g")
.attr("class","chord")
.selectAll("path")
.data(chord_layout.chords) //返回index(行索引)、subindex(列索引)、startAngle、endAngle、value等参数
.enter()
.append("path")
.attr("d",inner_chord)
.style("fill", function(d) { return color(d.source.index); })
.style("opacity",0.5)
.on("mouseover",function(d,i){
d3.select(this)
.style("fill","yellow");
})
.on("mouseout",function(d,i){
d3.select(this)
.transition()
.duration(1000)
.style("fill",color(d.source.index))
})
静态图如下: