UNPKG

esri-leaflet-vector

Version:

Esri vector basemap and vector tile layer plugin for Leaflet.

232 lines (211 loc) 7.54 kB
import { Util } from 'esri-leaflet'; import { getBasemapStyleUrl, getAttributionData, getBasemapStyleV2Url } from './Util'; import { VectorTileLayer } from './VectorTileLayer'; const POWERED_BY_ESRI_ATTRIBUTION_STRING = 'Powered by <a href="https://www.esri.com">Esri</a>'; export const VectorBasemapLayer = VectorTileLayer.extend({ /** * Populates "this.options" to be used in the rest of the module. * * @param {string} key * @param {object} options optional */ initialize: function (key, options) { // Default to the v1 service endpoint if (!options.version) { if (key.includes('/')) options.version = 2; else options.version = 1; } if (!key) { // Default style enum if none provided key = options.version === 1 ? 'ArcGIS:Streets' : 'arcgis/streets'; } // If no API Key or token is provided (support outdated casing apiKey of apikey) if (!(options.apikey || options.apiKey || options.token)) { throw new Error( 'An API Key or token is required for vectorBasemapLayer.' ); } // Validate v2 service params if (options.version !== 2) { if (options.language) { throw new Error( 'The language parameter is only supported by the basemap styles service v2. Provide a v2 style enumeration to use this option.' ); } if (options.worldview) { throw new Error( 'The worldview parameter is only supported by the basemap styles service v2. Provide a v2 style enumeration to use this option.' ); } if (options.places) { throw new Error( 'The places parameter is only supported by the basemap styles service v2. Provide a v2 style enumeration to use this option.' ); } } // Determine layer order if (!options.pane) { if (key.includes(':Label') || key.includes('/label')) { options.pane = 'esri-labels'; } else if (key.includes(':Detail') || key.includes('/detail')) { options.pane = 'esri-detail'; } else { // Create layer in the tilePane by default options.pane = 'tilePane'; } } // Options has been configured, continue on to create the layer: VectorTileLayer.prototype.initialize.call(this, key, options); }, /** * Creates the maplibreGLJSLayer using "this.options" */ _createLayer: function () { let styleUrl; if (this.options.version && this.options.version === 2) { styleUrl = getBasemapStyleV2Url(this.options.key, this.options.apikey, { language: this.options.language, worldview: this.options.worldview, places: this.options.places, baseUrl: this.options.baseUrl }); } else { styleUrl = getBasemapStyleUrl(this.options.key, this.options.apikey); } // show error warning on successful response for previous version(1) if (this.options.version && this.options.version === 1) { fetch(styleUrl) .then((response) => { return response.json(); }) .then((styleData) => { if (styleData.error) { console.warn('Error:', styleData.error.message); } }) .catch((error) => { console.warn('Error:', error.message); }); } this._createMaplibreLayer(styleUrl); }, _setupAttribution: function () { if (this.options.key.length === 32) { // this is an itemId const sources = this._maplibreGL.getMaplibreMap().style.stylesheet.sources; const allAttributions = []; Object.keys(sources).forEach(function (key) { allAttributions.push(sources[key].attribution); if ( sources[key].copyrightText && sources[key].copyrightText && sources[key].copyrightText !== '' && sources[key].attribution !== sources[key].copyrightText ) { allAttributions.push(sources[key].copyrightText); } }); // In the case of an enum, since the attribution is dynamic, Esri Leaflet // will add the "Powered by Esri" string. But in this case we are not // dynamic so we must add it ourselves. this._map.attributionControl.addAttribution( `<span class="esri-dynamic-attribution">${POWERED_BY_ESRI_ATTRIBUTION_STRING} | ${allAttributions.join( ', ' )}</span>` ); } else { // setup dynamic attribution Util.setEsriAttribution(this._map); // this is an enum if (!this.options.attributionUrls) { this.options.attributionUrls = this._getAttributionUrls( this.options.key ); } if (this._map && this.options.attributionUrls) { if (this._map.attributionControl) { for ( let index = 0; index < this.options.attributionUrls.length; index++ ) { const attributionUrl = this.options.attributionUrls[index]; getAttributionData(attributionUrl, this._map); } this._map.attributionControl.addAttribution( '<span class="esri-dynamic-attribution"></span>' ); } Util._updateMapAttribution({ target: this._map }); } } }, /** * Given a key, return the attribution url(s). * @param {string} key */ _getAttributionUrls: function (key) { if (key.indexOf('OSM:') === 0 || key.indexOf('osm/') === 0) { return ['https://static.arcgis.com/attribution/Vector/OpenStreetMap_v2']; } else if ( key.indexOf('ArcGIS:Imagery') === 0 || key.indexOf('arcgis/imagery') === 0 ) { return [ 'https://static.arcgis.com/attribution/World_Imagery', 'https://static.arcgis.com/attribution/Vector/World_Basemap_v2' ]; } // default: return ['https://static.arcgis.com/attribution/Vector/World_Basemap_v2']; }, _initPane: function () { if (!this._map.getPane(this.options.pane)) { const pane = this._map.createPane(this.options.pane); pane.style.pointerEvents = 'none'; let zIndex = 500; if (this.options.pane === 'esri-detail') { zIndex = 250; } else if (this.options.pane === 'esri-labels') { zIndex = 300; } pane.style.zIndex = zIndex; } }, onRemove: function (map) { map.off('moveend', Util._updateMapAttribution); map.removeLayer(this._maplibreGL); if (map.attributionControl) { if (Util.removeEsriAttribution) Util.removeEsriAttribution(map); const element = document.getElementsByClassName( 'esri-dynamic-attribution' ); if (element && element.length > 0) { const vectorAttribution = element[0].outerHTML; // call removeAttribution twice here // this is needed due to the 2 different ways that addAttribution is called inside _setupAttribution. // leaflet attributionControl.removeAttribution method ignore a call when the attribution sent is not present there map.attributionControl.removeAttribution(vectorAttribution); map.attributionControl.removeAttribution( '<span class="esri-dynamic-attribution"></span>' ); } } }, _asyncAdd: function () { const map = this._map; this._initPane(); map.on('moveend', Util._updateMapAttribution); this._maplibreGL.addTo(map, this); } }); export function vectorBasemapLayer (key, options) { return new VectorBasemapLayer(key, options); } export default vectorBasemapLayer;