UNPKG

dhis2-maps-api

Version:

Maps API for DHIS2 based on Leaflet

172 lines (135 loc) 4.7 kB
// Base class for most vector layers import L from 'leaflet'; import label from './Label'; import polylabel from 'polylabel'; import '../node_modules/leaflet.layergroup.collision/src/Leaflet.LayerGroup.Collision'; const geojsonArea = require('geojson-area'); export const GeoJson = L.GeoJSON.extend({ options: { highlightStyle: { weight: 2, }, resetStyle: { weight: 1, }, }, initialize(options = {}) { if (options.label) { this._labels = L.layerGroup({ margin: 2 }); } L.GeoJSON.prototype.initialize.call(this, options.data, options); }, addLayer(layer) { const options = this.options; const feature = layer.feature; // Add text label if (options.label) { this.addLabel(layer, L.Util.template(options.label, feature.properties)); } if (options.hoverLabel || options.label) { layer.bindTooltip(L.Util.template(options.hoverLabel || options.label, feature.properties), { sticky: true, }); } if (options.popup && !(options.popup instanceof Function)) { layer.bindPopup(L.Util.template(options.popup, feature.properties)); } L.GeoJSON.prototype.addLayer.call(this, layer); }, // Add label to layer addLabel(layer, text) { const prop = layer.feature.properties; const geometry = layer.feature.geometry; const labelStyle = L.extend(prop.labelStyle || {}, this.options.labelStyle); const latlng = this._getLabelLatlng(geometry); if (prop.style && prop.style.color) { labelStyle.color = prop.style.color; } layer._label = label(latlng, { html: text, position: geometry.type === 'Point' ? 'below' : 'middle', labelStyle: labelStyle, pane: this.options.labelPane || 'markerPane', }); this._labels.addLayer(layer._label); }, setOpacity(opacity) { this.setStyle({ opacity: opacity, fillOpacity: opacity, }); }, findById(id) { for (const i in this._layers) { if (this._layers[i].feature.id === id) { return this._layers[i]; } } return null; }, onAdd(map) { L.GeoJSON.prototype.onAdd.call(this, map); if (this._labels) { map.addLayer(this._labels); } if (this.options.highlightStyle) { this.on('mouseover', this.onMouseOver, this); this.on('mouseout', this.onMouseOut, this); } if (this.options.contextmenu) { this.on('contextmenu', this.options.contextmenu); } this.fire('ready'); }, onRemove(map) { L.GeoJSON.prototype.onRemove.call(this, map); if (this._labels) { map.removeLayer(this._labels); } if (this.options.highlightStyle) { this.off('mouseover', this.onMouseOver, this); this.off('mouseout', this.onMouseOut, this); } if (this.options.contextmenu) { this.off('contextmenu', this.options.contextmenu); } }, // Set highlight style onMouseOver(evt) { evt.layer.setStyle(this.options.highlightStyle); }, // Reset style onMouseOut(evt) { if (!evt.layer.feature.isSelected) { evt.layer.setStyle(this.options.resetStyle); } }, // Returns the best label placement _getLabelLatlng(geometry) { const coords = geometry.coordinates; let biggestRing; if (geometry.type === 'Point') { return [coords[1], coords[0]]; } else if (geometry.type === 'Polygon') { biggestRing = coords; } else if (geometry.type === 'MultiPolygon') { biggestRing = coords[0]; // If more than one polygon, place the label on the polygon with the biggest area if (coords.length > 1) { let biggestSize = 0; coords.forEach(ring => { const size = geojsonArea.ring(ring[0]); // Area calculation if (size > biggestSize) { biggestRing = ring; biggestSize = size; } }); } } // Returns pole of inaccessibility, the most distant internal point from the polygon outline return polylabel(biggestRing, 2).reverse(); }, }); export default function geoJson(options) { return new GeoJson(options); }