Skip to content
  1. Examples

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": {
 

...