- _resetView: function (e) {
- var animating = e && (e.pinch || e.flyTo);
- this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
- },
-
- _animateZoom: function (e) {
- this._setView(e.center, e.zoom, true, e.noUpdate);
- },
-
- _setView: function (center, zoom, noPrune, noUpdate) {
- var tileZoom = Math.round(zoom);
- if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||
- (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {
- tileZoom = undefined;
- }
-
- var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);
-
- if (!noUpdate || tileZoomChanged) {
-
- this._tileZoom = tileZoom;
-
- if (this._abortLoading) {
- this._abortLoading();
- }
-
- this._updateLevels();
- this._resetGrid();
-
- if (tileZoom !== undefined) {
- this._update(center);
- }
-
- if (!noPrune) {
- this._pruneTiles();
- }
-
- // Flag to prevent _updateOpacity from pruning tiles during
- // a zoom anim or a pinch gesture
- this._noPrune = !!noPrune;
- }
-
- this._setZoomTransforms(center, zoom);
- },
-
- _setZoomTransforms: function (center, zoom) {
- for (var i in this._levels) {
- this._setZoomTransform(this._levels[i], center, zoom);
- }
- },
-
- _setZoomTransform: function (level, center, zoom) {
- var scale = this._map.getZoomScale(zoom, level.zoom),
- translate = level.origin.multiplyBy(scale)
- .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
-
- if (L.Browser.any3d) {
- L.DomUtil.setTransform(level.el, translate, scale);
- } else {
- L.DomUtil.setPosition(level.el, translate);
- }
- },
-
- _resetGrid: function () {
- var map = this._map,
- crs = map.options.crs,
- tileSize = this._tileSize = this.getTileSize(),
- tileZoom = this._tileZoom;
-
- var bounds = this._map.getPixelWorldBounds(this._tileZoom);
- if (bounds) {
- this._globalTileRange = this._pxBoundsToTileRange(bounds);
- }
-
- this._wrapX = crs.wrapLng && !this.options.noWrap && [
- Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
- Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
- ];
- this._wrapY = crs.wrapLat && !this.options.noWrap && [
- Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
- Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
- ];
- },
-
- _onMoveEnd: function () {
- if (!this._map || this._map._animatingZoom) { return; }
-
- this._update();
- },
-
- _getTiledPixelBounds: function (center) {
- var map = this._map,
- mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
- scale = map.getZoomScale(mapZoom, this._tileZoom),
- pixelCenter = map.project(center, this._tileZoom).floor(),
- halfSize = map.getSize().divideBy(scale * 2);
-
- return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
- },
-
- // Private method to load tiles in the grid's active zoom level according to map bounds
- _update: function (center) {
- var map = this._map;
- if (!map) { return; }
- var zoom = map.getZoom();
-
- if (center === undefined) { center = map.getCenter(); }
- if (this._tileZoom === undefined) { return; } // if out of minzoom/maxzoom
-
- var pixelBounds = this._getTiledPixelBounds(center),
- tileRange = this._pxBoundsToTileRange(pixelBounds),
- tileCenter = tileRange.getCenter(),
- queue = [],
- margin = this.options.keepBuffer,
- noPruneRange = new L.Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
- tileRange.getTopRight().add([margin, -margin]));
-
- for (var key in this._tiles) {
- var c = this._tiles[key].coords;
- if (c.z !== this._tileZoom || !noPruneRange.contains(L.point(c.x, c.y))) {
- this._tiles[key].current = false;
- }
- }
-
- // _update just loads more tiles. If the tile zoom level differs too much
- // from the map's, let _setView reset levels and prune old tiles.
- if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }
-
- // create a queue of coordinates to load tiles from
- for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
- for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
- var coords = new L.Point(i, j);
- coords.z = this._tileZoom;
-
- if (!this._isValidTile(coords)) { continue; }
-
- var tile = this._tiles[this._tileCoordsToKey(coords)];
- if (tile) {
- tile.current = true;
- } else {
- queue.push(coords);
- }
- }
- }
-
- // sort tile queue to load tiles in order of their distance to center
- queue.sort(function (a, b) {
- return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
- });
-
- if (queue.length !== 0) {
- // if its the first batch of tiles to load
- if (!this._loading) {
- this._loading = true;
- // @event loading: Event
- // Fired when the grid layer starts loading tiles.
- this.fire('loading');
- }
-
- // create DOM fragment to append tiles in one batch
- var fragment = document.createDocumentFragment();
-
- for (i = 0; i < queue.length; i++) {
- this._addTile(queue[i], fragment);
- }
-
- this._level.el.appendChild(fragment);
- }
- },
-
- _isValidTile: function (coords) {
- var crs = this._map.options.crs;
-
- if (!crs.infinite) {
- // don't load tile if it's out of bounds and not wrapped
- var bounds = this._globalTileRange;
- if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
- (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
- }
-
- if (!this.options.bounds) { return true; }
-
- // don't load tile if it doesn't intersect the bounds in options
- var tileBounds = this._tileCoordsToBounds(coords);
- return L.latLngBounds(this.options.bounds).overlaps(tileBounds);
- },
-
- _keyToBounds: function (key) {
- return this._tileCoordsToBounds(this._keyToTileCoords(key));
- },
-
- // converts tile coordinates to its geographical bounds
- _tileCoordsToBounds: function (coords) {
-
- var map = this._map,
- tileSize = this.getTileSize(),
-
- nwPoint = coords.scaleBy(tileSize),
- sePoint = nwPoint.add(tileSize),
-
- nw = map.unproject(nwPoint, coords.z),
- se = map.unproject(sePoint, coords.z);
-
- if (!this.options.noWrap) {
- nw = map.wrapLatLng(nw);
- se = map.wrapLatLng(se);
- }
-
- return new L.LatLngBounds(nw, se);
- },
-
- // converts tile coordinates to key for the tile cache
- _tileCoordsToKey: function (coords) {
- return coords.x + ':' + coords.y + ':' + coords.z;
- },
-
- // converts tile cache key to coordinates
- _keyToTileCoords: function (key) {
- var k = key.split(':'),
- coords = new L.Point(+k[0], +k[1]);
- coords.z = +k[2];
- return coords;
- },
-
- _removeTile: function (key) {
- var tile = this._tiles[key];
- if (!tile) { return; }
-
- L.DomUtil.remove(tile.el);
-
- delete this._tiles[key];
-
- // @event tileunload: TileEvent
- // Fired when a tile is removed (e.g. when a tile goes off the screen).
- this.fire('tileunload', {
- tile: tile.el,
- coords: this._keyToTileCoords(key)
- });
- },
-
- _initTile: function (tile) {
- L.DomUtil.addClass(tile, 'leaflet-tile');
-
- var tileSize = this.getTileSize();
- tile.style.width = tileSize.x + 'px';
- tile.style.height = tileSize.y + 'px';
-
- tile.onselectstart = L.Util.falseFn;
- tile.onmousemove = L.Util.falseFn;
-
- // update opacity on tiles in IE7-8 because of filter inheritance problems
- if (L.Browser.ielt9 && this.options.opacity < 1) {
- L.DomUtil.setOpacity(tile, this.options.opacity);
- }
-
- // without this hack, tiles disappear after zoom on Chrome for Android
- // https://github.com/Leaflet/Leaflet/issues/2078
- if (L.Browser.android && !L.Browser.android23) {
- tile.style.WebkitBackfaceVisibility = 'hidden';
- }
- },
-
- _addTile: function (coords, container) {
- var tilePos = this._getTilePos(coords),
- key = this._tileCoordsToKey(coords);
-
- var tile = this.createTile(this._wrapCoords(coords), L.bind(this._tileReady, this, coords));
-
- this._initTile(tile);
-
- // if createTile is defined with a second argument ("done" callback),
- // we know that tile is async and will be ready later; otherwise
- if (this.createTile.length < 2) {
- // mark tile as ready, but delay one frame for opacity animation to happen
- L.Util.requestAnimFrame(L.bind(this._tileReady, this, coords, null, tile));
- }
-
- L.DomUtil.setPosition(tile, tilePos);
-
- // save tile in cache
- this._tiles[key] = {
- el: tile,
- coords: coords,
- current: true
- };
-
- container.appendChild(tile);
- // @event tileloadstart: TileEvent
- // Fired when a tile is requested and starts loading.
- this.fire('tileloadstart', {
- tile: tile,
- coords: coords
- });
- },
-
- _tileReady: function (coords, err, tile) {
- if (!this._map) { return; }
-
- if (err) {
- // @event tileerror: TileErrorEvent
- // Fired when there is an error loading a tile.
- this.fire('tileerror', {
- error: err,
- tile: tile,
- coords: coords
- });
- }
-
- var key = this._tileCoordsToKey(coords);
-
- tile = this._tiles[key];
- if (!tile) { return; }
-
- tile.loaded = +new Date();
- if (this._map._fadeAnimated) {
- L.DomUtil.setOpacity(tile.el, 0);
- L.Util.cancelAnimFrame(this._fadeFrame);
- this._fadeFrame = L.Util.requestAnimFrame(this._updateOpacity, this);
- } else {
- tile.active = true;
- this._pruneTiles();
- }
-
- L.DomUtil.addClass(tile.el, 'leaflet-tile-loaded');
-
- // @event tileload: TileEvent
- // Fired when a tile loads.
- this.fire('tileload', {
- tile: tile.el,
- coords: coords
- });
-
- if (this._noTilesToLoad()) {
- this._loading = false;
- // @event load: Event
- // Fired when the grid layer loaded all visible tiles.
- this.fire('load');
-
- if (L.Browser.ielt9 || !this._map._fadeAnimated) {
- L.Util.requestAnimFrame(this._pruneTiles, this);
- } else {
- // Wait a bit more than 0.2 secs (the duration of the tile fade-in)
- // to trigger a pruning.
- setTimeout(L.bind(this._pruneTiles, this), 250);
- }
- }
- },
-
- _getTilePos: function (coords) {
- return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
- },
-
- _wrapCoords: function (coords) {
- var newCoords = new L.Point(
- this._wrapX ? L.Util.wrapNum(coords.x, this._wrapX) : coords.x,
- this._wrapY ? L.Util.wrapNum(coords.y, this._wrapY) : coords.y);
- newCoords.z = coords.z;
- return newCoords;
- },
-
- _pxBoundsToTileRange: function (bounds) {
- var tileSize = this.getTileSize();
- return new L.Bounds(
- bounds.min.unscaleBy(tileSize).floor(),
- bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));
- },
-
- _noTilesToLoad: function () {
- for (var key in this._tiles) {
- if (!this._tiles[key].loaded) { return false; }
- }
- return true;
- }
-});
-
-// @factory L.gridLayer(options?: GridLayer options)
-// Creates a new instance of GridLayer with the supplied options.
-L.gridLayer = function (options) {
- return new L.GridLayer(options);
-};
-
-
-
-/*
- * @class TileLayer
- * @inherits GridLayer
- * @aka L.TileLayer
- * Used to load and display tile layers on the map. Extends `GridLayer`.
- *
- * @example
- *
- * ```js
- * L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);
- * ```
- *
- * @section URL template
- * @example
- *
- * A string of the following form:
- *
- * ```
- * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
- * ```
- *
- * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add @2x to the URL to load retina tiles.
- *
- * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
- *
- * ```
- * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
- * ```
- */
-
-
-L.TileLayer = L.GridLayer.extend({
-
- // @section
- // @aka TileLayer options
- options: {
- // @option minZoom: Number = 0
- // Minimum zoom number.
- minZoom: 0,
-
- // @option maxZoom: Number = 18
- // Maximum zoom number.
- maxZoom: 18,
-
- // @option maxNativeZoom: Number = null
- // Maximum zoom number the tile source has available. If it is specified,
- // the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
- // from `maxNativeZoom` level and auto-scaled.
- maxNativeZoom: null,
-
- // @option subdomains: String|String[] = 'abc'
- // Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.
- subdomains: 'abc',
-
- // @option errorTileUrl: String = ''
- // URL to the tile image to show in place of the tile that failed to load.
- errorTileUrl: '',
-
- // @option zoomOffset: Number = 0
- // The zoom number used in tile URLs will be offset with this value.
- zoomOffset: 0,
-
- // @option tms: Boolean = false
- // If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
- tms: false,
-
- // @option zoomReverse: Boolean = false
- // If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
- zoomReverse: false,
-
- // @option detectRetina: Boolean = false
- // If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.
- detectRetina: false,
-
- // @option crossOrigin: Boolean = false
- // If true, all tiles will have their crossOrigin attribute set to ''. This is needed if you want to access tile pixel data.
- crossOrigin: false
- },
-
- initialize: function (url, options) {
-
- this._url = url;
-
- options = L.setOptions(this, options);
-
- // detecting retina displays, adjusting tileSize and zoom levels
- if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) {
-
- options.tileSize = Math.floor(options.tileSize / 2);
-
- if (!options.zoomReverse) {
- options.zoomOffset++;
- options.maxZoom--;
- } else {
- options.zoomOffset--;
- options.minZoom++;
- }
-
- options.minZoom = Math.max(0, options.minZoom);
- }
-
- if (typeof options.subdomains === 'string') {
- options.subdomains = options.subdomains.split('');
- }
-
- // for https://github.com/Leaflet/Leaflet/issues/137
- if (!L.Browser.android) {
- this.on('tileunload', this._onTileRemove);
- }
- },
-
- // @method setUrl(url: String, noRedraw?: Boolean): this
- // Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
- setUrl: function (url, noRedraw) {
- this._url = url;
-
- if (!noRedraw) {
- this.redraw();
- }
- return this;
- },
-
- // @method createTile(coords: Object, done?: Function): HTMLElement
- // Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
- // to return an `<img>` HTML element with the appropiate image URL given `coords`. The `done`
- // callback is called when the tile has been loaded.
- createTile: function (coords, done) {
- var tile = document.createElement('img');
-
- L.DomEvent.on(tile, 'load', L.bind(this._tileOnLoad, this, done, tile));
- L.DomEvent.on(tile, 'error', L.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 = '';
-
- tile.src = this.getTileUrl(coords);
-
- return tile;
- },
-
- // @section Extension methods
- // @uninheritable
- // Layers extending `TileLayer` might reimplement the following method.
- // @method getTileUrl(coords: Object): String
- // Called only internally, returns the URL for a tile given its coordinates.
- // Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
- getTileUrl: function (coords) {
- var data = {
- r: L.Browser.retina ? '@2x' : '',
- s: this._getSubdomain(coords),
- x: coords.x,
- y: coords.y,
- z: this._getZoomForUrl()
- };
- if (this._map && !this._map.options.crs.infinite) {
- var invertedY = this._globalTileRange.max.y - coords.y;
- if (this.options.tms) {
- data['y'] = invertedY;
- }
- data['-y'] = invertedY;
- }
-
- return L.Util.template(this._url, L.extend(data, this.options));
- },
-
- _tileOnLoad: function (done, tile) {
- // For https://github.com/Leaflet/Leaflet/issues/3332
- if (L.Browser.ielt9) {
- setTimeout(L.bind(done, this, null, tile), 0);
- } else {
- done(null, tile);
- }
- },
-
- _tileOnError: function (done, tile, e) {
- var errorUrl = this.options.errorTileUrl;
- if (errorUrl) {
- tile.src = errorUrl;
- }
- done(e, tile);
- },
-
- getTileSize: function () {
- var map = this._map,
- tileSize = L.GridLayer.prototype.getTileSize.call(this),
- zoom = this._tileZoom + this.options.zoomOffset,
- zoomN = this.options.maxNativeZoom;
-
- // increase tile size when overscaling
- return zoomN !== null && zoom > zoomN ?
- tileSize.divideBy(map.getZoomScale(zoomN, zoom)).round() :
- tileSize;
- },
-
- _onTileRemove: function (e) {
- e.tile.onload = null;
- },
-
- _getZoomForUrl: function () {
-
- var options = this.options,
- zoom = this._tileZoom;
-
- if (options.zoomReverse) {
- zoom = options.maxZoom - zoom;
- }
-
- zoom += options.zoomOffset;
-
- return options.maxNativeZoom !== null ? Math.min(zoom, options.maxNativeZoom) : zoom;
- },
-
- _getSubdomain: function (tilePoint) {
- var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
- return this.options.subdomains[index];
- },
-
- // stops loading all tiles in the background layer
- _abortLoading: function () {
- var i, tile;
- for (i in this._tiles) {
- if (this._tiles[i].coords.z !== this._tileZoom) {
- tile = this._tiles[i].el;
-
- tile.onload = L.Util.falseFn;
- tile.onerror = L.Util.falseFn;
-
- if (!tile.complete) {
- tile.src = L.Util.emptyImageUrl;
- L.DomUtil.remove(tile);
- }
- }
- }
- }
-});
-
-
-// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
-// Instantiates a tile layer object given a `URL template` and optionally an options object.
-
-L.tileLayer = function (url, options) {
- return new L.TileLayer(url, options);
-};
-
-
-
-/*
- * @class TileLayer.WMS
- * @inherits TileLayer
- * @aka L.TileLayer.WMS
- * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.
- *
- * @example
- *
- * ```js
- * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
- * layers: 'nexrad-n0r-900913',
- * format: 'image/png',
- * transparent: true,
- * attribution: "Weather data © 2012 IEM Nexrad"
- * });
- * ```
- */
-
-L.TileLayer.WMS = L.TileLayer.extend({
-
- // @section
- // @aka TileLayer.WMS options
- // If any custom options not documented here are used, they will be sent to the
- // WMS server as extra parameters in each request URL. This can be useful for
- // [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
- defaultWmsParams: {
- service: 'WMS',
- request: 'GetMap',
-
- // @option layers: String = ''
- // **(required)** Comma-separated list of WMS layers to show.
- layers: '',
-
- // @option styles: String = ''
- // Comma-separated list of WMS styles.
- styles: '',
-
- // @option format: String = 'image/jpeg'
- // WMS image format (use `'image/png'` for layers with transparency).
- format: 'image/jpeg',
-
- // @option transparent: Boolean = false
- // If `true`, the WMS service will return images with transparency.
- transparent: false,
-
- // @option version: String = '1.1.1'
- // Version of the WMS service to use
- version: '1.1.1'
- },
-
- options: {
- // @option crs: CRS = null
- // Coordinate Reference System to use for the WMS requests, defaults to
- // map CRS. Don't change this if you're not sure what it means.
- crs: null,
-
- // @option uppercase: Boolean = false
- // If `true`, WMS request parameter keys will be uppercase.
- uppercase: false
- },
-
- initialize: function (url, options) {
-
- this._url = url;
-
- var wmsParams = L.extend({}, this.defaultWmsParams);
-
- // all keys that are not TileLayer options go to WMS params
- for (var i in options) {
- if (!(i in this.options)) {
- wmsParams[i] = options[i];
- }
- }
-
- options = L.setOptions(this, options);
-
- wmsParams.width = wmsParams.height = options.tileSize * (options.detectRetina && L.Browser.retina ? 2 : 1);
-
- this.wmsParams = wmsParams;
- },
-
- onAdd: function (map) {
-
- this._crs = this.options.crs || map.options.crs;
- this._wmsVersion = parseFloat(this.wmsParams.version);
-
- var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
- this.wmsParams[projectionKey] = this._crs.code;
-
- L.TileLayer.prototype.onAdd.call(this, map);
- },
-
- getTileUrl: function (coords) {
-
- var tileBounds = this._tileCoordsToBounds(coords),
- nw = this._crs.project(tileBounds.getNorthWest()),
- se = this._crs.project(tileBounds.getSouthEast()),
-
- bbox = (this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?
- [se.y, nw.x, nw.y, se.x] :
- [nw.x, se.y, se.x, nw.y]).join(','),
-
- url = L.TileLayer.prototype.getTileUrl.call(this, coords);
-
- return url +
- L.Util.getParamString(this.wmsParams, url, this.options.uppercase) +
- (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
- },
-
- // @method setParams(params: Object, noRedraw?: Boolean): this
- // Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
- setParams: function (params, noRedraw) {
-
- L.extend(this.wmsParams, params);
-
- if (!noRedraw) {
- this.redraw();
- }
-
- return this;
- }
-});
-
-
-// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)
-// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.
-L.tileLayer.wms = function (url, options) {
- return new L.TileLayer.WMS(url, options);
-};
-
-
-
-/*
- * @class ImageOverlay
- * @aka L.ImageOverlay
- * @inherits Interactive layer
- *
- * Used to load and display a single image over specific bounds of the map. Extends `Layer`.
- *
- * @example
- *
- * ```js
- * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
- * imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
- * L.imageOverlay(imageUrl, imageBounds).addTo(map);
- * ```
- */
-
-L.ImageOverlay = L.Layer.extend({
-
- // @section
- // @aka ImageOverlay options
- options: {
- // @option opacity: Number = 1.0
- // The opacity of the image overlay.
- opacity: 1,
-
- // @option alt: String = ''
- // Text for the `alt` attribute of the image (useful for accessibility).
- alt: '',
-
- // @option interactive: Boolean = false
- // If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
- interactive: false,
-
- // @option attribution: String = null
- // An optional string containing HTML to be shown on the `Attribution control`
- attribution: null,
-
- // @option crossOrigin: Boolean = false
- // If true, the image will have its crossOrigin attribute set to ''. This is needed if you want to access image pixel data.
- crossOrigin: false
- },
-
- initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
- this._url = url;
- this._bounds = L.latLngBounds(bounds);
-
- L.setOptions(this, options);
- },
-
- onAdd: function () {
- if (!this._image) {
- this._initImage();
-
- if (this.options.opacity < 1) {
- this._updateOpacity();
- }
- }
-
- if (this.options.interactive) {
- L.DomUtil.addClass(this._image, 'leaflet-interactive');
- this.addInteractiveTarget(this._image);
- }
-
- this.getPane().appendChild(this._image);
- this._reset();
- },
-
- onRemove: function () {
- L.DomUtil.remove(this._image);
- if (this.options.interactive) {
- this.removeInteractiveTarget(this._image);
- }
- },
-
- // @method setOpacity(opacity: Number): this
- // Sets the opacity of the overlay.
- setOpacity: function (opacity) {
- this.options.opacity = opacity;
-
- if (this._image) {
- this._updateOpacity();
- }
- return this;
- },
-
- setStyle: function (styleOpts) {
- if (styleOpts.opacity) {
- this.setOpacity(styleOpts.opacity);
- }
- return this;
- },
-
- // @method bringToFront(): this
- // Brings the layer to the top of all overlays.
- bringToFront: function () {
- if (this._map) {
- L.DomUtil.toFront(this._image);
- }
- return this;
- },
-
- // @method bringToBack(): this
- // Brings the layer to the bottom of all overlays.
- bringToBack: function () {
- if (this._map) {
- L.DomUtil.toBack(this._image);
- }
- return this;
- },
-
- // @method setUrl(url: String): this
- // Changes the URL of the image.
- setUrl: function (url) {
- this._url = url;
-
- if (this._image) {
- this._image.src = url;
- }
- return this;
- },
-
- setBounds: function (bounds) {
- this._bounds = bounds;
-
- if (this._map) {
- this._reset();
- }
- return this;
- },
-
- getAttribution: function () {
- return this.options.attribution;
- },
-
- getEvents: function () {
- var events = {
- zoom: this._reset,
- viewreset: this._reset
- };
-
- if (this._zoomAnimated) {
- events.zoomanim = this._animateZoom;
- }
-
- return events;
- },
-
- getBounds: function () {
- return this._bounds;
- },
-
- getElement: function () {
- return this._image;
- },
-
- _initImage: function () {
- var img = this._image = L.DomUtil.create('img',
- 'leaflet-image-layer ' + (this._zoomAnimated ? 'leaflet-zoom-animated' : ''));
-
- img.onselectstart = L.Util.falseFn;
- img.onmousemove = L.Util.falseFn;
-
- img.onload = L.bind(this.fire, this, 'load');
-
- if (this.options.crossOrigin) {
- img.crossOrigin = '';
- }
-
- img.src = this._url;
- img.alt = this.options.alt;
- },
-
- _animateZoom: function (e) {
- var scale = this._map.getZoomScale(e.zoom),
- offset = this._map._latLngToNewLayerPoint(this._bounds.getNorthWest(), e.zoom, e.center);
-
- L.DomUtil.setTransform(this._image, offset, scale);
- },
-
- _reset: function () {
- var image = this._image,
- bounds = new L.Bounds(
- this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
- this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
- size = bounds.getSize();
-
- L.DomUtil.setPosition(image, bounds.min);
-
- image.style.width = size.x + 'px';
- image.style.height = size.y + 'px';
- },
-
- _updateOpacity: function () {
- L.DomUtil.setOpacity(this._image, this.options.opacity);
- }
-});
-
-// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
-// Instantiates an image overlay object given the URL of the image and the
-// geographical bounds it is tied to.
-L.imageOverlay = function (url, bounds, options) {
- return new L.ImageOverlay(url, bounds, options);
-};