/* * from - https://gist.github.com/fnicollet/5764080 * Modified by Ryan Whitley - Jan 30, 2013 * L.DynamicSingleTile uses L.ImageOverlay to display a single-tile layer from node-mapnik. * url parameter must accept width, height and bbox. */ L.DynamicSingleTile = L.ImageOverlay.extend({ initialize: function (url, bounds, options) { // (String, Object) this._url = url; if (url.indexOf("{s}") != -1) { this.options.subdomains = options.subdomains = '1234'; } this._isSwap = false; this._imageSwap = null; L.setOptions(this, options); }, onAdd: function (map) { this._map = map; // this._bounds = map.getBounds(); // pan map.on('moveend', this._onViewReset, this); // hide on zoom if (map.options.zoomAnimation && L.Browser.any3d) { map.on('zoomanim', this._onZoomAnim, this); } // request a first image on add this._onViewReset(); // override //L.ImageOverlay.prototype.onAdd.call(this, map); }, onRemove: function (map) { // super() L.ImageOverlay.prototype.onRemove.call(this, map); // add if (this._imageSwap) { map.getPanes().overlayPane.removeChild(this._imageSwap); } map.off('moveend', this._onViewReset, this); map.off('zoomanim', this._onZoomAnim, this); }, _onViewReset: function () { this._futureBounds = this._map.getBounds(); var size = this._map.getSize(); var b = this._map.getBounds(); var metersBounds = { southWest: L.CRS.EPSG3857.project(b.getSouthWest()), northEast: L.CRS.EPSG3857.project(b.getNorthEast()) }; var imageSrc = this._url + L.Util.getParamString(this.Params, this._url) + "&width=" + size.x + "&height=" + size.y + "&bbox=" + metersBounds.southWest.x + "," + metersBounds.northEast.y + "," + metersBounds.northEast.x + "," + metersBounds.southWest.y; this.swapImage(imageSrc, this._futureBounds); }, _reset: function () { var el = this._isSwap ? this._imageSwap : this._image; if (!el) { return; } /** @type {L.LatLng} */ var nwLatLng = this._bounds.getNorthWest(); var seLatLng = this._bounds.getSouthEast(); var topLeft = this._map.latLngToLayerPoint(nwLatLng); var bottomRight = this._map.latLngToLayerPoint(seLatLng); var size = bottomRight.subtract(topLeft); L.DomUtil.setPosition(el, topLeft); el.width = size.x; el.height = size.y; }, _onZoomAnim: function () { if (this._imageSwap) { this._imageSwap.style.visibility = 'hidden'; } if (this._image) { this._image.style.visibility = 'hidden'; } }, _onSwapImageLoad: function () { if (this._isSwap) { this._imageSwap.style.visibility = 'hidden'; this._image.style.visibility = ''; } else { this._imageSwap.style.visibility = ''; this._image.style.visibility = 'hidden'; } this._isSwap = !this._isSwap; this._bounds = this._futureBounds; this._reset(); }, _updateOpacity : function (){ L.DomUtil.setOpacity(this._image, this.options.opacity); L.DomUtil.setOpacity(this._imageSwap, this.options.opacity); }, swapImage: function (src, bounds) { if (!this._imagesCreated) { this._image = this._createImageSwap(); this._imageSwap = this._createImageSwap(); this._imagesCreated = true; } if (this._isSwap) { this._image.src = src; } else { this._imageSwap.src = src; } this._updateOpacity(); // do not assign the bound here, this will be done after the next image this._futureBounds = bounds; // allows to re-position the image while waiting for the swap. // attention : the does not work while resizing, because of the wrong bound (size in pixel) this._reset(); }, _createImageSwap: function () { var el = L.DomUtil.create('img', 'leaflet-image-layer'); L.Util.extend(el, { galleryimg: 'no', onselectstart: L.Util.falseFn, onmousemove: L.Util.falseFn, onload: L.Util.bind(this._onSwapImageLoad, this) }); this._map._panes.overlayPane.appendChild(el); el.style.visibility = ''; return el; } }); L.dynamicSingleTile = function (url, bounds, options) { return new L.DynamicSingleTile(url, bounds, options); };