Appearance
Custom charts
This example shows how to generate custom textures that you can apply on nodes to create features that are not native to Ogma, such as donut charts.
It uses the image attribute to display the generated images.
js
import Ogma from '@linkurious/ogma';
import { pieChart, donutChart } from './charts.js';
const ogma = new Ogma({
container: 'graph-container'
});
const MAX = 220;
const PIE = 0;
const DONUT = 1;
ogma.generate
.random({ nodes: 10, edges: 30 })
.then(graph => {
// fill dummy values for the charts
graph.nodes.forEach(node => {
const value1 = Math.random() * MAX;
const value2 = (MAX - value1) * Math.random();
node.data = {
value1,
value2,
chartType: Math.random() > 0.5 ? PIE : DONUT
};
});
return ogma.addGraph(graph);
})
.then(() => ogma.layouts.force({ locate: true }));
const textureCache = {};
//On the Ogma code you could re-define your style rule as follow:
ogma.styles.addNodeRule({
// raw number for the wedges here, the function will compute the %
image: node => {
// chart wedges
const data = [node.getData('value1'), node.getData('value2'), MAX];
// custom colors for the wedges
const palette = ['#f05365', '#fca311', '#605770'];
const type = node.getData('chartType');
// if you have a lot of data, we recommend to cache the texture
const textureId = [type, ...data].join('_');
if (!textureCache[textureId]) {
// render the texture if not cached
textureCache[textureId] =
type === DONUT
? donutChart(data, palette, '#fff', 0.6)
: pieChart(data, palette);
}
return textureCache[textureId];
},
radius: 10
});
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 src="index.js"></script>
</body>
</html>
css
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: 0;
overflow: hidden;
}
js
function renderPieChart(data, palette, ctx, size) {
let lastend = -Math.PI / 2; // start at 12:00
let total = 0;
for (let e = 0; e < data.length; e++) total += data[e];
const halfWidth = size / 2;
const halfHeight = size / 2;
for (let i = 0; i < data.length; i++) {
const slice = data[i] / total;
ctx.fillStyle = palette[i];
ctx.beginPath();
ctx.moveTo(halfWidth, halfHeight);
ctx.arc(
halfWidth,
halfHeight,
halfHeight,
lastend,
lastend + Math.PI * 2 * slice,
false
);
ctx.lineTo(halfWidth, halfHeight);
ctx.fill();
lastend += Math.PI * 2 * slice;
}
}
export function pieChart(data, palette) {
const canvas = document.createElement('canvas');
// make it 256px per side to be crispy on retina displays
const size = 256;
canvas.width = canvas.height = size;
const ctx = canvas.getContext('2d');
renderPieChart(data, palette, ctx, size);
return canvas.toDataURL();
}
export function donutChart(data, palette, centerFillColor, innerRadius = 0.5) {
const canvas = document.createElement('canvas');
// make it 256px per side to be crispy on retina displays
const size = 256;
canvas.width = canvas.height = size;
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const halfWidth = size / 2;
const halfHeight = size / 2;
renderPieChart(data, palette, ctx, size);
// now draw a circle at the center of the pie chart to make it become a donut chart
ctx.fillStyle = centerFillColor;
ctx.beginPath();
ctx.moveTo(halfWidth, halfHeight);
ctx.arc(halfWidth, halfHeight, innerRadius * halfHeight, 0, Math.PI * 2);
ctx.lineTo(halfWidth, halfHeight);
ctx.fill();
return canvas.toDataURL();
}
html
This example shows how you can create a custom donut chart on each node.