Appearance
Visual grouping new
This example shows how to use node grouping to group nodes in geo mode. The grouping transformation automatically computes the coordinates of the groups nodes based on the coordinates of their children.
ts
import Ogma, { RawGraph } from '@linkurious/ogma';
const ogma = new Ogma({
container: 'graph-container'
});
const hexToRgba = (hex: string, alpha: number) => {
// convert hex color to rgba
const r = parseInt(hex.substring(1, 3), 16);
const g = parseInt(hex.substring(3, 5), 16);
const b = parseInt(hex.substring(5, 7), 16);
return `rgba(${r},${g},${b},${alpha})`;
};
interface NodeData {
type: 'Central Office' | 'Department' | 'District Head Office';
district: number;
}
interface Feature<Properties> {
type: 'Feature';
id: number;
geometry: {
type: 'Point';
coordinates: [number, number];
};
properties: Properties;
}
interface FeatureCollection<Properties> {
type: 'FeatureCollection';
features: Feature<Properties>[];
}
const districtColor: Record<number, string> = {
11: '#f0a202',
17: '#f18805',
13: '#d95d39',
19: '#202c59'
};
ogma.styles.addNodeRule(node => node.isVirtual(), {
color: node => {
const district = node.getData('district') as number | undefined;
if (district !== undefined) {
const color = districtColor[district];
return hexToRgba(color, 0.5);
}
}
});
ogma.styles.addRule({
edgeAttributes: {
color: '#333',
width: 2
}
});
ogma.styles.addEdgeRule(edge => edge.isVirtual(), {
color: '#fff',
stroke: {
color: '#202c59',
width: 2
}
});
(async () => {
const graph: RawGraph<Feature<NodeData>, unknown> = await fetch(
'./stores.json'
).then(response => response.json());
await ogma.setGraph(graph);
await ogma.layouts.force({ locate: true });
await ogma.geo.enable({
latitudePath: 'geometry.coordinates.1',
longitudePath: 'geometry.coordinates.0'
});
const grouping = ogma.transformations.addNodeGrouping({
groupIdFunction: node => {
return `group-${node.getData('properties.district')}`;
},
nodeGenerator: (nodes, id) => {
const district = nodes.get(0).getData('properties.district');
return {
id,
data: {
type: 'group',
district
}
};
},
padding: 10,
showContents: true,
enabled: true
});
})();
html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.3/leaflet.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.3/leaflet.js"></script>
<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
{
"nodes": [
{
"id": "0",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 17
},
"geometry": {
"coordinates": [
2.302915632687615,
48.89113528883203
],
"type": "Point"
},
"id": 0
}
},
{
"id": "1",
"data": {
"type": "Feature",
"properties": {
"type": "District Head Office",
"district": 17
},
"geometry": {
"coordinates": [
2.3154087597822297,
48.891032935711166
],
"type": "Point"
},
"id": 1
}
},
{
"id": "2",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 17
},
"geometry": {
"coordinates": [
2.2997031955045486,
48.887555624507996
],
"type": "Point"
},
"id": 2
}
},
{
"id": "3",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 17
},
"geometry": {
"coordinates": [
2.3097045180901716,
48.88542513348682
],
"type": "Point"
},
"id": 3
}
},
{
"id": "4",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 17
},
"geometry": {
"coordinates": [
2.310695272037208,
48.892007923790544
],
"type": "Point"
},
"id": 4
}
},
{
"id": "5",
"data": {
"type": "Feature",
"properties": {
"type": "Central Office"
},
"geometry": {
"coordinates": [
2.3406616033647083,
48.87162697244372
],
"type": "Point"
},
"id": 5
}
},
{
"id": "6",
"data": {
"type": "Feature",
"properties": {
"type": "District Head Office",
"district": 19
},
"geometry": {
"coordinates": [
2.377639836901892,
48.89497890039473
],
"type": "Point"
},
"id": 6
}
},
{
"id": "7",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 19
},
"geometry": {
"coordinates": [
2.391277381644727,
48.89082669920518
],
"type": "Point"
},
"id": 7
}
},
{
"id": "8",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 19
},
"geometry": {
"coordinates": [
2.382738046821686,
48.88579998124541
],
"type": "Point"
},
"id": 8
}
},
{
"id": "9",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 11
},
"geometry": {
"coordinates": [
2.383380793843571,
48.85530666732532
],
"type": "Point"
},
"id": 9
}
},
{
"id": "10",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 11
},
"geometry": {
"coordinates": [
2.3781030418253124,
48.856849903008055
],
"type": "Point"
},
"id": 10
}
},
{
"id": "11",
"data": {
"type": "Feature",
"properties": {
"type": "District Head Office",
"district": 11
},
"geometry": {
"coordinates": [
2.3874811860540035,
48.85096366936003
],
"type": "Point"
},
"id": 11
}
},
{
"id": "12",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 11
},
"geometry": {
"coordinates": [
2.386708625877816,
48.861881748592765
],
"type": "Point"
},
"id": 12
}
},
{
"id": "13",
"data": {
"type": "Feature",
"properties": {
"type": "Department",
"district": 13
},
"geometry": {
"coordinates": [
2.3491292671401425,
48.8305793466796
],
"type": "Point"
},
"id": 13
}
},
{
"id": "14",
"data": {
"type": "Feature",
"properties": {
"type": "District Head Office",
"district": 13
},
"geometry": {
...