Public
Edited
Feb 27, 2024
Insert cell
Insert cell
viewof vis = {
let d3cola = cola.d3adaptor(d3).convergenceThreshold(0.1);

const width = 960,
height = 700,
margin = 20,
pad = 12;

let outer = d3.select(DOM.svg(width, height)).attr("pointer-events", "all");

outer
.append("rect")
.attr("class", "background")
.attr("width", "100%")
.attr("height", "100%")
.append("svg:defs")
.append("svg:marker")
.attr("id", "end-arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 8)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5L2,0")
.attr("stroke-width", "0px")
.attr("fill", "#000");

let vis = outer
.append("g")
.attr("transform", "translate(250,250) scale(0.3)");

let { nodes, edges } = JSON.parse(JSON.stringify(data));

d3cola
.avoidOverlaps(true)
.convergenceThreshold(1e-3)
.flowLayout("x", 150)
.size([width, height])
.nodes(nodes)
.links(edges)
.jaccardLinkLengths(150);

let link = vis
.selectAll(".link")
.data(edges)
.enter()
.append("path")
.attr("class", "link");

let node = vis
.selectAll(".node")
.data(nodes)
.enter()
.append("rect")
.classed("node", true)
.attr("rx", 5)
.attr("ry", 5)
.call(d3cola.drag);

let label = vis
.selectAll(".label")
.data(nodes)
.enter()
.append("text")
.attr("class", "label")
.text(function (d) {
return d.name;
})
.call(d3cola.drag)
.each(function (d) {
var b = getBBox(this);
var extra = 2 * margin + 2 * pad;
d.width = b.width + extra;
d.height = b.height + extra;
});
d3cola
.start(50, 100, 200)

.on("tick", function () {
node
.each(function (d) {
d.innerBounds = d.bounds.inflate(-margin);
})
.attr("x", function (d) {
return d.innerBounds.x;
})
.attr("y", function (d) {
return d.innerBounds.y;
})
.attr("width", function (d) {
return d.innerBounds.X - d.innerBounds.x;
})
.attr("height", function (d) {
return d.innerBounds.height();
});

link.attr("d", function (d) {
var route = cola.makeEdgeBetween(
d.source.innerBounds,
d.target.innerBounds,
5
);
return lineFunction([route.sourceIntersection, route.arrowStart]);
});

label
.attr("x", function (d) {
return d.x;
})
.attr("y", function (d) {
return d.y + (margin + pad) / 2;
});
})
.on("end", routeEdges(d3cola, link));

outer.node().value = { nodes, edges };

return outer.node();
}
Insert cell
import { autoBBox } from "@rlesser/automatic-getbbox@344"
Insert cell
Insert cell
Insert cell
Insert cell
graphlibDot = require("https://bundle.run/graphlib-dot@0.6.4")
Insert cell
Insert cell
routeEdges = function (d3cola, link) {
return function () {
d3cola.prepareEdgeRouting();
link.attr("d", function (d) {
return lineFunction(d3cola.routeEdge(d));
});
};
}
Insert cell
lineFunction = d3
.line()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
})
Insert cell
vis
Insert cell
Insert cell
getBBox = (element) => {
const svg = html`<svg style="border:solid 1px red;">
<g name="content">
${element.outerHTML}
</g>
</svg>`;

// Add the SVG element to the DOM so we can determine its size.
document.body.appendChild(svg);

// Computing the bounding box of the content.
const box = svg.querySelector("[name=content]").getBBox();

// Remove the SVG element from the DOM.
svg.remove();

console.log(element.outerHTML);
return box;
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more