Published
Edited
Jul 1, 2019
5 stars
Insert cell
Insert cell
chart = {
const links = data.links.map(d => Object.create(d));
const nodes = data.nodes.map(d => Object.create(d));

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

let element = DOM.canvas(width, height);

const svg = d3.select(element);

let illo = new Zdog.Illustration({
element,
dragRotate: true,
zoom: 2,
// Reheat simulation on drag to trigger tick and update Zdog rendering
onDragStart: () => simulation.alphaTarget(0.1).restart(),
onDragEnd: () => simulation.alphaTarget(0)
});

svg.call(
d3
.zoom()
.scaleExtent([0.1, 10])
.on("zoom", () => {
illo.scale.x = d3.event.transform.k;
illo.scale.y = d3.event.transform.k;
illo.scale.z = d3.event.transform.k;
illo.updateRenderGraph();
})
);

let nodeShapes = nodes.reduce((acc, n) => {
const shape = new Zdog.Shape({
addTo: illo,
stroke: 5,
translate: { x: n.x, y: n.y, z: n.z },
color: color(n)
});
acc[n.id] = shape;
return acc;
}, {});

let linkShapes = links.reduce((acc, l) => {
const shape = new Zdog.Shape({
addTo: illo,
stroke: l.value / 3,
path: [
{ x: l.source.x, y: l.source.y, z: l.source.z },
{ x: l.target.x, y: l.target.y, z: l.target.z }
],
color: d3.color("rgba(153, 153, 153, 0.6)")
});
acc[l.source.id + "->" + l.target.id] = shape;
return acc;
}, {});

simulation.on("tick", () => {
let nodesCentroid = nodes.reduce(
(acc, n) => {
acc.x += n.x / nodes.length;
acc.y += n.y / nodes.length;
acc.z += n.z / nodes.length;
return acc;
},
{ x: 0, y: 0, z: 0 }
);

links.forEach(l => {
linkShapes[l.source.id + "->" + l.target.id].path = [
{
x: l.source.x - nodesCentroid.x,
y: l.source.y - nodesCentroid.y,
z: l.source.z - nodesCentroid.z
},
{
x: l.target.x - nodesCentroid.x,
y: l.target.y - nodesCentroid.y,
z: l.target.z - nodesCentroid.z
}
];
linkShapes[l.source.id + "->" + l.target.id].updatePath();
});

nodes.forEach(
n =>
(nodeShapes[n.id].translate = {
x: n.x - nodesCentroid.x,
y: n.y - nodesCentroid.y,
z: n.z - nodesCentroid.z
})
);

illo.updateRenderGraph();
});

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

return svg.node();
}
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