Public
Edited
Apr 7, 2024
2 forks
7 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3
.select(this || d3.create("svg").node()) // to redraw on the previous one
.attr("viewBox", [0, 0, width, height]),
gLinks = svg
.selectAll("g#bundledLinks")
.data([0]) // create one if doesn't exist
.join("g")
.attr("id", "bundledLinks"),
link = svg
.selectAll(".link")
.data(graph.links)
.join("line")
.classed("link", true)
.style("stroke", "firebrick")
.style("display", showOriginalLinks ? "block" : "none")
.style("opacity", 0.1),
node = svg
.selectAll(".node")
.data(graph.nodes)
.join("circle")
.attr("fill", (d) => color(d.group))
.attr("r", 3)
.classed("node", true);

const simulation = d3
.forceSimulation()
.nodes(graph.nodes)
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.force(
"link",
d3.forceLink(graph.links).id((d) => d.id)
)
.on("tick", tick);

const drag = d3.drag().on("start", dragstart).on("drag", dragged);

node.call(drag).on("click", click);

const bundling = edgeBundling(graph, {
compatibility_threshold,
bundling_stiffness,
step_size
});

const bundledPaths = gLinks
.selectAll("path.bundled")
.data(graph.links)
.join("path")
.attr("class", "bundled")
.attr("stroke", "#ccc")
.attr("fill", "none")
.attr("opacity", 0.7);

function tick() {
link
.attr("x1", (d) => d.source.x)
.attr("y1", (d) => d.source.y)
.attr("x2", (d) => d.target.x)
.attr("y2", (d) => d.target.y);
node
.attr("stroke", (d) => (d.fx !== undefined ? "black" : "none"))
.attr("stroke-width", (d) => (d.fx !== undefined ? 3 : 0))
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y);

// Draw the force edged results

bundling.update();
bundledPaths.data(graph.links).attr("d", (d) => line(d.path));

node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
}

function click(event, d) {
delete d.fx;
delete d.fy;
d3.select(this).classed("fixed", false);
simulation.alpha(1).restart();
}

function dragstart() {
d3.select(this).classed("fixed", true);
}

function dragged(event, d) {
d.fx = clamp(event.x, 0, width);
d.fy = clamp(event.y, 0, height);
simulation.alpha(1).restart();
}

// for (let i=0; i< 300; i++)
// simulation.tick();
// simulation.stop();
simulation.tick();

invalidation.then(() => simulation.stop());

return svg.node();
}
Insert cell
Insert cell
line = d3.line()
.x(d => d.x)
.y(d => d.y)
Insert cell
color = d3.scaleOrdinal(d3.schemeCategory10)
Insert cell
d3 = require("d3@7")
Insert cell
height = Math.min(500, width * 0.6)
Insert cell
function clamp(x, lo, hi) {
return x < lo ? lo : x > hi ? hi : x;
}
Insert cell
graph = miserables
Insert cell
import {edgeBundling} from "@john-guerra/force-edge-bundling"
Insert cell
miserables = FileAttachment("miserables.json").json()
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