maplibre-gl-leaflet-with-canvas-dash-offset 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FUNDING.yml +2 -0
- package/.github/workflows/publish.yml +27 -0
- package/.github/workflows/test.yml +27 -0
- package/.travis.yml +6 -0
- package/API.md +43 -0
- package/CHANGELOG.md +145 -0
- package/CONTRIBUTING.md +8 -0
- package/LICENSE +15 -0
- package/README.md +99 -0
- package/debug/README.md +5 -0
- package/debug/maps-concurrent-resizing.html +362 -0
- package/debug/max-latitude-bug-reproduction.html +49 -0
- package/examples/basic.html +52 -0
- package/examples/cluster.html +52 -0
- package/examples/events.html +86 -0
- package/examples/overlay.html +47 -0
- package/leaflet-maplibre-gl.d.ts +20 -0
- package/leaflet-maplibre-gl.js +346 -0
- package/package.json +37 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
(function (root, factory) {
|
|
2
|
+
if (typeof define === 'function' && define.amd) {
|
|
3
|
+
// AMD
|
|
4
|
+
define(['leaflet-with-canvas-dash-offset', 'maplibre-gl'], factory);
|
|
5
|
+
} else if (typeof exports === 'object') {
|
|
6
|
+
// Node, CommonJS-like
|
|
7
|
+
module.exports = factory(require('leaflet-with-canvas-dash-offset'), require('maplibre-gl'));
|
|
8
|
+
} else {
|
|
9
|
+
// Browser globals (root is window)
|
|
10
|
+
root.returnExports = factory(root.L, root.maplibregl);
|
|
11
|
+
}
|
|
12
|
+
}(typeof globalThis !== 'undefined' ? globalThis : this || self, function (L, maplibregl) {
|
|
13
|
+
L.MaplibreGL = L.Layer.extend({
|
|
14
|
+
options: {
|
|
15
|
+
updateInterval: 32,
|
|
16
|
+
// How much to extend the overlay view (relative to map size)
|
|
17
|
+
// e.g. 0.1 would be 10% of map view in each direction
|
|
18
|
+
padding: 0.1,
|
|
19
|
+
// whether or not to register the mouse and keyboard
|
|
20
|
+
// events on the maplibre overlay
|
|
21
|
+
interactive: false,
|
|
22
|
+
// set the tilepane as the default pane to draw gl tiles
|
|
23
|
+
pane: 'tilePane'
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
initialize: function (options) {
|
|
27
|
+
L.setOptions(this, options);
|
|
28
|
+
|
|
29
|
+
// setup throttling the update event when panning
|
|
30
|
+
this._throttledUpdate = L.Util.throttle(this._update, this.options.updateInterval, this);
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
onAdd: function (map) {
|
|
34
|
+
if (!this._container) {
|
|
35
|
+
this._initContainer();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var paneName = this.getPaneName();
|
|
39
|
+
map.getPane(paneName).appendChild(this._container);
|
|
40
|
+
|
|
41
|
+
this._initGL();
|
|
42
|
+
|
|
43
|
+
this._offset = this._map.containerPointToLayerPoint([0, 0]);
|
|
44
|
+
|
|
45
|
+
// work around https://github.com/mapbox/mapbox-gl-leaflet/issues/47
|
|
46
|
+
if (map.options.zoomAnimation) {
|
|
47
|
+
L.DomEvent.on(map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
onRemove: function (map) {
|
|
52
|
+
if (this._map._proxy && this._map.options.zoomAnimation) {
|
|
53
|
+
L.DomEvent.off(this._map._proxy, L.DomUtil.TRANSITION_END, this._transitionEnd, this);
|
|
54
|
+
}
|
|
55
|
+
var paneName = this.getPaneName();
|
|
56
|
+
map.getPane(paneName).removeChild(this._container);
|
|
57
|
+
|
|
58
|
+
this._glMap.remove();
|
|
59
|
+
this._glMap = null;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
getEvents: function () {
|
|
63
|
+
return {
|
|
64
|
+
move: this._throttledUpdate, // sensibly throttle updating while panning
|
|
65
|
+
zoomanim: this._animateZoom, // applys the zoom animation to the <canvas>
|
|
66
|
+
zoom: this._pinchZoom, // animate every zoom event for smoother pinch-zooming
|
|
67
|
+
zoomstart: this._zoomStart, // flag starting a zoom to disable panning
|
|
68
|
+
zoomend: this._zoomEnd,
|
|
69
|
+
resize: this._resize
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// https://leafletjs.com/reference.html#layer-getattribution
|
|
74
|
+
getAttribution: function () {
|
|
75
|
+
// Return custom attribution if specified in options
|
|
76
|
+
if (this.options.attributionControl) {
|
|
77
|
+
return this.options.attributionControl.customAttribution;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Gather attributions from MapLibre styles
|
|
81
|
+
var map = this._glMap;
|
|
82
|
+
if (map && this.options.attributionControl !== false) {
|
|
83
|
+
var style = map.getStyle();
|
|
84
|
+
if (style && style.sources) {
|
|
85
|
+
return Object.keys(style.sources)
|
|
86
|
+
.map(function (sourceId) {
|
|
87
|
+
var source = map.getSource(sourceId);
|
|
88
|
+
return (source && typeof source.attribution === 'string') ? source.attribution.trim() : null;
|
|
89
|
+
})
|
|
90
|
+
.filter(Boolean) // Remove null/undefined values
|
|
91
|
+
.join(', ');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return '';
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
getMaplibreMap: function () {
|
|
99
|
+
return this._glMap;
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
getCanvas: function () {
|
|
103
|
+
return this._glMap.getCanvas();
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
getSize: function () {
|
|
107
|
+
return this._map.getSize().multiplyBy(1 + this.options.padding * 2);
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
getBounds: function () {
|
|
111
|
+
var halfSize = this.getSize().multiplyBy(0.5);
|
|
112
|
+
var center = this._map.latLngToContainerPoint(this._map.getCenter());
|
|
113
|
+
return L.latLngBounds(
|
|
114
|
+
this._map.containerPointToLatLng(center.subtract(halfSize)),
|
|
115
|
+
this._map.containerPointToLatLng(center.add(halfSize))
|
|
116
|
+
);
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
getContainer: function () {
|
|
120
|
+
return this._container;
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// returns the pane name set in options if it is a valid pane, defaults to tilePane
|
|
124
|
+
getPaneName: function () {
|
|
125
|
+
return this._map.getPane(this.options.pane) ? this.options.pane : 'tilePane';
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
_roundPoint: function (p) {
|
|
129
|
+
return { x: Math.round(p.x), y: Math.round(p.y) };
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
_initContainer: function () {
|
|
133
|
+
var container = this._container = L.DomUtil.create('div', 'leaflet-gl-layer');
|
|
134
|
+
this._resizeContainer();
|
|
135
|
+
|
|
136
|
+
var offset = this._map.getSize().multiplyBy(this.options.padding);
|
|
137
|
+
|
|
138
|
+
var topLeft = this._map.containerPointToLayerPoint([0, 0]).subtract(offset);
|
|
139
|
+
|
|
140
|
+
L.DomUtil.setPosition(container, this._roundPoint(topLeft));
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
_resizeContainer: function () {
|
|
144
|
+
var size = this.getSize();
|
|
145
|
+
this._container.style.width = size.x + 'px';
|
|
146
|
+
this._container.style.height = size.y + 'px';
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
_initGL: function () {
|
|
150
|
+
var center = this._map.getCenter();
|
|
151
|
+
|
|
152
|
+
var options = L.extend({}, this.options, {
|
|
153
|
+
container: this._container,
|
|
154
|
+
center: [center.lng, center.lat],
|
|
155
|
+
zoom: this._map.getZoom() - 1,
|
|
156
|
+
attributionControl: false
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
this._glMap = new maplibregl.Map(options);
|
|
160
|
+
|
|
161
|
+
var _map = this._map;
|
|
162
|
+
var _currentAttribution = this.getAttribution();
|
|
163
|
+
var _getAttribution = this.getAttribution.bind(this);
|
|
164
|
+
this._glMap.on('load', function () {
|
|
165
|
+
// Force attribution update
|
|
166
|
+
if (_map && _map.attributionControl) {
|
|
167
|
+
_map.attributionControl.removeAttribution(_currentAttribution);
|
|
168
|
+
_map.attributionControl.addAttribution(_getAttribution());
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// allow GL base map to pan beyond min/max latitudes
|
|
173
|
+
// Defensively check if properties are writable before setting them,
|
|
174
|
+
// ensuring compatibility with both old and new versions of MapLibre GL JS.
|
|
175
|
+
var transformProto = Object.getPrototypeOf(this._glMap.transform);
|
|
176
|
+
|
|
177
|
+
var latRangeDescriptor = Object.getOwnPropertyDescriptor(transformProto, 'latRange');
|
|
178
|
+
if (!latRangeDescriptor || latRangeDescriptor.set || latRangeDescriptor.writable) {
|
|
179
|
+
this._glMap.transform.latRange = null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Although this property is obsolete in modern versions, we apply the same
|
|
183
|
+
// defensive check for robust backward compatibility.
|
|
184
|
+
var maxValidLatitudeDescriptor = Object.getOwnPropertyDescriptor(transformProto, 'maxValidLatitude');
|
|
185
|
+
if (!maxValidLatitudeDescriptor || maxValidLatitudeDescriptor.set || maxValidLatitudeDescriptor.writable) {
|
|
186
|
+
this._glMap.transform.maxValidLatitude = Infinity;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
// check for the existence of _helper and _latRange in MapLibre
|
|
191
|
+
// this supports MapLibre v5
|
|
192
|
+
if (this._glMap.transform._helper && this._glMap.transform._helper._latRange) {
|
|
193
|
+
this._glMap.transform._helper._latRange = [-Infinity, Infinity];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this._transformGL(this._glMap);
|
|
197
|
+
|
|
198
|
+
if (this._glMap._canvas.canvas) {
|
|
199
|
+
// older versions of mapbox-gl surfaced the canvas differently
|
|
200
|
+
this._glMap._actualCanvas = this._glMap._canvas.canvas;
|
|
201
|
+
} else {
|
|
202
|
+
this._glMap._actualCanvas = this._glMap._canvas;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
// treat child <canvas> element like L.ImageOverlay
|
|
207
|
+
var canvas = this._glMap._actualCanvas;
|
|
208
|
+
L.DomUtil.addClass(canvas, 'leaflet-image-layer');
|
|
209
|
+
L.DomUtil.addClass(canvas, 'leaflet-zoom-animated');
|
|
210
|
+
|
|
211
|
+
if (this.options.interactive) {
|
|
212
|
+
L.DomUtil.addClass(canvas, 'leaflet-interactive');
|
|
213
|
+
}
|
|
214
|
+
if (this.options.className) {
|
|
215
|
+
L.DomUtil.addClass(canvas, this.options.className);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
_update: function (e) {
|
|
220
|
+
if (!this._map) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
// update the offset so we can correct for it later when we zoom
|
|
224
|
+
this._offset = this._map.containerPointToLayerPoint([0, 0]);
|
|
225
|
+
|
|
226
|
+
if (this._zooming) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
var container = this._container,
|
|
231
|
+
gl = this._glMap,
|
|
232
|
+
offset = this._map.getSize().multiplyBy(this.options.padding),
|
|
233
|
+
topLeft = this._map.containerPointToLayerPoint([0, 0]).subtract(offset);
|
|
234
|
+
|
|
235
|
+
L.DomUtil.setPosition(container, this._roundPoint(topLeft));
|
|
236
|
+
|
|
237
|
+
this._transformGL(gl);
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
_transformGL: function (gl) {
|
|
241
|
+
var center = this._map.getCenter();
|
|
242
|
+
|
|
243
|
+
// gl.setView([center.lat, center.lng], this._map.getZoom() - 1, 0);
|
|
244
|
+
// calling setView directly causes sync issues because it uses requestAnimFrame
|
|
245
|
+
|
|
246
|
+
var tr = gl._getTransformForUpdate(); // .clone() ?
|
|
247
|
+
|
|
248
|
+
if (tr.setCenter) {
|
|
249
|
+
// maplibre 5.0.0 and higher:
|
|
250
|
+
tr.setCenter(maplibregl.LngLat.convert([center.lng, center.lat]));
|
|
251
|
+
tr.setZoom(this._map.getZoom() - 1);
|
|
252
|
+
gl.transform.apply(tr);
|
|
253
|
+
} else {
|
|
254
|
+
// maplibre < 5.0.0
|
|
255
|
+
tr = gl.transform;
|
|
256
|
+
tr.center = maplibregl.LngLat.convert([center.lng, center.lat]);
|
|
257
|
+
tr.zoom = this._map.getZoom() - 1;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
gl._fireMoveEvents();
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
// update the map constantly during a pinch zoom
|
|
264
|
+
_pinchZoom: function (e) {
|
|
265
|
+
this._glMap.jumpTo({
|
|
266
|
+
zoom: this._map.getZoom() - 1,
|
|
267
|
+
center: this._map.getCenter()
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// borrowed from L.ImageOverlay
|
|
272
|
+
// https://github.com/Leaflet/Leaflet/blob/master/src/layer/ImageOverlay.js#L139-L144
|
|
273
|
+
_animateZoom: function (e) {
|
|
274
|
+
var scale = this._map.getZoomScale(e.zoom);
|
|
275
|
+
var padding = this._map.getSize().multiplyBy(this.options.padding * scale);
|
|
276
|
+
var viewHalf = this.getSize()._divideBy(2);
|
|
277
|
+
// corrections for padding (scaled), adapted from
|
|
278
|
+
// https://github.com/Leaflet/Leaflet/blob/master/src/map/Map.js#L1490-L1508
|
|
279
|
+
var topLeft = this._map.project(e.center, e.zoom)
|
|
280
|
+
._subtract(viewHalf)
|
|
281
|
+
._add(this._map._getMapPanePos()
|
|
282
|
+
.add(padding))._round();
|
|
283
|
+
var offset = this._map.project(this._map.getBounds().getNorthWest(), e.zoom)
|
|
284
|
+
._subtract(topLeft);
|
|
285
|
+
|
|
286
|
+
L.DomUtil.setTransform(
|
|
287
|
+
this._glMap._actualCanvas,
|
|
288
|
+
offset.subtract(this._offset),
|
|
289
|
+
scale
|
|
290
|
+
);
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
_zoomStart: function (e) {
|
|
294
|
+
this._zooming = true;
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
_zoomEnd: function () {
|
|
298
|
+
var scale = this._map.getZoomScale(this._map.getZoom());
|
|
299
|
+
|
|
300
|
+
L.DomUtil.setTransform(
|
|
301
|
+
this._glMap._actualCanvas,
|
|
302
|
+
// https://github.com/mapbox/mapbox-gl-leaflet/pull/130
|
|
303
|
+
null,
|
|
304
|
+
scale
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
this._zooming = false;
|
|
308
|
+
|
|
309
|
+
this._update();
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
_transitionEnd: function (e) {
|
|
313
|
+
L.Util.requestAnimFrame(function () {
|
|
314
|
+
var zoom = this._map.getZoom();
|
|
315
|
+
var center = this._map.getCenter();
|
|
316
|
+
var offset = this._map.latLngToContainerPoint(
|
|
317
|
+
this._map.getBounds().getNorthWest()
|
|
318
|
+
);
|
|
319
|
+
this._resizeContainer();
|
|
320
|
+
|
|
321
|
+
// reset the scale and offset
|
|
322
|
+
L.DomUtil.setTransform(this._glMap._actualCanvas, offset, 1);
|
|
323
|
+
|
|
324
|
+
// enable panning once the gl map is ready again
|
|
325
|
+
this._glMap.once('moveend', L.Util.bind(function () {
|
|
326
|
+
this._zoomEnd();
|
|
327
|
+
}, this));
|
|
328
|
+
|
|
329
|
+
// update the map position
|
|
330
|
+
this._glMap.jumpTo({
|
|
331
|
+
center: center,
|
|
332
|
+
zoom: zoom - 1
|
|
333
|
+
});
|
|
334
|
+
}, this);
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
_resize: function (e) {
|
|
338
|
+
this._transitionEnd(e);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
L.maplibreGL = function (options) {
|
|
343
|
+
return new L.MaplibreGL(options);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
}));
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "maplibre-gl-leaflet-with-canvas-dash-offset",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Supports adding Maplibre GL Web to a Leaflet Map as a layer",
|
|
5
|
+
"main": "leaflet-maplibre-gl.js",
|
|
6
|
+
"directories": {
|
|
7
|
+
"example": "examples"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "jshint leaflet-maplibre-gl.js"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/maplibre/maplibre-gl-leaflet.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"maplibre",
|
|
18
|
+
"gl",
|
|
19
|
+
"leaflet",
|
|
20
|
+
"leafletjs",
|
|
21
|
+
"maps"
|
|
22
|
+
],
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/maplibre/maplibre-gl-leaflet/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/maplibre/maplibre-gl-leaflet",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"jshint": "^2.10.1"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@types/leaflet": "^1.9.0",
|
|
33
|
+
"leaflet-with-canvas-dash-offset": "^1.9.3",
|
|
34
|
+
"maplibre-gl": "^2.4.0 || ^3.3.1 || ^4.3.2 || ^5.0.0"
|
|
35
|
+
},
|
|
36
|
+
"types": "leaflet-maplibre-gl.d.ts"
|
|
37
|
+
}
|