292 lines
8.7 KiB
JavaScript
292 lines
8.7 KiB
JavaScript
define(function () {
|
|
/**
|
|
* https://github.com/Mappy/Leaflet-active-area
|
|
* Apache 2.0 license https://www.apache.org/licenses/LICENSE-2.0
|
|
*/
|
|
|
|
var previousMethods = {
|
|
getCenter: L.Map.prototype.getCenter,
|
|
setView: L.Map.prototype.setView,
|
|
setZoomAround: L.Map.prototype.setZoomAround,
|
|
getBoundsZoom: L.Map.prototype.getBoundsZoom,
|
|
RendererUpdate: L.Renderer.prototype._update
|
|
};
|
|
|
|
L.Map.include({
|
|
getBounds: function () {
|
|
if (this._viewport) {
|
|
return this.getViewportLatLngBounds();
|
|
}
|
|
var bounds = this.getPixelBounds();
|
|
var sw = this.unproject(bounds.getBottomLeft());
|
|
var ne = this.unproject(bounds.getTopRight());
|
|
|
|
return new L.LatLngBounds(sw, ne);
|
|
},
|
|
|
|
getViewport: function () {
|
|
return this._viewport;
|
|
},
|
|
|
|
getViewportBounds: function () {
|
|
var vp = this._viewport;
|
|
var topleft = L.point(vp.offsetLeft, vp.offsetTop);
|
|
var vpsize = L.point(vp.clientWidth, vp.clientHeight);
|
|
|
|
if (vpsize.x === 0 || vpsize.y === 0) {
|
|
// Our own viewport has no good size - so we fallback to the container size:
|
|
vp = this.getContainer();
|
|
if (vp) {
|
|
topleft = L.point(0, 0);
|
|
vpsize = L.point(vp.clientWidth, vp.clientHeight);
|
|
}
|
|
}
|
|
|
|
return L.bounds(topleft, topleft.add(vpsize));
|
|
},
|
|
|
|
getViewportLatLngBounds: function () {
|
|
var bounds = this.getViewportBounds();
|
|
return L.latLngBounds(this.containerPointToLatLng(bounds.min), this.containerPointToLatLng(bounds.max));
|
|
},
|
|
|
|
getOffset: function () {
|
|
var mCenter = this.getSize().divideBy(2);
|
|
var vCenter = this.getViewportBounds().getCenter();
|
|
|
|
return mCenter.subtract(vCenter);
|
|
},
|
|
|
|
getCenter: function (withoutViewport) {
|
|
var center = previousMethods.getCenter.call(this);
|
|
|
|
if (this.getViewport() && !withoutViewport) {
|
|
var zoom = this.getZoom();
|
|
var point = this.project(center, zoom);
|
|
point = point.subtract(this.getOffset());
|
|
|
|
center = this.unproject(point, zoom);
|
|
}
|
|
|
|
return center;
|
|
},
|
|
|
|
setView: function (center, zoom, options) {
|
|
center = L.latLng(center);
|
|
zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
|
|
|
|
if (this.getViewport()) {
|
|
var point = this.project(center, this._limitZoom(zoom));
|
|
point = point.add(this.getOffset());
|
|
center = this.unproject(point, this._limitZoom(zoom));
|
|
}
|
|
|
|
return previousMethods.setView.call(this, center, zoom, options);
|
|
},
|
|
|
|
setZoomAround: function (latlng, zoom, options) {
|
|
var vp = this.getViewport();
|
|
|
|
if (vp) {
|
|
var scale = this.getZoomScale(zoom);
|
|
var viewHalf = this.getViewportBounds().getCenter();
|
|
var containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng);
|
|
|
|
var centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale);
|
|
var newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
|
|
|
|
return this.setView(newCenter, zoom, { zoom: options });
|
|
}
|
|
return previousMethods.setZoomAround.call(this, latlng, zoom, options);
|
|
},
|
|
|
|
getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
|
|
bounds = L.latLngBounds(bounds);
|
|
padding = L.point(padding || [0, 0]);
|
|
|
|
var zoom = this.getZoom() || 0;
|
|
var min = this.getMinZoom();
|
|
var max = this.getMaxZoom();
|
|
var nw = bounds.getNorthWest();
|
|
var se = bounds.getSouthEast();
|
|
var vp = this.getViewport();
|
|
var size = (vp ? L.point(vp.clientWidth, vp.clientHeight) : this.getSize()).subtract(padding);
|
|
var boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom));
|
|
var snap = L.Browser.any3d ? this.options.zoomSnap : 1;
|
|
|
|
var scale = Math.min(size.x / boundsSize.x, size.y / boundsSize.y);
|
|
|
|
zoom = this.getScaleZoom(scale, zoom);
|
|
|
|
if (snap) {
|
|
zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
|
|
zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
|
|
}
|
|
|
|
return Math.max(min, Math.min(max, zoom));
|
|
}
|
|
});
|
|
|
|
L.Map.include({
|
|
setActiveArea: function (css, keepCenter, animate) {
|
|
var center;
|
|
if (keepCenter && this._zoom) {
|
|
// save center if map is already initialized
|
|
// and keepCenter is passed
|
|
center = this.getCenter();
|
|
}
|
|
|
|
if (!this._viewport) {
|
|
// Make viewport if not already made
|
|
var container = this.getContainer();
|
|
this._viewport = L.DomUtil.create('div', '');
|
|
container.insertBefore(this._viewport, container.firstChild);
|
|
}
|
|
|
|
if (typeof css === 'string') {
|
|
this._viewport.className = css;
|
|
} else {
|
|
L.extend(this._viewport.style, css);
|
|
}
|
|
|
|
if (center) {
|
|
this.setView(center, this.getZoom(), { animate: !!animate });
|
|
}
|
|
return this;
|
|
}
|
|
});
|
|
|
|
L.Renderer.include({
|
|
_onZoom: function () {
|
|
this._updateTransform(this._map.getCenter(true), this._map.getZoom());
|
|
},
|
|
|
|
_update: function () {
|
|
previousMethods.RendererUpdate.call(this);
|
|
this._center = this._map.getCenter(true);
|
|
}
|
|
});
|
|
|
|
L.GridLayer.include({
|
|
_updateLevels: function () {
|
|
var zoom = this._tileZoom;
|
|
var maxZoom = this.options.maxZoom;
|
|
|
|
if (zoom === undefined) {
|
|
return undefined;
|
|
}
|
|
|
|
for (var z in this._levels) {
|
|
if (this._levels[z].el.children.length || z === zoom) {
|
|
this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);
|
|
} else {
|
|
L.DomUtil.remove(this._levels[z].el);
|
|
this._removeTilesAtZoom(z);
|
|
delete this._levels[z];
|
|
}
|
|
}
|
|
|
|
var level = this._levels[zoom];
|
|
var map = this._map;
|
|
|
|
if (!level) {
|
|
level = this._levels[zoom] = {};
|
|
|
|
level.el = L.DomUtil.create('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);
|
|
level.el.style.zIndex = maxZoom;
|
|
|
|
level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();
|
|
level.zoom = zoom;
|
|
|
|
this._setZoomTransform(level, map.getCenter(true), map.getZoom());
|
|
|
|
// force the browser to consider the newly added element for transition
|
|
L.Util.falseFn(level.el.offsetWidth);
|
|
}
|
|
|
|
this._level = level;
|
|
|
|
return level;
|
|
},
|
|
|
|
_resetView: function (e) {
|
|
var animating = e && (e.pinch || e.flyTo);
|
|
this._setView(this._map.getCenter(true), this._map.getZoom(), animating, animating);
|
|
},
|
|
|
|
_update: function (center) {
|
|
var map = this._map;
|
|
if (!map) {
|
|
return;
|
|
}
|
|
var zoom = map.getZoom();
|
|
|
|
if (center === undefined) {
|
|
center = map.getCenter(this);
|
|
}
|
|
if (this._tileZoom === undefined) {
|
|
return;
|
|
} // if out of minzoom/maxzoom
|
|
|
|
var pixelBounds = this._getTiledPixelBounds(center);
|
|
var tileRange = this._pxBoundsToTileRange(pixelBounds);
|
|
var tileCenter = tileRange.getCenter();
|
|
var queue = [];
|
|
|
|
for (var key in this._tiles) {
|
|
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);
|
|
}
|
|
}
|
|
});
|
|
});
|