效果图:
高亮效果:
//chord.js,使用时直接引入,调用
//引入依赖d3,color.js是我自己的配色方案,可以直接使用d3的配色方案,例:d3.schemeSet3
define(['d3.v5.min.js','../color.js',],function(d3,color){
var relation = function(data,width,height){
//data传入是一个对象,包含{names(指传入的数据名称数组),matrix:数据关系拼成的二维矩阵}
//例:names=['北京','上海','广州','深圳','河北']
//matrix= [
// [1000, 3045, 4567, 1234, 3714],
// [3214, 2000, 2060, 124, 3234],
// [8761, 6545, 3000, 8045, 647],
// [3211, 1067, 3214, 4000, 1006],
// [2146, 1034, 6745, 4764, 5000]
//];
var colors = color;
var outerR = Math.min(width, height) / 2-85
var innerR = outerR-15
var padAngle = 2 * Math.PI / 200
var names=data.names
var matrix = data.matrix
var chords = d3.chord()
.padAngle(padAngle)(matrix)
clearSvg();
if(matrix.length){
var svg = createSvg(width, height)
var tooltip = d3.select(".body").append("span")
.attr("class","tooltip") //用于css设置类样式
.attr("opacity",0.0)
drawGroups() // 绘制节点
drawChords() // 绘制弦图
drawTicks()
drawLabels()
}else {
d3.select('body').append('div').attr("class","noData").html('暂无关联数据')
}
function createSvg(w, h) {
return d3.select('.relation-box')
.append('svg')
.attr('width', w)
.attr('height', h)
.append('g')
.attr('transform', 'translate('+w/2+','+h/2+')')
}
function clearSvg(){
d3.select('.body').html('')
}
function drawGroups() {
var groups = chords.groups // 节点数组
var maxVal = d3.max(groups, function(d){return d.value})
var arc = d3.arc()
.innerRadius(innerR)
.outerRadius(outerR)
svg.append('g')
.attr('class', 'groups')
.selectAll('g')
.data(groups)
.enter()
.append('g')
.attr('class', 'group')
.append('path')
.attr('d', function(d){
return arc(d)
})
.on('mouseover', fade(0.1))
.on('mouseout', fade(1))
.attr('fill', function(_, i){ return colors[i]})
}
function fade(opacity){
var tooltipOpacity;
opacity==0.1?tooltipOpacity=1:tooltipOpacity=0
return function(g,i){
svg.selectAll(".chord path").filter(function(d){
return d.source.index!=i&&d.target.index!=i;
})
// .transition()
.style("opacity",opacity)
tooltip.html(names[g.index])
//设置tooltip的位置(left,top 相对于页面的距离)
.style("left",d3.event.offsetX+"px")
.style("top",d3.event.offsetY+"px")
.style("opacity",tooltipOpacity);
}
}
function fadeCurrent(opacity){
var tooltipOpacity;
opacity==0.1?tooltipOpacity=1:tooltipOpacity=0
return function(g,i){
svg.selectAll(".chord path")
// .transition()
.style("opacity",opacity)
d3.select(this)
.style("opacity",1);
tooltip.html(names[g.source.index]+"-"+names[g.target.index]+": "+g.source.value+"条")
//设置tooltip的位置(left,top 相对于页面的距离)
.style("left",d3.event.offsetX+"px")
.style("top",d3.event.offsetY+"px")
.style("opacity",tooltipOpacity);
}
}
function drawChords() {
var ribbon = d3.ribbon()
.radius(innerR-5)
svg.append('g')
.attr('class', 'chord')
.selectAll('path')
.data(chords)
.enter()
.append('path')
.attr('d', ribbon)
.attr('fill', function(d){return colors[d.source.index]})
.attr('stroke', function(d){return d3.rgb(colors[d.source.index]).darker()})
.on('mouseover', fadeCurrent(0.1))
.on('mouseout', fadeCurrent(1))
}
function drawTicks() {
d3.selectAll('.group')
.append('g')
.attr('class', 'ticks')
.selectAll('line')
.data(function(d){
var value = d.value,
startAngle = d.startAngle
endAngle = d.endAngle
var k = (endAngle - startAngle) / value
return d3.range(0, value, 100).map(function(value){ return ({
text: value,
angle: d.startAngle + value * k,
})})
})
.enter()
.append('g')
// .call(createRadialTicks)
}
function drawLabels() {
svg.append('g')
.selectAll('text')
.data(chords.groups)
.enter()
.append('g')
.call(setAttr, {
fill: function(_, i){return colors[i]},
transform: function(d){
var deg = rotateAngle(d)
var degRotate = deg-90;
var outerRT = outerR+5;
return 'rotate('+degRotate+')translate('+outerRT+', 0)'
}
})
.append('text')
.attr('dominant-baseline', 'middle')
.text(function(d, i){return names[d.index]})
.call(setAttr, {
transform: function (d) {
var deg = rotateAngle(d)
var boxWidth = -this.getBBox().width
return deg > 180
? 'rotate(180)translate('+boxWidth+', 0)'
: ''
}
})
}
function setAttr(ele, attrs) {
for ( var index in Object.entries(attrs)) {
ele.attr(Object.entries(attrs)[index][0], Object.entries(attrs)[index][1])
}
}
function tsRadian2angle(radian) {
return radian * 180 / Math.PI
}
// 文本旋转角度
function rotateAngle(d) {
return tsRadian2angle( (d.startAngle + d.endAngle) / 2 )
}
}
return relation;
});