I am using D3-DAG Sugiyama to render DAG. On click of a node, I need to highlight all its child nodes. I am able to get only the data (id’s of node and its child) and not the node on click. const nodeB = dag.descendants().find(node => node.id() === p.data.id) is not returning the node. This is what I tried.
const dag = d3.dagStratify()(data);
const nodeRadius = 15;
const layout = d3
.sugiyama() // base layout
.layering(d3.layeringLongestPath())
.nodeSize((node) => {
return [(node ? 3.6 : 0.25) * nodeRadius, 3 * nodeRadius];
})
const { width, height } = layout(dag);
// --------------------------------
// This code only handles rendering
// --------------------------------
const svgSelection = d3.select("svg");
svgSelection.attr("viewBox", [0, 0, width, height].join(" "));
const defs = svgSelection.append("defs"); // For gradients
const trans = svgSelection.transition().duration(750);
const steps = dag.size();
const interp = d3.interpolateRainbow;
const colorMap = new Map();
for (const [i, node] of dag.idescendants().entries()) {
colorMap.set(node.data.id, interp(i / steps));
}
//const nodeB = dag.descendants().find(node => node.id() === "B");
// How to draw edges
const line = d3
.line()
.curve(d3.curveCatmullRom)
.x((d) => d.x)
.y((d) => d.y);
// Plot edges
svgSelection
.append("g")
.selectAll("path")
.data(dag.links())
.enter()
.append("path")
.attr("d", ({ points }) => line(points))
.attr("fill", "none")
.attr("stroke-width", 1)
.attr("stroke", ({ source, target }) => {
// encodeURIComponents for spaces, hope id doesn't have a `--` in it
const gradId = encodeURIComponent(`${source.data.id}--${target.data.id}`);
const grad = defs
.append("linearGradient")
.attr("id", gradId)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", source.x)
.attr("x2", target.x)
.attr("y1", source.y)
.attr("y2", target.y);
grad
.append("stop")
.attr("offset", "0%")
.attr("stop-color", colorMap.get(source.data.id));
grad
.append("stop")
.attr("offset", "100%")
.attr("stop-color", colorMap.get(target.data.id));
return `url(#${gradId})`;
});
// Select nodes
const nodes = svgSelection
.append("g")
.selectAll("g")
.data(dag.descendants())
.enter()
.append("g")
.attr("transform", ({ x, y }) => `translate(${x}, ${y})`);
var titleTip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("border", "1px thin black")
.style("background-color", "#D3D3D3")
.style("stroke", "#000")
.style("stroke-width", "10");
// Plot node circles
nodes
.append("circle")
.attr("id", "circleBasicTooltip")
.attr("r", nodeRadius)
.attr("fill", (n) => colorMap.get(n.data.id))
nodes
.each(function (p, j) {
d3.select(this)
.on("click", (selectedNode) => {
selectedNode.srcElement.attributes.fill = 'grey';
const nodeB = dag.descendants().find(node => node.id() === p.data.id);// not able to get the node
const highlightedNode = p.data.id;
})
})
const arrowSize = (nodeRadius * nodeRadius) / 10.0;
const arrowLen = Math.sqrt((4 * arrowSize) / Math.sqrt(3));
const arrow = d3.symbol().type(d3.symbolTriangle).size(arrowSize);
svgSelection
.append("g")
.selectAll("path")
.data(dag.links())
.enter()
.append("path")
.attr("d", arrow)
.attr("transform", ({ points }) => {
var twoPoints = points.slice(-2);
const sx = twoPoints[0].x;
const sy = twoPoints[0].y;
const ex = twoPoints[1].x;
const ey = twoPoints[1].y;
const dx = sx - ex;
const dy = sy - ey;
// This is the angle of the last line segment
const scale = nodeRadius * 1.15 / Math.sqrt(dx * dx + dy * dy);
const angle = (Math.atan2(-dy, -dx) * 180) / Math.PI + 90;
return `translate(${ ex + dx * scale }, ${ ey + dy * scale }) rotate(${ angle })`
})
.attr("stroke", "white")
.attr("stroke-width", 1.5)
.attr("stroke-dasharray", `${arrowLen},${arrowLen}`);
//Add text to nodes
nodes
.append("text")
.text((d) => d.data.id)
.attr("font-weight", "bold")
.attr("font-family", "sans-serif")
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
.attr("fill", "white")