Appearance
d3 integration
This example shows how you can use your charts and graphs developed with d3 in full sync with Ogma visualisation.
ts
import Ogma, { NodeId } from '@linkurious/ogma';
import * as d3 from 'd3';
const ogma = new Ogma({
container: 'graph-container',
graph: {
nodes: [{ id: 'us' }, { id: 'de' }, { id: 'fr' }],
edges: [
{ source: 'us', target: 'de' },
{ source: 'de', target: 'fr' },
{ source: 'fr', target: 'us' }
]
},
options: {
interactions: {
zoom: { maxValue: () => Infinity }
}
}
});
//
ogma.styles.addRule({
nodeAttributes: {
radius: 9,
color: '#055761'
},
edgeAttributes: {
width: 0.8
}
});
const colors = [
'#98abc5',
'#8a89a6',
'#7b6888',
'#6b486b',
'#a05d56',
'#d0743c',
'#ff8c00'
];
interface DataPoint {
label: string;
value: number;
}
const data = [
{ label: '<5', value: 2704659 },
{ label: '5-13', value: 4499890 },
{ label: '14-17', value: 2159981 },
{ label: '18-24', value: 3853788 },
{ label: '25-44', value: 14106543 },
{ label: '45-64', value: 8819342 },
{ label: '≥65', value: 612463 }
];
ogma.layouts.force({ locate: true }).then(() => {
const pie = d3
.pie<DataPoint>()
.sort(null)
.value(d => d.value);
// randomize data for the sake of example
const arcsById: Record<NodeId, d3.PieArcDatum<DataPoint>[]> = ogma
.getNodes()
.reduce((acc, node) => {
acc[node.getId()] = pie(
data.map(({ label }) => ({
label,
value: Math.round(Math.random() * 7e6)
}))
);
return acc;
}, {});
const radius = 15;
const arc = d3
.arc<d3.PieArcDatum<DataPoint>>()
.outerRadius(radius - radius * 0.1)
.innerRadius(radius - radius * 0.3);
const labelArc = d3
.arc<d3.PieArcDatum<DataPoint>>()
.outerRadius(radius - radius * 0.2)
.innerRadius(radius - radius * 0.2);
function renderDonutChart(
ctx: CanvasRenderingContext2D,
arcs: d3.PieArcDatum<DataPoint>[],
x: number,
y: number
) {
ctx.save();
ctx.translate(x, y);
const drawArc = arc.context(ctx);
arcs.forEach((d, i) => {
ctx.beginPath();
drawArc(d);
ctx.fillStyle = colors[i];
ctx.fill();
});
ctx.beginPath();
arcs.forEach(arc);
ctx.strokeStyle = '#fff';
ctx.lineWidth = 0.1;
ctx.stroke();
ctx.font = '1px Georgia, Times, serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#fff';
const drawLabelArc = labelArc.context(ctx);
arcs.forEach(d => {
const [x, y] = drawLabelArc.centroid(d);
ctx.fillText(d.data.label, x, y);
});
ctx.restore();
}
const render = (ctx: CanvasRenderingContext2D) =>
ogma.getNodes().forEach(node => {
const id = node.getId();
const { x, y } = node.getPosition();
renderDonutChart(ctx, arcsById[id], x, y);
});
const layer = ogma.layers.addCanvasLayer(ctx => render(ctx));
ogma.events.on(['nodesDragProgress'], () => layer.refresh());
});
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;
}