弦表圖
主要用于顯示矩陣關(guān)系的表圖
注1:所有圖形的路徑都是從容器所在位置開始計算的
注2:所有dom綁定的數(shù)據(jù)都是新拷貝一份的 不會修改原對象
示例矩陣關(guān)系:
亞洲 | 非洲 | 歐洲 | 美洲 | 太平洋 | |
---|---|---|---|---|---|
亞洲 | 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 = ["亞洲", "非洲", "歐洲", "美洲", "太平洋"];
// 聲明矩陣數(shù)據(jù)
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]
];
// 創(chuàng)建弦圖布局
const chord = d3.layout.chord()
.padding(.02)
// 給分組排序
// 給弦上分布大小排序
.sortSubgroups(d3.ascending)
// 設(shè)置矩陣
.matrix(population);
// 創(chuàng)建一個容器 把整體圖形移動 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) + ")");
// 創(chuàng)建一個外圈圖形容器
const gOuter = gChord.append("g");
// 創(chuàng)建內(nèi)圈圖形容器
const gInner = gChord.append("g");
const color = d3.scale.category20();
// 內(nèi)圈半徑為svg一半的0.7倍
const innerRadius = width / 2 * .7;
// 外圈半徑為內(nèi)圈半徑的1.1倍
const outerRadius = innerRadius * 1.1;
// 創(chuàng)建弧形生成器
const actOuter = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
// 創(chuàng)建外圈的弧形
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);
// 給外圈弧形創(chuàng)建文字
gOuter.selectAll(".outerText")
.data(chord.groups())
.enter()
.append("text")
// 遍歷綁定的數(shù)據(jù)并計算出數(shù)字旋轉(zhuǎn)角度
.each(function (d, i) {
// 開始角度加結(jié)束角度的一半 為弧中心角度
d.angle = (d.startAngle + d.endAngle) / 2;
d.name = container[i];
})
.attr("class", "outerText")
.attr("dy", ".35em")
.attr("transform", function (d) {
// 旋轉(zhuǎn)計算出的角度
var result = "rotate(" + (d.angle * 180 / Math.PI) + ")";
// 平移到外圈外面
result += "translate(0," + -(outerRadius + 10) + ")";
//如果角度是大于3/4的半圓并且小于5/4的半圓就讓文字翻轉(zhuǎn)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()生成是一個符合弦生成器的數(shù)組
/*[
{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")
// 直接把數(shù)據(jù)給弦生成器生成弦圖形
.attr("d", arcInner)
.style("stroke", "black")
.style("fill", function (d) {
return color(d.source.index);
});
// 給所有外圈弦綁定事件 觸發(fā)事件時修改所有圖形透明度
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);
}
}
結(jié)果:
image.png