弦表图
主要用于显示矩阵关系的表图
注1:所有图形的路径都是从容器所在位置开始计算的
注2:所有dom绑定的数据都是新拷贝一份的 不会修改原对象
示例矩阵关系:
亚洲 | 非洲 | 欧洲 | 美洲 | 太平洋 | |
---|---|---|---|---|---|
亚洲 | 9000 | 870 | 3000 | 1000 | 5200 |
非洲 | 2000 | 2870 | 7700 | 4881 | 4050 |
欧洲 | 3540 | 3870 | 1200 | 7000 | 3200 |
美洲 | 5540 | 1870 | 5300 | 5000 | 4200 |
太平洋 | 8540 | 6870 | 4400 | 1000 | 7200 |
const width = 700, height = 500, padding = {top: 60, left: 30};
const svg = d3.select("body").append("svg").attr("width", width + padding.left * 2).attr("height", height + padding.top * 2);
const container = ["亚洲", "非洲", "欧洲", "美洲", "太平洋"];
// 声明矩阵数据
const population = [
[9000, 870, 3000, 1000, 5200],
[2000, 2870, 7700, 4881,4050],
[3540, 3870, 1200, 7000, 3200],
[5540, 1870, 5300, 5000, 4200],
[8540, 6870, 4400, 1000, 7200]
];
// 创建弦图布局
const chord = d3.layout.chord()
.padding(.02)
// 给分组排序
// 给弦上分布大小排序
.sortSubgroups(d3.ascending)
// 设置矩阵
.matrix(population);
// 创建一个容器 把整体图形移动 path的坐标系是相对父容器的
/*生成的分组中是这样的 用于做外圈的弧 value是总和
[{
index: 0,
startAngle: 0,
endAngle: 1.1092402123019984,
value: 19070,
angle: 0.5546201061509992
},...]
*/
console.log(chord.groups());
console.log(chord.chords());
const gChord = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + (height / 2 + padding.top) + ")");
// 创建一个外圈图形容器
const gOuter = gChord.append("g");
// 创建内圈图形容器
const gInner = gChord.append("g");
const color = d3.scale.category20();
// 内圈半径为svg一半的0.7倍
const innerRadius = width / 2 * .7;
// 外圈半径为内圈半径的1.1倍
const outerRadius = innerRadius * 1.1;
// 创建弧形生成器
const actOuter = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
// 创建外圈的弧形
gOuter.selectAll(".outerPath")
.data(chord.groups())
.enter()
.append("path")
.style("stroke", "black")
.attr("class", "outerPath")
.style("fill", function (d) {
return color(d.index);
})
// 用groups中的startAngle和endAngle生成外圈弧形
.attr("d", actOuter);
// 给外圈弧形创建文字
gOuter.selectAll(".outerText")
.data(chord.groups())
.enter()
.append("text")
// 遍历绑定的数据并计算出数字旋转角度
.each(function (d, i) {
// 开始角度加结束角度的一半 为弧中心角度
d.angle = (d.startAngle + d.endAngle) / 2;
d.name = container[i];
})
.attr("class", "outerText")
.attr("dy", ".35em")
.attr("transform", function (d) {
// 旋转计算出的角度
var result = "rotate(" + (d.angle * 180 / Math.PI) + ")";
// 平移到外圈外面
result += "translate(0," + -(outerRadius + 10) + ")";
//如果角度是大于3/4的半圆并且小于5/4的半圆就让文字翻转180°正过来显示
if (d.angle > Math.PI * 3 / 4 && d.angle < Math.PI * 5 / 4) {
result += "rotate(180)";
}
return result;
})
.text(function (d) {
return d.name;
});
// chord.chords()生成是一个符合弦生成器的数组
/*[
{source:{
index: 0,
startAngle: 0,
endAngle: 1.1092402123019984,
value: 19070,
angle: 0.5546201061509992
},target:{
index: 0,
startAngle: 0,
endAngle: 1.1092402123019984,
value: 19070,
angle: 0.5546201061509992
}}
]*/
const arcInner = d3.svg.chord().radius(innerRadius);
gInner.selectAll(".innerPath")
.data(chord.chords())
.enter()
.append("path")
.attr("class", "innerPath")
// 直接把数据给弦生成器生成弦图形
.attr("d", arcInner)
.style("stroke", "black")
.style("fill", function (d) {
return color(d.source.index);
});
// 给所有外圈弦绑定事件 触发事件时修改所有图形透明度
gOuter.selectAll(".outerPath")
.on("mouseover", fade(0.0))
.on("mouseout", fade(1.0));
function fade(opacity) {
return function (g, i) {
gInner.selectAll(".innerPath")
.filter(function (d) {
return d.source.index != i && d.target.index != i;
})
.transition()
.style("opacity", opacity);
}
}
结果: