UNPKG

esri-leaflet-vector

Version:

Esri vector basemap and vector tile layer plugin for Leaflet.

235 lines (214 loc) 7.5 kB
import { Util } from "esri-leaflet"; import { getBasemapStyleUrl, getAttributionData, getBasemapStyleV2Url, } from "./Util.js"; import { VectorTileLayer } from "./VectorTileLayer.js"; 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(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() { 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) => response.json()) .then((styleData) => { if (styleData.error) { console.warn("Error:", styleData.error.message); } }) .catch((error) => { console.warn("Error:", error.message); }); } this._createMaplibreLayer(styleUrl); }, _setupAttribution() { if (this.options.key.length === 32) { // this is an itemId const sources = this._maplibreGL.getMaplibreMap().style.stylesheet.sources; const allAttributions = []; Object.keys(sources).forEach((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(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() { 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(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() { 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;