Appearance
Density contours
See how you can render the density controus using d3-contours in a background layer. This example also shows how you can pre-calculate and cache the contours to improve performance and appearance.
ts
import Ogma, { Point } from '@linkurious/ogma';
import * as d3 from 'd3';
const ogma = new Ogma({
container: 'graph-container',
options: {
interactions: {
zoom: { maxValue: () => Infinity },
drag: { enabled: false }
}
}
});
ogma.styles.addRule({
edgeAttributes: {
width: 0.5,
color: '#aaa'
},
nodeAttributes: {
color: '#333'
}
});
const clamp = (value: number, min: number, max: number) =>
Math.max(min, Math.min(max, value));
const graph = await Ogma.parse.jsonFromUrl('files/codeminer.json');
await ogma.setGraph(graph);
await ogma.layouts.force({ gpu: true, steps: 80, locate: true });
// shift the graph to the center, d3-contour doesn't work with negative values
const { width, height } = ogma.getNodes().getBoundingBox();
await ogma.getNodes().setAttributes(
ogma
.getNodes()
.getPosition()
.map(p => ({ x: p.x + width / 2, y: p.y + height / 2 }))
);
await ogma.view.locateGraph();
const positions = ogma.getNodes().getPosition();
const maxLod = 4;
const minLod = 0;
const lods = Array.from({ length: maxLod - minLod + 1 }, (_, i) => i + minLod);
// pre-calculate lods
const contours = lods.map(zoom =>
d3
.contourDensity<Point>()
.x(d => d.x)
.y(d => d.y)
.size([width, height])
.bandwidth(120)
.thresholds(zoom * 10)(positions)
);
const render = (ctx: CanvasRenderingContext2D) => {
const renderContour = d3.geoPath().context(ctx);
const zoom = ogma.view.getZoom();
ctx.beginPath();
ctx.strokeStyle = 'red';
const lod = clamp(Math.round(zoom * 10), minLod, maxLod);
const LODcontour = contours[lod];
ctx.lineWidth = 1 / ogma.view.getZoom();
LODcontour.forEach(contour => renderContour(contour));
ctx.closePath();
ctx.stroke();
};
const layer = ogma.layers.addCanvasLayer(ctx => render(ctx));
layer.moveToBottom();
html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="graph-container"></div>
<script type="module" src="index.ts"></script>
</body>
</html>
css
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: 0;
overflow: hidden;
}
json
{
"name": "test",
"version": "0.0.0",
"description": "Ogma, large-scale graph visualization library",
"main": "index.ts",
"module": "index.ts",
"scripts": {
"start": "vite dev --open",
"build": "vite build"
},
"dependencies": {
"@linkurious/ogma": "https://get.linkurio.us/api/get/npm/5.2.0/?secret=YOUR_API_KEY",
"d3": "7.9.0"
},
"devDependencies": {
"vite": "latest"
}
}