Public
Edited
Apr 25, 2023
Fork of D3-DAG: Grid
1 fork
1 star
Insert cell
Insert cell
{
// Get laidout dag
const { width, height, dag } = laidout;
console.log("x", [...new Set([...dag].map((n) => n.x))][0]);
for (const { points } of dag.ilinks()) {
if (points.length > 2) console.log(points.slice(1, -1));
}

// This code only handles rendering
const svgNode = svg`<svg width=${width} height=${height}></svg>`;

const svgSelection = d3.select(svgNode);
const defs = svgSelection.append("defs"); // For gradients

const steps = dag.size();
const interp = d3.interpolateRainbow;
const colorMap = {};
for (const [i, node] of [...dag].entries()) {
let nodeType = findNodeType(node.data.id);
colorMap[nodeType] = interp(i / steps);
}

// How to draw edges
const curveStyle =
splines.get(spline) ??
{
Grid: [d3.curveBasis, d3.curveBasis],
Zherebko: [d3.curveMonotoneY, d3.curveMonotoneX],
Sugiyama: [d3.curveNatural, d3.curveNatural]
}[algorithm][+horizontal];
const line = d3
.line()
.curve(curveStyle)
.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", 3)
.attr("stroke", ({ source, target }) => {
// encode URI component to handle special characters
const gradId = encodeURIComponent(
`${source.data.id.replaceAll(" ", "")}--${target.data.id.replaceAll(
" ",
""
)}`
);
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[findNodeType(source.data.id)]);
grad
.append("stop")
.attr("offset", "100%")
.attr("stop-color", colorMap[findNodeType(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})`);

// Plot node circles
nodes
.append("circle")
.attr("r", nodeRadius)
.attr("fill", (n) => colorMap[findNodeType(n.data.id)]);

// Add text to nodes
nodes
.append("text")
.text((d) => d.data.id)
.attr("font-size", "9")
.attr("font-weight", "bold")
.attr("font-family", "sans-serif")
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
.attr("stroke", "white")
.attr("paint-order", "stroke")
.attr("fill", "black");

return svgNode;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
findNodeType = (id) => _.find(dataCrisp.nodes, ["label", id]).type
Insert cell
Insert cell
Insert cell
Insert cell
mydag = require("d3-dag@0.11.5")
Insert cell
Insert cell
d3.grid().rank
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
algorithms = {
return {
Grid: {
"Top Down": gridTweak(gridCompact(d3.grid())),
"Bottom Up": gridTweak(
gridCompact(d3.grid().lane(d3.laneGreedy().topDown(false)))
),
Open: gridTweak(gridCompact(d3.grid().lane(leftLane))),
"Optimal (slow)": gridTweak(gridCompact(d3.grid().lane(d3.laneOpt())))
},
Zherebko: {
Greedy: d3
.zherebko()
.nodeSize([
nodeRadius * 2,
(nodeRadius + edgeRadius) * 2,
edgeRadius * 2
])
},
Sugiyama: {
Fast: d3
.sugiyama()
.layering(d3.layeringTopological())
.coord(d3.coordTopological())
.nodeSize((d) =>
d === undefined
? [edgeRadius * 2, 0]
: [nodeRadius * 2, (nodeRadius + edgeRadius) * 2]
),
Slow: d3
.sugiyama()
.layering(d3.layeringTopological())
.decross(d3.decrossOpt())
.coord(d3.coordTopological())
.nodeSize((d) =>
d === undefined
? [edgeRadius * 2, 0]
: [nodeRadius * 2, (nodeRadius + edgeRadius) * 2]
)
}
};
}
Insert cell
dagData = FileAttachment("dag-data.json").json()
Insert cell
dataCrisp = FileAttachment("data-crisp.json").json()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more