首先我们要明白弦图所要表达的意思是什么?比如我们有以下一组关于地区人口的数据:
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<Math.PI*5/4)?"rotate(180)":""); })//在用 transform 进行位移时,要注意转换的顺序: rotate -> 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)) })静态图如下: