Published
Edited
Nov 11, 2020
Importers
1 star
Insert cell
Insert cell
graph = ({
id: "root",
layoutOptions: { 'elk.algorithm': 'layered' },
children: [
{ id: "n1", width: 30, height: 30, label:"Box A" },
{ id: "n2", width: 30, height: 30, label:"Hello World B" },
{ id: "n3", width: 30, height: 30, label:"Hello World C" }
],
edges: [
{ id: "e1", sources: [ "n1" ], targets: [ "n2" ] },
{ id: "e2", sources: [ "n1" ], targets: [ "n3" ] }
]
})
Insert cell
render(graph)
Insert cell
getTextWidth = text => style["font.char.width"] * len(text)
Insert cell
getTextSize = text => {
const lines = text ? text.split("\n") : [];
return [max(map(lines, getTextWidth)), style["font.line.height"]];
}
Insert cell
md`## Graph rendering`
Insert cell
render = (graph) => {
each(graph.children, prepareNode);
return Elk.layout(graph).then(_ => {
const layers = {};
const addToLayer = (v,k)=> {layers[k] = append(layers[k]||[], v)};

each(graph.children, _ => each(renderNode(_), addToLayer));
each(graph.edges, _ => each(renderEdge(_), addToLayer));
const svg_layers = reduce(layers, (r,v,k)=>{r.push(map(v, _ => S.g({"class":k}, v)))}, []);
return S.svg({width:_.width,height:_.height}, svg_layers);
});
}
Insert cell
prepareNode = (node) => {
if (node.label) {
const [w,h] = getTextSize(node.label);
node.width = w + (style["node.padding.left"]||0) + (style["node.padding.right"]||0);
node.height = h + (style["node.padding.top"]||0) + (style["node.padding.bottom"]||0);
}
return node;
}
Insert cell
renderEdge = edge => {
// Support: bendPoint
const path = reduce(edge.sections, (r,v,i)=>{
if (r.length === 0) {r.push("M");}
r.push(v.startPoint.x);
r.push(v.startPoint.y);
r.push("L");
r.push(v.endPoint.x);
r.push(v.endPoint.y);
return r;
}, []).join(" ");
return {
edges: S.path({"class":"edge", d:path, fill:"none", stroke:"black", "stroke-width":"1px"})
}
}
Insert cell
renderNode = node => {
const {x,y,width,height,label} = node;
const dx = style["node.padding.left"];
const dy = style["node.padding.top"] + style["font.char.height"];
return {
shapes : S.rect({"class":"shape", width, height, x, y}),
labels : S.text({"class":"label",x,y,dx,dy}, label),
};
}
Insert cell
Insert cell
Insert cell
stylesheet({
".shape":{
"fill": "#0082DC",
},
".label":{
"fill": "#FFFFFF",
},
})
Insert cell
Insert cell
Insert cell
Insert cell
import {svg as S, map, maplist, reduce, each, max, len, stylesheet, append, values} from "@sebastien/boilerplate"
Insert cell
ELK = require('elkjs/lib/elk.bundled.js')
Insert cell
Elk = new ELK()
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