UNPKG

esri-leaflet

Version:

Leaflet plugins for consuming ArcGIS Online and ArcGIS Server services.

198 lines (165 loc) 7.14 kB
import { CRS, DomEvent, TileLayer, Util } from 'leaflet'; import { warn, getUrlParams, setEsriAttribution, removeEsriAttribution } from '../Util'; import mapService from '../Services/MapService'; export var TiledMapLayer = TileLayer.extend({ options: { zoomOffsetAllowance: 0.1, errorTileUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEABAMAAACuXLVVAAAAA1BMVEUzNDVszlHHAAAAAXRSTlMAQObYZgAAAAlwSFlzAAAAAAAAAAAB6mUWpAAAADZJREFUeJztwQEBAAAAgiD/r25IQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7waBAAABw08RwAAAAABJRU5ErkJggg==' }, statics: { MercatorZoomLevels: { 0: 156543.03392799999, 1: 78271.516963999893, 2: 39135.758482000099, 3: 19567.879240999901, 4: 9783.9396204999593, 5: 4891.9698102499797, 6: 2445.9849051249898, 7: 1222.9924525624899, 8: 611.49622628138002, 9: 305.74811314055802, 10: 152.874056570411, 11: 76.437028285073197, 12: 38.218514142536598, 13: 19.109257071268299, 14: 9.5546285356341496, 15: 4.7773142679493699, 16: 2.38865713397468, 17: 1.1943285668550501, 18: 0.59716428355981699, 19: 0.29858214164761698, 20: 0.14929107082381, 21: 0.07464553541191, 22: 0.0373227677059525, 23: 0.0186613838529763 } }, initialize: function (options) { options = Util.setOptions(this, options); // set the urls options = getUrlParams(options); this.tileUrl = (options.proxy ? options.proxy + '?' : '') + options.url + 'tile/{z}/{y}/{x}' + (options.requestParams && Object.keys(options.requestParams).length > 0 ? Util.getParamString(options.requestParams) : ''); // Remove subdomain in url // https://github.com/Esri/esri-leaflet/issues/991 if (options.url.indexOf('{s}') !== -1 && options.subdomains) { options.url = options.url.replace('{s}', options.subdomains[0]); } this.service = mapService(options); this.service.addEventParent(this); var arcgisonline = new RegExp(/tiles.arcgis(online)?\.com/g); if (arcgisonline.test(options.url)) { this.tileUrl = this.tileUrl.replace('://tiles', '://tiles{s}'); options.subdomains = ['1', '2', '3', '4']; } if (this.options.token) { this.tileUrl += ('?token=' + this.options.token); } // init layer by calling TileLayers initialize method TileLayer.prototype.initialize.call(this, this.tileUrl, options); }, getTileUrl: function (tilePoint) { var zoom = this._getZoomForUrl(); return Util.template(this.tileUrl, Util.extend({ s: this._getSubdomain(tilePoint), x: tilePoint.x, y: tilePoint.y, // try lod map first, then just default to zoom level z: (this._lodMap && this._lodMap[zoom]) ? this._lodMap[zoom] : zoom }, this.options)); }, createTile: function (coords, done) { var tile = document.createElement('img'); DomEvent.on(tile, 'load', Util.bind(this._tileOnLoad, this, done, tile)); DomEvent.on(tile, 'error', Util.bind(this._tileOnError, this, done, tile)); if (this.options.crossOrigin) { tile.crossOrigin = ''; } /* Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons http://www.w3.org/TR/WCAG20-TECHS/H67 */ tile.alt = ''; // if there is no lod map or an lod map with a proper zoom load the tile // otherwise wait for the lod map to become available if (!this._lodMap || (this._lodMap && this._lodMap[this._getZoomForUrl()])) { tile.src = this.getTileUrl(coords); } else { this.once('lodmap', function () { tile.src = this.getTileUrl(coords); }, this); } return tile; }, onAdd: function (map) { // include 'Powered by Esri' in map attribution setEsriAttribution(map); if (!this._lodMap) { this.metadata(function (error, metadata) { if (!error && metadata.spatialReference) { var sr = metadata.spatialReference.latestWkid || metadata.spatialReference.wkid; // display the copyright text from the service using leaflet's attribution control if (!this.options.attribution && map.attributionControl && metadata.copyrightText) { this.options.attribution = metadata.copyrightText; map.attributionControl.addAttribution(this.getAttribution()); } // if the service tiles were published in web mercator using conventional LODs but missing levels, we can try and remap them if (map.options.crs === CRS.EPSG3857 && (sr === 102100 || sr === 3857)) { this._lodMap = {}; // create the zoom level data var arcgisLODs = metadata.tileInfo.lods; var correctResolutions = TiledMapLayer.MercatorZoomLevels; for (var i = 0; i < arcgisLODs.length; i++) { var arcgisLOD = arcgisLODs[i]; for (var ci in correctResolutions) { var correctRes = correctResolutions[ci]; if (this._withinPercentage(arcgisLOD.resolution, correctRes, this.options.zoomOffsetAllowance)) { this._lodMap[ci] = arcgisLOD.level; break; } } } this.fire('lodmap'); } else if (map.options.crs && map.options.crs.code && (map.options.crs.code.indexOf(sr) > -1)) { // if the projection is WGS84, or the developer is using Proj4 to define a custom CRS, no action is required } else { // if the service was cached in a custom projection and an appropriate LOD hasn't been defined in the map, guide the developer to our Proj4 sample warn('L.esri.TiledMapLayer is using a non-mercator spatial reference. Support may be available through Proj4Leaflet https://developers.arcgis.com/esri-leaflet/samples/non-mercator-projection/'); } } }, this); } TileLayer.prototype.onAdd.call(this, map); }, onRemove: function (map) { removeEsriAttribution(map); TileLayer.prototype.onRemove.call(this, map); }, metadata: function (callback, context) { this.service.metadata(callback, context); return this; }, identify: function () { return this.service.identify(); }, find: function () { return this.service.find(); }, query: function () { return this.service.query(); }, authenticate: function (token) { var tokenQs = '?token=' + token; this.tileUrl = (this.options.token) ? this.tileUrl.replace(/\?token=(.+)/g, tokenQs) : this.tileUrl + tokenQs; this.options.token = token; this.service.authenticate(token); return this; }, _withinPercentage: function (a, b, percentage) { var diff = Math.abs((a / b) - 1); return diff < percentage; } }); export function tiledMapLayer (url, options) { return new TiledMapLayer(url, options); } export default tiledMapLayer;