leaflet
Version:
JavaScript library for mobile-friendly interactive maps
161 lines (124 loc) • 3.85 kB
JavaScript
/*
* L.TileLayer is used for standard xyz-numbered tile layers.
*/
L.TileLayer = L.GridLayer.extend({
options: {
maxZoom: 18,
subdomains: 'abc',
errorTileUrl: '',
zoomOffset: 0,
maxNativeZoom: null, // Number
tms: false,
zoomReverse: false,
detectRetina: false,
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);
options.zoomOffset++;
options.minZoom = Math.max(0, options.minZoom);
options.maxZoom--;
}
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);
}
},
setUrl: function (url, noRedraw) {
this._url = url;
if (!noRedraw) {
this.redraw();
}
return this;
},
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;
},
getTileUrl: function (coords) {
return L.Util.template(this._url, L.extend({
r: this.options.detectRetina && L.Browser.retina && this.options.maxZoom > 0 ? '@2x' : '',
s: this._getSubdomain(coords),
x: coords.x,
y: this.options.tms ? this._globalTileRange.max.y - coords.y : coords.y,
z: this._getZoomForUrl()
}, 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);
}
}
}
}
});
L.tileLayer = function (url, options) {
return new L.TileLayer(url, options);
};