D3.js Sankey图表-如何突出显示来自节点的链接集



我一直在制作一个D3 sankey图表,该图表显示了两个时间段内节点之间的音量移动。我的节点是颜色协调的(基于它们的名称(。我已经通过使用简单的CSS在链接上设置了悬停行为,但理想情况下,我需要的是能够悬停在左手边的一个节点上,然后突出显示来自该节点的所有链接。类似地,您应该能够将鼠标悬停在右侧的相应节点上,并高亮显示进入该节点的所有链接。

到目前为止,这是我的代码。任何帮助都将不胜感激:

// set the dimensions and margins of the graph
var margin = {
top: 75,
right: 10,
bottom: 10,
left: 10
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Color scale used
var color = d3.scaleOrdinal().range(["#002060ff", "#164490ff", "#4d75bcff", "#98b3e6ff", "#d5e2feff", "#008cb0ff"]);

// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(175)
.nodePadding(10)
.size([width, height]);
// load the data
var data = {
"years": [{
"year": 2019
}, {
"year": 2020
}
],
"nodes": [{
"node": 0,
"id": "a",
"name": "A"
},
{
"node": 1,
"id": "b",
"name": "B"
},
{
"node": 2,
"id": "c",
"name": "C"
},
{
"node": 3,
"id": "d",
"name": "D"
},
{
"node": 4,
"id": "e",
"name": "E"
},
{
"node": 5,
"id": "f",
"name": "F"
},
{
"node": 6,
"id": "a",
"name": "A"
},
{
"node": 7,
"id": "b",
"name": "B"
},
{
"node": 8,
"id": "c",
"name": "C"
},
{
"node": 9,
"id": "d",
"name": "D"
},
{
"node": 10,
"id": "e",
"name": "E"
},
{
"node": 11,
"id": "f",
"name": "F"
}
],
"links": [{
"source": 0,
"target": 6,
"value": 20
},
{
"source": 0,
"target": 7,
"value": 10
},
{
"source": 0,
"target": 8,
"value": 10
},
{
"source": 0,
"target": 9,
"value": 10
},
{
"source": 0,
"target": 10,
"value": 20
},
{
"source": 0,
"target": 11,
"value": 10
},
{
"source": 1,
"target": 6,
"value": 40
},
{
"source": 1,
"target": 7,
"value": 10
},
{
"source": 1,
"target": 8,
"value": 10
},
{
"source": 1,
"target": 9,
"value": 10
},
{
"source": 1,
"target": 10,
"value": 10
},
{
"source": 1,
"target": 11,
"value": 10
},
{
"source": 2,
"target": 6,
"value": 20
},
{
"source": 2,
"target": 7,
"value": 10
},
{
"source": 2,
"target": 8,
"value": 10
},
{
"source": 2,
"target": 9,
"value": 10
},
{
"source": 2,
"target": 10,
"value": 10
},
{
"source": 2,
"target": 11,
"value": 10
},
{
"source": 3,
"target": 6,
"value": 20
},
{
"source": 3,
"target": 7,
"value": 10
},
{
"source": 3,
"target": 8,
"value": 10
},
{
"source": 3,
"target": 9,
"value": 10
},
{
"source": 3,
"target": 10,
"value": 10
},
{
"source": 3,
"target": 11,
"value": 10
},
{
"source": 4,
"target": 6,
"value": 20
},
{
"source": 4,
"target": 7,
"value": 10
},
{
"source": 4,
"target": 8,
"value": 10
},
{
"source": 4,
"target": 9,
"value": 10
},
{
"source": 4,
"target": 10,
"value": 10
},
{
"source": 4,
"target": 11,
"value": 10
},
{
"source": 5,
"target": 6,
"value": 20
},
{
"source": 5,
"target": 7,
"value": 10
},
{
"source": 5,
"target": 8,
"value": 10
},
{
"source": 5,
"target": 9,
"value": 10
},
{
"source": 5,
"target": 10,
"value": 10
},
{
"source": 5,
"target": 11,
"value": 10
}

]
}
// Constructs a new Sankey
sankey
.nodes(data.nodes)
.links(data.links)
.layout(0);
// add in the links
var link = svg.append("g")
.selectAll(".link")
.data(data.links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", sankey.link())
.style("stroke-width", function(d) {
return Math.max(1, d.dy);
})
.sort(function(a, b) {
return b.dy - a.dy;
})

// add in the nodes
var node = svg.append("g")
.selectAll(".node")
.data(data.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})

// add the rectangles for the nodes
node
.append("rect")
.attr("height", function(d) {
return d.dy;
})
.attr("width", sankey.nodeWidth())
.attr("rx", 3)
.attr("ry", 3)
.style("fill", function(d) {
return d.color = color(d.id.replace(/ .*/, ""));
})
// Add hover text
.append("title")
.text(function(d) {
return d.name + "n" + d.value
});
// add in the title for the nodes
node
.append("text")
.attr("x", 87)
.attr("y", function(d) {
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
return d.name;
})
.style("fill", "white")
@import url('https://fonts.googleapis.com/css2?family=Assistant:wght@600&display=swap');
text {
font-family: 'Assistant', sans-serif
}
text {
font-size: 14px
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Assistant:wght@700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/gh/holtzy/D3-graph-gallery@master/LIB/sankey.js"></script>
<div id="chart"></div>

d3有自己的事件系统,支持悬停、单击、触摸等多种事件。除了非常简单的事情外,通常不需要使用CSS伪类。

// set the dimensions and margins of the graph
var margin = {
top: 75,
right: 10,
bottom: 10,
left: 10
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Color scale used
var color = d3.scaleOrdinal().range(["#002060ff", "#164490ff", "#4d75bcff", "#98b3e6ff", "#d5e2feff", "#008cb0ff"]);

// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(175)
.nodePadding(10)
.size([width, height]);
// load the data
var data = {
"years": [{
"year": 2019
}, {
"year": 2020
}
],
"nodes": [{
"node": 0,
"id": "a",
"name": "A"
},
{
"node": 1,
"id": "b",
"name": "B"
},
{
"node": 2,
"id": "c",
"name": "C"
},
{
"node": 3,
"id": "d",
"name": "D"
},
{
"node": 4,
"id": "e",
"name": "E"
},
{
"node": 5,
"id": "f",
"name": "F"
},
{
"node": 6,
"id": "a",
"name": "A"
},
{
"node": 7,
"id": "b",
"name": "B"
},
{
"node": 8,
"id": "c",
"name": "C"
},
{
"node": 9,
"id": "d",
"name": "D"
},
{
"node": 10,
"id": "e",
"name": "E"
},
{
"node": 11,
"id": "f",
"name": "F"
}
],
"links": [{
"source": 0,
"target": 6,
"value": 20
},
{
"source": 0,
"target": 7,
"value": 10
},
{
"source": 0,
"target": 8,
"value": 10
},
{
"source": 0,
"target": 9,
"value": 10
},
{
"source": 0,
"target": 10,
"value": 20
},
{
"source": 0,
"target": 11,
"value": 10
},
{
"source": 1,
"target": 6,
"value": 40
},
{
"source": 1,
"target": 7,
"value": 10
},
{
"source": 1,
"target": 8,
"value": 10
},
{
"source": 1,
"target": 9,
"value": 10
},
{
"source": 1,
"target": 10,
"value": 10
},
{
"source": 1,
"target": 11,
"value": 10
},
{
"source": 2,
"target": 6,
"value": 20
},
{
"source": 2,
"target": 7,
"value": 10
},
{
"source": 2,
"target": 8,
"value": 10
},
{
"source": 2,
"target": 9,
"value": 10
},
{
"source": 2,
"target": 10,
"value": 10
},
{
"source": 2,
"target": 11,
"value": 10
},
{
"source": 3,
"target": 6,
"value": 20
},
{
"source": 3,
"target": 7,
"value": 10
},
{
"source": 3,
"target": 8,
"value": 10
},
{
"source": 3,
"target": 9,
"value": 10
},
{
"source": 3,
"target": 10,
"value": 10
},
{
"source": 3,
"target": 11,
"value": 10
},
{
"source": 4,
"target": 6,
"value": 20
},
{
"source": 4,
"target": 7,
"value": 10
},
{
"source": 4,
"target": 8,
"value": 10
},
{
"source": 4,
"target": 9,
"value": 10
},
{
"source": 4,
"target": 10,
"value": 10
},
{
"source": 4,
"target": 11,
"value": 10
},
{
"source": 5,
"target": 6,
"value": 20
},
{
"source": 5,
"target": 7,
"value": 10
},
{
"source": 5,
"target": 8,
"value": 10
},
{
"source": 5,
"target": 9,
"value": 10
},
{
"source": 5,
"target": 10,
"value": 10
},
{
"source": 5,
"target": 11,
"value": 10
}
]
};
// Constructs a new Sankey
sankey
.nodes(data.nodes)
.links(data.links)
.layout(0);
// add in the links
var link = svg.append("g")
.selectAll(".link")
.data(data.links)
.enter()
.append("path")
.attr("class", "link")
.attr("d", sankey.link())
.style("stroke-opacity", 0.2)
.style("stroke-width", function(d) {
return Math.max(1, d.dy);
})
.sort(function(a, b) {
return b.dy - a.dy;
});
// add in the nodes
var node = svg.append("g")
.selectAll(".node")
.data(data.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
// add the rectangles for the nodes
node
.append("rect")
.attr("height", function(d) {
return d.dy;
})
.attr("width", sankey.nodeWidth())
.attr("rx", 3)
.attr("ry", 3)
.style("fill", function(d) {
return d.color = color(d.id.replace(/ .*/, ""));
})
.on("mouseover", function(d) {
link
.transition()
.duration(300)
.style("stroke-opacity", function(l) {
return l.source === d || l.target === d ? 0.5 : 0.2;
});
})
.on("mouseleave", function(d) {
link
.transition()
.duration(300)
.style("stroke-opacity", 0.2);
})
// Add hover text
.append("title")
.text(function(d) {
return d.name + "n" + d.value
});
// add in the title for the nodes
node
.append("text")
.attr("x", 87)
.attr("y", function(d) {
return d.dy / 2;
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
return d.name;
})
.style("fill", "white");
@import url('https://fonts.googleapis.com/css2?family=Assistant:wght@600&display=swap');
text {
font-family: 'Assistant', sans-serif
}
text {
font-size: 14px
}
.link {
fill: none;
stroke: #000;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Assistant:wght@700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/gh/holtzy/D3-graph-gallery@master/LIB/sankey.js"></script>
<div id="chart"></div>

最新更新