Zoom and click on d3 Sankey
gitgitwhat opened this issue · comments
gitgitwhat commented
I'm having trouble making zoom/pan work with sankey along with mouse events.
There are plenty of examples on the ether that show how to do zooming but they all seem to be using old d3 versions. Nothing that I've tried has worked. Same with node double clicks.
Here is my code based on https://observablehq.com/@d3/sankey-component.
const margin = {
top: 20,
right: 20,
bottom: 20,
left: 20,
};
var container = d3.select("#" + elem);
const svg = container.append("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; font: 10px sans-serif;");
const sankey = d3.sankey()
.nodeId(d => d.name)
.nodeAlign(d3[d3.sankeyLeft])
.nodeWidth(20)
.nodePadding(20)
.extent([[1, 5], [width - 1, height - 5]]);
const { nodes, links } = sankey({
nodes: na.map(d => Object.assign({}, d)),
links: la.map(d => Object.assign({}, d))
});
const color = d3.scaleOrdinal(d3.schemeCategory10);
const vsclr = function(d) {
return color(d.category);
};
const rect = svg.append("g")
.attr('transform', `translate(${margin.left}, ${margin.top})`)
.attr("stroke", "#000")
.selectAll()
.data(nodes)
.on("dblclick", d => {
console.log(d);
})
.join("rect")
.attr("x", d => d.x0)
.attr("y", d => d.y0)
.attr("height", d => d.y1 - d.y0)
.attr("width", d => d.x1 - d.x0)
.attr("fill", d => vsclr(d));
const link = svg.append("g")
.attr("fill", "none")
.attr("stroke-opacity", 0.5)
.selectAll()
.data(links)
.join("g")
.style("mix-blend-mode", "multiply");
var linkColor = "target";
var uid = 1;
if (linkColor === "source-target") {
const gradient = link.append("linearGradient")
.attr("id", d => (d.uid = (uid++).toString()).id)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", d => d.source.x1)
.attr("x2", d => d.target.x0);
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", d => vsclr(d.source));
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", d => vsclr(d.target));
}
link.append("path")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke", linkColor === "source-target" ? (d) => d.uid
: linkColor === "source" ? (d) => vsclr(d.source)
: linkColor === "target" ? (d) => vsclr(d.target)
: linkColor)
.attr("stroke-width", d => Math.max(1, d.width));
const tooltip = container
.append('div')
.attr('id', 'tooltip')
.style('position', 'absolute')
.style('padding', '1rem')
.style('background-color', 'white');
link.on("mouseover", (event, d) => {
tooltip.style("opacity", 1)
.style("left", (event.offsetX + 3) + "px")
.style("top", (event.offsetY + 5) + "px")
.html(`<strong>${d.source.name}</strong> - <strong>${d.target.name}</strong>`);
})
.on("mouseout", (event, d) => {
tooltip.style("opacity", 0)
});
svg.append("g")
.selectAll()
.data(nodes)
.join("text")
.attr("x", d => d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6)
.attr("y", d => (d.y1 + d.y0) / 2)
.attr("dy", "0.35em")
.attr("text-anchor", d => d.x0 < width / 2 ? "start" : "end")
.text(d => d.name);
var zoom = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', function(event) {
rect.selectAll().attr('transform', event.transform);
});
svg.call(zoom);