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.
@@ -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
+ }