Appearance
Vector layers and GeoJSON
This example shows how to add custom layers in Geo mode and to make them interract with the nodes. While dragging a node, the map will update the shapes to show the countries the node is in.
GeoJSON Europe shape source: Github repo.
Note: Linkurious SAS makes no warranty, expressed or implied, as to the shapes borders obtained from the use of the GeoJSON on the website.
js
import Ogma from '@linkurious/ogma';
// This demo uses 2 external dependencies in addition to Leaflet and Ogma for the example code:
// * leaflet-pip: a leaflet plugin to check if a point is within a GeoJSON shape
// * lodash.debounce: a debounce function implementation
// feel free to replace them with your custom ones if you need to
Ogma.libraries['leaflet'] = L;
let graph = {
nodes: [
{
id: 'Station A',
data: { latitude: 48.858838, longitude: 2.343436 },
attributes: { radius: 10, text: 'Drag me!', x: 0, y: 0 }
},
{
id: 'Station B',
data: { latitude: 51.509615, longitude: -0.134514 },
attributes: { radius: 10, text: 'Drag me!', x: 100, y: 0 }
}
],
edges: [
{
id: 'Eurostar',
source: 'Station A',
target: 'Station B',
attributes: { width: 5, text: 'Eurostar' }
}
]
};
let ogma = new Ogma({
graph: graph,
container: 'graph-container'
});
// this is the reference to the layer we're going to add to the leaflet map
let countriesShapesLayer;
// fetch the GeoJSON data
const getGeoJSONData = () =>
fetch('files/eu-shapes.geojson').then(response => response.json());
const updateShapesVisibility = nodeList => {
// for each node check if it's inside a country shape and return the country name
let countries = nodeList.getGeoCoordinates().map(coords => {
// list of country polygons that contain the provided node point
let polygons = leafletPip.pointInLayer(
L.latLng([coords.latitude, coords.longitude]),
countriesShapesLayer,
true
);
// just return the first one: countries do not overlap, the array is made of a single element.
return polygons[0];
});
// now iterate through all country shapes in the layer and set the opacity
countriesShapesLayer.getLayers().forEach(country => {
let isInside = countries.indexOf(country) > -1;
// play with
country.setStyle({
opacity: isInside ? 1 : 0,
fillOpacity: isInside ? 0.2 : 0
});
});
};
// Enable Geo mode making the nodes draggable
ogma.geo
.enable({ disableNodeDragging: false })
.then(() => getGeoJSONData())
.then(shapesData => {
// ask the map from Ogma
let map = ogma.geo.getMap();
// add a custom layer to the map
countriesShapesLayer = L.geoJSON(shapesData, {
style: {
color: '#ff7800',
weight: 5
}
}).addTo(map);
// now apply a filter based on the graph
let nodeList = ogma.getNodes();
updateShapesVisibility(nodeList);
// When a node is dragged update the map
// debounce the update for performance reason: ogma is pretty fast at notify but the
// leafletPip.pointInLayer method is calculationally heavy
ogma.events.on('dragProgress', () => {
requestAnimationFrame(() => updateShapesVisibility(nodeList));
});
// set the center in europe
return ogma.geo.setView(49.429053, 15.140625, 4);
});
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>
<script src="https://cdn.jsdelivr.net/npm/unfetch@4.2.0/dist/unfetch.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@mapbox/leaflet-pip@1.1.0/leaflet-pip.min.js"></script>
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="graph-container"></div>
<script src="index.js"></script>
</body>
</html>
css
html,
body {
margin: 0;
}
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: 0;
overflow: hidden;
}