| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- L.MapboxGL = L.Layer.extend({
- options: {
- updateInterval: 32
- },
-
- initialize: function (options) {
- L.setOptions(this, options);
-
- if (options.accessToken) {
- mapboxgl.accessToken = options.accessToken;
- } else {
- throw new Error('You should provide a Mapbox GL access token as a token option.');
- }
-
- /**
- * Create a version of `fn` that only fires once every `time` millseconds.
- *
- * @param {Function} fn the function to be throttled
- * @param {number} time millseconds required between function calls
- * @param {*} context the value of `this` with which the function is called
- * @returns {Function} debounced function
- * @private
- */
- var throttle = function (fn, time, context) {
- var lock, args, wrapperFn, later;
-
- later = function () {
- // reset lock and call if queued
- lock = false;
- if (args) {
- wrapperFn.apply(context, args);
- args = false;
- }
- };
-
- wrapperFn = function () {
- if (lock) {
- // called too soon, queue to call later
- args = arguments;
-
- } else {
- // call and lock until later
- fn.apply(context, arguments);
- setTimeout(later, time);
- lock = true;
- }
- };
-
- return wrapperFn;
- };
-
- // setup throttling the update event when panning
- this._throttledUpdate = throttle(L.Util.bind(this._update, this), this.options.updateInterval);
- },
-
- onAdd: function (map) {
- if (!this._glContainer) {
- this._initContainer();
- }
-
- map._panes.tilePane.appendChild(this._glContainer);
-
- this._initGL();
-
- this._offset = this._map.containerPointToLayerPoint([0, 0]);
-
- // work around https://github.com/mapbox/mapbox-gl-leaflet/issues/47
- if (map.options.zoomAnimation) {
- L.DomEvent.on(map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
- }
- },
-
- onRemove: function (map) {
- if (this._map.options.zoomAnimation) {
- L.DomEvent.off(this._map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
- }
-
- map.getPanes().tilePane.removeChild(this._glContainer);
- this._glMap.remove();
- this._glMap = null;
- },
-
- getEvents: function () {
- return {
- move: this._throttledUpdate, // sensibly throttle updating while panning
- zoomanim: this._animateZoom, // applys the zoom animation to the <canvas>
- zoom: this._pinchZoom, // animate every zoom event for smoother pinch-zooming
- zoomstart: this._zoomStart, // flag starting a zoom to disable panning
- zoomend: this._zoomEnd
- };
- },
-
- _initContainer: function () {
- var container = this._glContainer = L.DomUtil.create('div', 'leaflet-gl-layer');
-
- var size = this._map.getSize();
- container.style.width = size.x + 'px';
- container.style.height = size.y + 'px';
- },
-
- _initGL: function () {
- var center = this._map.getCenter();
-
- var options = L.extend({}, this.options, {
- container: this._glContainer,
- interactive: false,
- center: [center.lng, center.lat],
- zoom: this._map.getZoom() - 1,
- attributionControl: false
- });
-
- this._glMap = new mapboxgl.Map(options);
-
- // allow GL base map to pan beyond min/max latitudes
- this._glMap.transform.latRange = null;
-
- // treat child <canvas> element like L.ImageOverlay
- L.DomUtil.addClass(this._glMap._canvas, 'leaflet-image-layer');
- L.DomUtil.addClass(this._glMap._canvas, 'leaflet-zoom-animated');
- },
-
- _update: function (e) {
- // update the offset so we can correct for it later when we zoom
- this._offset = this._map.containerPointToLayerPoint([0, 0]);
-
- if (this._zooming) {
- return;
- }
-
- var size = this._map.getSize(),
- container = this._glContainer,
- gl = this._glMap,
- topLeft = this._map.containerPointToLayerPoint([0, 0]);
-
- L.DomUtil.setPosition(container, topLeft);
-
- var center = this._map.getCenter();
-
- // gl.setView([center.lat, center.lng], this._map.getZoom() - 1, 0);
- // calling setView directly causes sync issues because it uses requestAnimFrame
-
- var tr = gl.transform;
- tr.center = mapboxgl.LngLat.convert([center.lng, center.lat]);
- tr.zoom = this._map.getZoom() - 1;
-
- if (gl.transform.width !== size.x || gl.transform.height !== size.y) {
- container.style.width = size.x + 'px';
- container.style.height = size.y + 'px';
- if (gl._resize !== null && gl._resize !== undefined){
- gl._resize();
- } else {
- gl.resize();
- }
- } else {
- gl._update();
- }
- },
-
- // update the map constantly during a pinch zoom
- _pinchZoom: function (e) {
- this._glMap.jumpTo({
- zoom: this._map.getZoom() - 1,
- center: this._map.getCenter()
- });
- },
-
- // borrowed from L.ImageOverlay https://github.com/Leaflet/Leaflet/blob/master/src/layer/ImageOverlay.js#L139-L144
- _animateZoom: function (e) {
- var scale = this._map.getZoomScale(e.zoom),
- offset = this._map._latLngToNewLayerPoint(this._map.getBounds().getNorthWest(), e.zoom, e.center);
-
- L.DomUtil.setTransform(this._glMap._canvas, offset.subtract(this._offset), scale);
- },
-
- _zoomStart: function (e) {
- this._zooming = true;
- },
-
- _zoomEnd: function () {
- var scale = this._map.getZoomScale(this._map.getZoom()),
- offset = this._map._latLngToNewLayerPoint(this._map.getBounds().getNorthWest(), this._map.getZoom(), this._map.getCenter());
-
- L.DomUtil.setTransform(this._glMap._canvas, offset.subtract(this._offset), scale);
-
- this._zooming = false;
- },
-
- _transitionEnd: function (e) {
- L.Util.requestAnimFrame(function () {
- var zoom = this._map.getZoom(),
- center = this._map.getCenter(),
- offset = this._map.latLngToContainerPoint(this._map.getBounds().getNorthWest());
-
- // reset the scale and offset
- L.DomUtil.setTransform(this._glMap._canvas, offset, 1);
-
- // enable panning once the gl map is ready again
- this._glMap.once('moveend', L.Util.bind(function () {
- this._zoomEnd();
- }, this));
-
- // update the map position
- this._glMap.jumpTo({
- center: center,
- zoom: zoom - 1
- });
- }, this);
- }
- });
-
- L.mapboxGL = function (options) {
- return new L.MapboxGL(options);
- };
|