leaflet-rotate 0.1.4 → 0.2.0

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/lib/debug.js CHANGED
@@ -9,10 +9,14 @@ L.Rotate = {
9
9
  width: 100%;
10
10
  }
11
11
  .leaflet-rotate-info td {
12
- width: 7em;
12
+ /* width: 7em; */
13
13
  overflow: hidden;
14
- max-width: 7em;
14
+ /* max-width: 7em; */
15
15
  text-overflow: ellipsis;
16
+ /* white-space: nowrap; */
17
+ }
18
+ .leaflet-rotate-info td:nth-of-type(3) {
19
+ font-family: Monospace;
16
20
  }
17
21
  .leaflet-rotate-info th {
18
22
  text-align: left;
@@ -30,15 +34,31 @@ L.Rotate = {
30
34
  position:absolute;
31
35
  width:1px;
32
36
  height:1px;
33
- border: 1px solid purple;
34
- z-index: 100;
37
+ border: 5px solid yellow;
38
+ border-radius: 100%;
39
+ z-index: 1000;
35
40
  }
36
41
  div.pixelorigin {
37
- position:absolute;
38
- width:1px;
39
- height:1px;
40
- border: 1px solid cyan;
41
- z-index: 100;
42
+ position: absolute;
43
+ width: 1px;
44
+ height: 1px;
45
+ border: 5px solid yellow;
46
+ border-radius: 100%;
47
+ z-index: 1000;
48
+ }
49
+ div.pivot:before {
50
+ left: -1.5em;
51
+ bottom: -2em;
52
+ position: absolute;
53
+ content: 'PIVOT';
54
+ color: yellow;
55
+ }
56
+ div.pixelorigin:before {
57
+ left: -1.75em;
58
+ top: -2em;
59
+ position: absolute;
60
+ content: 'ORIGIN';
61
+ color: yellow;
42
62
  }
43
63
  div.panebounds.main {
44
64
  position:absolute;
@@ -111,6 +131,7 @@ L.Rotate = {
111
131
  </td>
112
132
  <td>
113
133
  <button onclick="L.Rotate.randomRotateMarkers(L.Rotate._map);" title="markers.setRotation(Math.random() * Math.PI / 30 + 0.1)">Rotate Markers</button>
134
+ <button onclick="L.Rotate.randomMarkers(L.Rotate._map, 100);" title="add 100 random markers to map">Add Markers</button>
114
135
  </td>
115
136
  </tr>
116
137
  <tr>
@@ -149,6 +170,12 @@ L.Rotate = {
149
170
  <td id='ogy'></td>
150
171
  <td class='long'>Negative pixel coords of the (0,0) CRS point relative to _rotatePane</td>
151
172
  </tr>
173
+ <tr>
174
+ <th>Pixel bounds </th>
175
+ <td id='ogbx'></td>
176
+ <td id='ogby'></td>
177
+ <td class='long'>Bounds of the current map view in projected pixel coordinates {min, max}.</td>
178
+ </tr>
152
179
  </table>`);
153
180
 
154
181
  map.___rotatePixelOrigin = L.DomUtil.create('div', 'pixelorigin', map._rotatePane);
@@ -165,15 +192,25 @@ L.Rotate = {
165
192
 
166
193
  padInput.addEventListener('change', L.Rotate.displayCenter.bind(this));
167
194
  padInput.addEventListener('mousemove', L.Rotate.displayCenter.bind(this));
195
+ padInput.addEventListener('change', L.Rotate.displayBounds.bind(this));
196
+ padInput.addEventListener('mousemove', L.Rotate.displayBounds.bind(this));
197
+ padInput.addEventListener('change', L.Rotate.displayPixelBounds.bind(this));
198
+ padInput.addEventListener('mousemove', L.Rotate.displayPixelBounds.bind(this));
168
199
 
169
200
  map.on('move rotate zoomend', this.updatePanePos);
170
201
  map.on('rotate zoomend load', this.updatePixelOrigin);
202
+ map.on('rotate', this.updateRhoInput);
203
+ map.on('rotate', this.updatePivotDot);
171
204
  map.on('moveend zoomend resetview rotate', this.displayCenter.bind(this));
205
+ map.on('moveend zoomend resetview rotate', this.displayBounds.bind(this));
206
+ map.on('moveend zoomend resetview rotate', this.displayPixelBounds.bind(this));
172
207
 
173
208
  this.updatePixelOrigin.call(map);
209
+ this.updateRhoInput.call(map);
210
+ this.updatePivotDot.call(map);
174
211
  this.displayCenter.call(this);
175
-
176
- map.on('rotate', this.updatePivotDot);
212
+ this.displayBounds.call(this);
213
+ this.displayPixelBounds.call(this);
177
214
 
178
215
  if (L.Browser.mobile) {
179
216
  map.compassBearing.enable();
@@ -204,10 +241,16 @@ L.Rotate = {
204
241
  document.getElementById('cny').innerHTML = e.containerPoint.y;
205
242
  },
206
243
 
244
+ /**
245
+ * Debug L.Map.setBearing()
246
+ */
207
247
  rotate: function(e) {
208
248
  return e.buttons !== 0 && this._map.setBearing(e.target.valueAsNumber);
209
249
  },
210
250
 
251
+ /**
252
+ * Debug L.Map._pixelOrigin
253
+ */
211
254
  updatePixelOrigin: function() {
212
255
  document.getElementById('ogx').innerHTML = this._pixelOrigin.x;
213
256
  document.getElementById('ogy').innerHTML = this._pixelOrigin.y;
@@ -215,6 +258,9 @@ L.Rotate = {
215
258
  this.___rotatePixelOrigin.style.top = (-this._pixelOrigin.y - 1) + 'px';
216
259
  },
217
260
 
261
+ /**
262
+ * Debug L.Map._pivot
263
+ */
218
264
  updatePivotDot: function() {
219
265
  document.getElementById('pvx').innerHTML = this._pivot.x;
220
266
  document.getElementById('pvy').innerHTML = this._pivot.y;
@@ -222,17 +268,33 @@ L.Rotate = {
222
268
  this.___rotatePivotDot.style.top = (this._pivot.y - 1) + 'px';
223
269
  },
224
270
 
271
+ /**
272
+ * Debug L.Map._getMapPanePos()
273
+ */
225
274
  updatePanePos: function() {
226
275
  var panePos = this._getMapPanePos();
227
276
  document.getElementById('pox').innerHTML = panePos.x;
228
277
  document.getElementById('poy').innerHTML = panePos.y;
229
278
  },
230
279
 
280
+ /**
281
+ * Debug L.Map.getBearing()
282
+ */
283
+ updateRhoInput: function() {
284
+ document.getElementById('rho_input').value = this.getBearing();
285
+ },
286
+
287
+ /**
288
+ * Debug L.Map.setBearing()
289
+ */
231
290
  rotateOneDegree: function() {
232
291
  var angle = document.getElementById('rho_input').valueAsNumber++;
233
292
  this.setBearing(angle < 360 ? angle : 0);
234
293
  },
235
294
 
295
+ /**
296
+ * Debug L.Marker.setRotation()
297
+ */
236
298
  randomRotateMarkers: function(map) {
237
299
  var markers = [],
238
300
  steps = [];
@@ -254,27 +316,156 @@ L.Rotate = {
254
316
  stepOn(25);
255
317
  },
256
318
 
319
+ /**
320
+ * Debug L.Map.panInside()
321
+ */
322
+ randomMarkers: function(map, number) {
323
+ var map = this._map;
324
+ var populate = function() {
325
+ // populate map with a cluster of random markers
326
+ for (var i = 0; i < number; i++) {
327
+ var bounds = map.getBounds();
328
+ var southWest = bounds.getSouthWest();
329
+ var northEast = bounds.getNorthEast();
330
+ var lngSpan = northEast.lng - southWest.lng;
331
+ var latSpan = northEast.lat - southWest.lat;
332
+ var m = L.marker( L.latLng(southWest.lat + latSpan * Math.random(), southWest.lng + lngSpan * Math.random()) );
333
+ m.addTo(L.Rotate._map);
334
+ L.Rotate.___cluster.addLayer(m);
335
+ }
336
+ }
337
+ if (!this.___cluster) {
338
+ // import and initialize "leaflet.markercluster" plugin
339
+ this.___cluster = import("https://unpkg.com/leaflet.markercluster@1.4.1/src/index.js")
340
+ .then(m => {
341
+ document.head.insertAdjacentHTML('beforeend', `
342
+ <!-- Leaflet-MarkerCluster -->
343
+ <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css">
344
+ <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css">
345
+ `);
346
+ Object.assign(globalThis.L, m);
347
+ this.___cluster = L.markerClusterGroup({
348
+ spiderfyOnMaxZoom: false,
349
+ showCoverageOnHover: false,
350
+ zoomToBoundsOnClick: false
351
+ })
352
+ .on('clusterclick', (a) => a.layer.spiderfy())
353
+ .addTo(map);
354
+ populate();
355
+ });
356
+ } else if (typeof L.markerClusterGroup === 'function') {
357
+ populate();
358
+ }
359
+ },
360
+
361
+ /**
362
+ * Debug L.Map.getCenter()
363
+ */
257
364
  displayCenter: function() {
258
365
  var map = this._map;
259
366
  if (this.___centerMarker) {
260
367
  this.___centerMarker.remove();
261
368
  }
262
369
  this.___centerMarker = L.circleMarker(map.getCenter(), {
263
- radius: 0,
264
- color: 'green',
265
- }).addTo(map);
370
+ radius: 3,
371
+ color: 'red',
372
+ }).addTo(map).bindTooltip('<b>center</b>', { direction: 'right', permanent: true, });
373
+ this.___centerMarker.getTooltip().getElement().setAttribute("tabindex", "-1");
374
+ },
266
375
 
267
- if (this.___bounds) {
268
- this.___bounds.remove();
269
- }
270
- var padding = document.getElementById('pad_input').valueAsNumber;
271
- this.___bounds = L.rectangle(map.getBounds().pad(padding), {
272
- fill: false,
273
- lineCap: 'square',
274
- color: 'green',
275
- dashArray: '5, 10',
276
- weight: 2,
277
- }).addTo(map);
376
+ /**
377
+ * Debug L.Map.getCenter()
378
+ */
379
+ displayBounds: function() {
380
+ var map = this._map;
381
+ if (this.___bounds) {
382
+ this.___bounds.remove();
383
+ }
384
+ var padding = document.getElementById('pad_input').valueAsNumber;
385
+ var latLngBounds = map.getBounds().pad(padding)
386
+ this.___bounds = L.rectangle(latLngBounds, {
387
+ fill: false,
388
+ lineCap: 'square',
389
+ color: 'yellow',
390
+ dashArray: '5, 10',
391
+ weight: 2,
392
+ // pane: 'norotatePane',
393
+ }).addTo(map);
394
+ },
395
+
396
+ /**
397
+ * @TODO Debug L.Map.getPixelBounds()
398
+ */
399
+ displayPixelBounds: function() {
400
+ var map = this._map;
401
+ this.___corners && this.___corners.remove();
402
+ this.___pixelbounds && this.___pixelbounds.remove();
403
+
404
+ const size = map.getSize();
405
+ const rect = map._container.getBoundingClientRect();
406
+ const pixelBounds = map.getPixelBounds();
407
+
408
+ const TL = L.point(rect);
409
+ const TR = L.point(rect).add(L.point(rect.width, 0));
410
+ const BR = L.point(rect).add(L.point(rect.width, rect.height))
411
+ const BL = L.point(rect).add(L.point(0, rect.height));
412
+
413
+ const topLeft = L.marker( map.containerPointToLatLng(TL), { title: 'Top Left corner', rotation: 135 * L.DomUtil.DEG_TO_RAD } );
414
+ const topRight = L.marker( map.containerPointToLatLng(TR), { title: 'Top Right corner', rotation: -135 * L.DomUtil.DEG_TO_RAD } );
415
+ const bottomRight = L.marker( map.containerPointToLatLng(BR), { title: 'Bottom Right corner', rotation: -45 * L.DomUtil.DEG_TO_RAD } );
416
+ const bottomLeft = L.marker( map.containerPointToLatLng(BL), { title: 'Bottom Left corner', rotation: -135 * L.DomUtil.DEG_TO_RAD } );
417
+
418
+ this.___corners = L.featureGroup([topLeft, topRight, bottomRight, bottomLeft]).addTo(map).eachLayer(marker => marker.getElement().style.filter = 'hue-rotate(150deg)');
419
+
420
+ // L.polyline([
421
+ // [topLeft.getLatLng(), topRight.getLatLng()],
422
+ // [topRight.getLatLng(), bottomRight.getLatLng()],
423
+ // [bottomRight.getLatLng(), bottomLeft.getLatLng()],
424
+ // [bottomLeft.getLatLng(), topLeft.getLatLng()],
425
+ // ], {
426
+ // lineCap: 'square',
427
+ // dashArray: '5, 1, 5',
428
+ // color: 'yellow',
429
+ // weight: 2,
430
+ // }).addTo(this.___corners);
431
+
432
+ // this.___latLngBounds = L.latLngBounds([
433
+ // // map.containerPointToLatLng(TL),
434
+ // //map.containerPointToLatLng(BR)
435
+ // topLeft.getLatLng(),
436
+ // topRight.getLatLng(),
437
+ // bottomRight.getLatLng(),
438
+ // bottomLeft.getLatLng(),
439
+ // ]);
440
+
441
+ // this.___pixelbounds = L.rectangle(this.___latLngPixelBounds, {
442
+ // fill: false,
443
+ // lineCap: 'square',
444
+ // dashArray: '5, 1, 5',
445
+ // color: 'yellow',
446
+ // weight: 2,
447
+ // pane: 'norotatePane',
448
+ // }).addTo(map);
449
+
450
+
451
+ // this.___latLngPixelBounds = L.latLngBounds([
452
+ // map.layerPointToLatLng([0, 0]), // topleft
453
+ // map.layerPointToLatLng([size.x, 0]), // topright
454
+ // map.layerPointToLatLng([size.x, size.y]), // bottomright
455
+ // map.layerPointToLatLng([0, size.y]), // bottomleft
456
+ // ]);
457
+
458
+ // const paddingTL = L.point(L.Marker.prototype.options.icon.options.iconAnchor || [0, 0]),
459
+ // paddingBR = L.point(L.Marker.prototype.options.icon.options.iconSize || [0, 0]).subtract(paddingTL),
460
+ // pixelBounds = L.bounds([ L.point(rect), L.point(rect).add(map.getSize()) ]),
461
+ // paddedBounds = L.latLngBounds([
462
+ // map.layerPointToLatLng(pixelBounds.min.add(paddingTL)),
463
+ // map.layerPointToLatLng(pixelBounds.max.subtract(paddingBR))
464
+ // ]);
465
+ // // paddedSize = paddedBounds.getSize();
466
+
467
+ document.getElementById('ogbx').innerHTML = JSON.stringify(pixelBounds.min);
468
+ document.getElementById('ogby').innerHTML = JSON.stringify(pixelBounds.max);
278
469
  },
279
470
 
280
471
  resetHeading: function(e) {
@@ -283,6 +474,9 @@ L.Rotate = {
283
474
  }
284
475
  },
285
476
 
477
+ /**
478
+ * Debug L.Map.locate()
479
+ */
286
480
  locate: function() {
287
481
  this._map.locate({
288
482
  setView: true,
package/lib/debug.min.js CHANGED
@@ -1,9 +1 @@
1
- 'use strict';L.Rotate={debug:function(map,options={}){this._map=map;document.head.insertAdjacentHTML("beforeend",`<style>\n .leaflet-rotate-info {\n width: 100%;\n }\n .leaflet-rotate-info td {\n width: 7em;\n overflow: hidden;\n max-width: 7em;\n text-overflow: ellipsis;\n }\n .leaflet-rotate-info th {\n text-align: left;\n }\n div.crosshair {\n position:absolute;\n width:1px;\n height:1px;\n border: 1px solid green;\n z-index: 100;\n left: 50%;\n right: 50%;\n }\n div.pivot {\n position:absolute;\n width:1px;\n height:1px;\n border: 1px solid purple;\n z-index: 100;\n }\n div.pixelorigin {\n position:absolute;\n width:1px;\n height:1px;\n border: 1px solid cyan;\n z-index: 100;\n }\n div.panebounds.main {\n position:absolute;\n width:800px;\n height:600px;\n border: 1px solid red;\n border-bottom: 1px red dashed;\n border-right: 1px red dashed;\n z-index: 100;\n }\n div.panebounds.rotate {\n position:absolute;\n width:800px;\n height:600px;\n border: 1px solid purple;\n border-bottom: 1px purple dashed;\n border-right: 1px purple dashed;\n z-index: 100;\n }\n div.crosshair.c1 {\n left:calc(50% - 5px);\n top:50%;\n height: 0;\n width: 10px;\n }\n div.crosshair.c2 {\n left:50%;\n top:calc(50% - 5px);\n width: 0;\n height: 10px;\n }\n #rho_input {\n vertical-align: middle;\n }\n .panebounds:before {\n padding: 1ch;\n }\n .panebounds.rotate:before {\n float: right;\n content: 'ROTATED';\n }\n .panebounds.main:before {\n float: left;\n content: 'MAIN';\n }\n </style>`);
2
- map._container.insertAdjacentHTML("afterbegin",`<div class="crosshair c1"></div><div class="crosshair c2"></div>`);map._container.insertAdjacentHTML("afterend",`<hr>\n <table class="leaflet-rotate-info">\n <tr>\n <td>\n <button onclick="L.Rotate._map.setBearing(0);" title="map.setBearing(0);"> 0</button>\n <button onclick="L.Rotate._map.setBearing(15);" title="map.setBearing(15);">15</button>\n <button onclick="L.Rotate._map.setBearing(30);" title="map.setBearing(30);">30</button>\n <button onclick="L.Rotate._map.setBearing(45);" title="map.setBearing(45);">45</button>\n <button onclick="L.Rotate._map.setBearing(60);" title="map.setBearing(60);">60</button>\n <button onclick="L.Rotate._map.setBearing(75);" title="map.setBearing(75);">75</button>\n <button onclick="L.Rotate._map.setBearing(90);" title="map.setBearing(90);">90</button>\n <button onclick="L.Rotate._map.setBearing(180);" title="map.setBearing(180);">180</button>\n </td>\n <td>\n <input title="increase/decrease rotation angle" type="range" min="0" max="360" step="1" value="0" name="rho" id='rho_input' /><span id='rho'></span>\n </td>\n <td>\n <input title="increase/decrease padding bounds" type="range" min="-0.25" max="0" value="0" step="0.01" name="pad" id='pad_input' />\n </td>\n <td>\n <button onclick="L.Rotate.randomRotateMarkers(L.Rotate._map);" title="markers.setRotation(Math.random() * Math.PI / 30 + 0.1)">Rotate Markers</button>\n </td>\n </tr>\n <tr>\n <th>LatLng </th>\n <td id='llx'></td>\n <td id='lly'></td>\n <td class='long'>LatLng of mouse pointer</td>\n </tr>\n <tr>\n <th>Rel to pane </th>\n <td id='lyx'></td>\n <td id='lyy'></td>\n <td class='long'>Mouse pointer pixel coords relative to _rotatePane</td>\n </tr>\n <tr>\n <th>Rel to container</th>\n <td id='cnx'></td>\n <td id='cny'></td>\n <td class='long'>Mouse pointer coords relative to map &lt;div&gt;</td>\n </tr>\n <tr>\n <th>Pivot </th>\n <td id='pvx'></td>\n <td id='pvy'></td>\n <td class='long'>Last _rotationPane pivot pixel coords relative to _rotationPane</td>\n </tr>\n <tr>\n <th>Pane offset </th>\n <td id='pox'></td>\n <td id='poy'></td>\n <td class='long'>Pixel offset of _mapPane</td>\n </tr>\n <tr>\n <th>Pixel origin </th>\n <td id='ogx'></td>\n <td id='ogy'></td>\n <td class='long'>Negative pixel coords of the (0,0) CRS point relative to _rotatePane</td>\n </tr>\n </table>`);
3
- map.___rotatePixelOrigin=L.DomUtil.create("div","pixelorigin",map._rotatePane);map.___rotatePivotDot=L.DomUtil.create("div","pivot",map._mapPane);L.DomUtil.create("div","panebounds rotate",map._rotatePane);L.DomUtil.create("div","panebounds main",map._mapPane);var rhoInput=document.getElementById("rho_input");var padInput=document.getElementById("pad_input");rhoInput.addEventListener("change",L.Rotate.rotate.bind(this));rhoInput.addEventListener("mousemove",L.Rotate.rotate.bind(this));padInput.addEventListener("change",
4
- L.Rotate.displayCenter.bind(this));padInput.addEventListener("mousemove",L.Rotate.displayCenter.bind(this));map.on("move rotate zoomend",this.updatePanePos);map.on("rotate zoomend load",this.updatePixelOrigin);map.on("moveend zoomend resetview rotate",this.displayCenter.bind(this));this.updatePixelOrigin.call(map);this.displayCenter.call(this);map.on("rotate",this.updatePivotDot);if(L.Browser.mobile)map.compassBearing.enable();map.on("mousemove",this.logMouse);map.on("locationfound",this.resetHeading);
5
- if(options.log)map.on("click movestart move moveend zoomstart zoomend locationfound locationerror locationfound",this.logEvent)},logEvent:function(e){console.log(e,e.type)},logMouse:function(e){document.getElementById("llx").innerHTML=e.latlng.lng;document.getElementById("lly").innerHTML=e.latlng.lat;document.getElementById("lyx").innerHTML=e.layerPoint.x;document.getElementById("lyy").innerHTML=e.layerPoint.y;document.getElementById("cnx").innerHTML=e.containerPoint.x;document.getElementById("cny").innerHTML=
6
- e.containerPoint.y},rotate:function(e){return e.buttons!==0&&this._map.setBearing(e.target.valueAsNumber)},updatePixelOrigin:function(){document.getElementById("ogx").innerHTML=this._pixelOrigin.x;document.getElementById("ogy").innerHTML=this._pixelOrigin.y;this.___rotatePixelOrigin.style.left=-this._pixelOrigin.x-1+"px";this.___rotatePixelOrigin.style.top=-this._pixelOrigin.y-1+"px"},updatePivotDot:function(){document.getElementById("pvx").innerHTML=this._pivot.x;document.getElementById("pvy").innerHTML=
7
- this._pivot.y;this.___rotatePivotDot.style.left=this._pivot.x-1+"px";this.___rotatePivotDot.style.top=this._pivot.y-1+"px"},updatePanePos:function(){var panePos=this._getMapPanePos();document.getElementById("pox").innerHTML=panePos.x;document.getElementById("poy").innerHTML=panePos.y},rotateOneDegree:function(){var angle=document.getElementById("rho_input").valueAsNumber++;this.setBearing(angle<360?angle:0)},randomRotateMarkers:function(map){var markers=[],steps=[];for(var i in map._layers)if(map._layers[i]instanceof
8
- L.Marker){markers.push(map._layers[i]);steps.push(Math.random()*Math.PI/30+.1)}function stepOn(steps_left){for(var i=0;i<markers.length;i++)markers[i].setRotation(markers[i].options.rotation+steps[i]);if(--steps_left)setTimeout(stepOn.bind(null,steps_left),20)}stepOn(25)},displayCenter:function(){var map=this._map;if(this.___centerMarker)this.___centerMarker.remove();this.___centerMarker=L.circleMarker(map.getCenter(),{radius:0,color:"green"}).addTo(map);if(this.___bounds)this.___bounds.remove();
9
- var padding=document.getElementById("pad_input").valueAsNumber;this.___bounds=L.rectangle(map.getBounds().pad(padding),{fill:false,lineCap:"square",color:"green",dashArray:"5, 10",weight:2}).addTo(map)},resetHeading:function(e){if(e.heading!==null)this.setBearing(e.heading)},locate:function(){this._map.locate({setView:true,enableHighAccuracy:true})}};
1
+ L.Rotate={debug:function(map,options={}){this._map=map,document.head.insertAdjacentHTML("beforeend","<style>\n .leaflet-rotate-info {\n width: 100%;\n }\n .leaflet-rotate-info td {\n /* width: 7em; */\n overflow: hidden;\n /* max-width: 7em; */\n text-overflow: ellipsis;\n /* white-space: nowrap; */\n }\n .leaflet-rotate-info td:nth-of-type(3) {\n font-family: Monospace;\n }\n .leaflet-rotate-info th {\n text-align: left;\n }\n div.crosshair {\n position:absolute;\n width:1px;\n height:1px;\n border: 1px solid green;\n z-index: 100;\n left: 50%;\n right: 50%;\n }\n div.pivot {\n position:absolute;\n width:1px;\n height:1px;\n border: 5px solid yellow;\n border-radius: 100%;\n z-index: 1000;\n }\n div.pixelorigin {\n position: absolute;\n width: 1px;\n height: 1px;\n border: 5px solid yellow;\n border-radius: 100%;\n z-index: 1000;\n }\n div.pivot:before {\n left: -1.5em;\n bottom: -2em;\n position: absolute;\n content: 'PIVOT';\n color: yellow;\n }\n div.pixelorigin:before {\n left: -1.75em;\n top: -2em;\n position: absolute;\n content: 'ORIGIN';\n color: yellow;\n }\n div.panebounds.main {\n position:absolute;\n width:800px;\n height:600px;\n border: 1px solid red;\n border-bottom: 1px red dashed;\n border-right: 1px red dashed;\n z-index: 100;\n }\n div.panebounds.rotate {\n position:absolute;\n width:800px;\n height:600px;\n border: 1px solid purple;\n border-bottom: 1px purple dashed;\n border-right: 1px purple dashed;\n z-index: 100;\n }\n div.crosshair.c1 {\n left:calc(50% - 5px);\n top:50%;\n height: 0;\n width: 10px;\n }\n div.crosshair.c2 {\n left:50%;\n top:calc(50% - 5px);\n width: 0;\n height: 10px;\n }\n #rho_input {\n vertical-align: middle;\n }\n .panebounds:before {\n padding: 1ch;\n }\n .panebounds.rotate:before {\n float: right;\n content: 'ROTATED';\n }\n .panebounds.main:before {\n float: left;\n content: 'MAIN';\n }\n </style>"),map._container.insertAdjacentHTML("afterbegin",'<div class="crosshair c1"></div><div class="crosshair c2"></div>'),map._container.insertAdjacentHTML("afterend",'<hr>\n <table class="leaflet-rotate-info">\n <tr>\n <td>\n <button onclick="L.Rotate._map.setBearing(0);" title="map.setBearing(0);"> 0</button>\n <button onclick="L.Rotate._map.setBearing(15);" title="map.setBearing(15);">15</button>\n <button onclick="L.Rotate._map.setBearing(30);" title="map.setBearing(30);">30</button>\n <button onclick="L.Rotate._map.setBearing(45);" title="map.setBearing(45);">45</button>\n <button onclick="L.Rotate._map.setBearing(60);" title="map.setBearing(60);">60</button>\n <button onclick="L.Rotate._map.setBearing(75);" title="map.setBearing(75);">75</button>\n <button onclick="L.Rotate._map.setBearing(90);" title="map.setBearing(90);">90</button>\n <button onclick="L.Rotate._map.setBearing(180);" title="map.setBearing(180);">180</button>\n </td>\n <td>\n <input title="increase/decrease rotation angle" type="range" min="0" max="360" step="1" value="0" name="rho" id=\'rho_input\' /><span id=\'rho\'></span>\n </td>\n <td>\n <input title="increase/decrease padding bounds" type="range" min="-0.25" max="0" value="0" step="0.01" name="pad" id=\'pad_input\' />\n </td>\n <td>\n <button onclick="L.Rotate.randomRotateMarkers(L.Rotate._map);" title="markers.setRotation(Math.random() * Math.PI / 30 + 0.1)">Rotate Markers</button>\n <button onclick="L.Rotate.randomMarkers(L.Rotate._map, 100);" title="add 100 random markers to map">Add Markers</button>\n </td>\n </tr>\n <tr>\n <th>LatLng </th>\n <td id=\'llx\'></td>\n <td id=\'lly\'></td>\n <td class=\'long\'>LatLng of mouse pointer</td>\n </tr>\n <tr>\n <th>Rel to pane </th>\n <td id=\'lyx\'></td>\n <td id=\'lyy\'></td>\n <td class=\'long\'>Mouse pointer pixel coords relative to _rotatePane</td>\n </tr>\n <tr>\n <th>Rel to container</th>\n <td id=\'cnx\'></td>\n <td id=\'cny\'></td>\n <td class=\'long\'>Mouse pointer coords relative to map &lt;div&gt;</td>\n </tr>\n <tr>\n <th>Pivot </th>\n <td id=\'pvx\'></td>\n <td id=\'pvy\'></td>\n <td class=\'long\'>Last _rotationPane pivot pixel coords relative to _rotationPane</td>\n </tr>\n <tr>\n <th>Pane offset </th>\n <td id=\'pox\'></td>\n <td id=\'poy\'></td>\n <td class=\'long\'>Pixel offset of _mapPane</td>\n </tr>\n <tr>\n <th>Pixel origin </th>\n <td id=\'ogx\'></td>\n <td id=\'ogy\'></td>\n <td class=\'long\'>Negative pixel coords of the (0,0) CRS point relative to _rotatePane</td>\n </tr>\n <tr>\n <th>Pixel bounds </th>\n <td id=\'ogbx\'></td>\n <td id=\'ogby\'></td>\n <td class=\'long\'>Bounds of the current map view in projected pixel coordinates {min, max}.</td>\n </tr>\n </table>'),map.___rotatePixelOrigin=L.DomUtil.create("div","pixelorigin",map._rotatePane),map.___rotatePivotDot=L.DomUtil.create("div","pivot",map._mapPane),L.DomUtil.create("div","panebounds rotate",map._rotatePane),L.DomUtil.create("div","panebounds main",map._mapPane);var rhoInput=document.getElementById("rho_input"),padInput=document.getElementById("pad_input");rhoInput.addEventListener("change",L.Rotate.rotate.bind(this)),rhoInput.addEventListener("mousemove",L.Rotate.rotate.bind(this)),padInput.addEventListener("change",L.Rotate.displayCenter.bind(this)),padInput.addEventListener("mousemove",L.Rotate.displayCenter.bind(this)),padInput.addEventListener("change",L.Rotate.displayBounds.bind(this)),padInput.addEventListener("mousemove",L.Rotate.displayBounds.bind(this)),padInput.addEventListener("change",L.Rotate.displayPixelBounds.bind(this)),padInput.addEventListener("mousemove",L.Rotate.displayPixelBounds.bind(this)),map.on("move rotate zoomend",this.updatePanePos),map.on("rotate zoomend load",this.updatePixelOrigin),map.on("rotate",this.updateRhoInput),map.on("rotate",this.updatePivotDot),map.on("moveend zoomend resetview rotate",this.displayCenter.bind(this)),map.on("moveend zoomend resetview rotate",this.displayBounds.bind(this)),map.on("moveend zoomend resetview rotate",this.displayPixelBounds.bind(this)),this.updatePixelOrigin.call(map),this.updateRhoInput.call(map),this.updatePivotDot.call(map),this.displayCenter.call(this),this.displayBounds.call(this),this.displayPixelBounds.call(this),L.Browser.mobile&&map.compassBearing.enable(),map.on("mousemove",this.logMouse),map.on("locationfound",this.resetHeading),options.log&&map.on("click movestart move moveend zoomstart zoomend locationfound locationerror locationfound",this.logEvent)},logEvent:function(e){console.log(e,e.type)},logMouse:function(e){document.getElementById("llx").innerHTML=e.latlng.lng,document.getElementById("lly").innerHTML=e.latlng.lat,document.getElementById("lyx").innerHTML=e.layerPoint.x,document.getElementById("lyy").innerHTML=e.layerPoint.y,document.getElementById("cnx").innerHTML=e.containerPoint.x,document.getElementById("cny").innerHTML=e.containerPoint.y},rotate:function(e){return 0!==e.buttons&&this._map.setBearing(e.target.valueAsNumber)},updatePixelOrigin:function(){document.getElementById("ogx").innerHTML=this._pixelOrigin.x,document.getElementById("ogy").innerHTML=this._pixelOrigin.y,this.___rotatePixelOrigin.style.left=-this._pixelOrigin.x-1+"px",this.___rotatePixelOrigin.style.top=-this._pixelOrigin.y-1+"px"},updatePivotDot:function(){document.getElementById("pvx").innerHTML=this._pivot.x,document.getElementById("pvy").innerHTML=this._pivot.y,this.___rotatePivotDot.style.left=this._pivot.x-1+"px",this.___rotatePivotDot.style.top=this._pivot.y-1+"px"},updatePanePos:function(){var panePos=this._getMapPanePos();document.getElementById("pox").innerHTML=panePos.x,document.getElementById("poy").innerHTML=panePos.y},updateRhoInput:function(){document.getElementById("rho_input").value=this.getBearing()},rotateOneDegree:function(){var angle=document.getElementById("rho_input").valueAsNumber++;this.setBearing(angle<360?angle:0)},randomRotateMarkers:function(map){var markers=[],steps=[];for(var i in map._layers)map._layers[i]instanceof L.Marker&&(markers.push(map._layers[i]),steps.push(Math.random()*Math.PI/30+.1));function stepOn(steps_left){for(var i=0;i<markers.length;i++)markers[i].setRotation(markers[i].options.rotation+steps[i]);--steps_left&&setTimeout(stepOn.bind(null,steps_left),20)}stepOn(25)},randomMarkers:function(map,number){var map=this._map,populate=function(){for(var i=0;i<number;i++){var bounds=map.getBounds(),southWest=bounds.getSouthWest(),northEast=bounds.getNorthEast(),lngSpan=northEast.lng-southWest.lng,latSpan=northEast.lat-southWest.lat,m=L.marker(L.latLng(southWest.lat+latSpan*Math.random(),southWest.lng+lngSpan*Math.random()));m.addTo(L.Rotate._map),L.Rotate.___cluster.addLayer(m)}};this.___cluster?"function"==typeof L.markerClusterGroup&&populate():this.___cluster=import("https://unpkg.com/leaflet.markercluster@1.4.1/src/index.js").then(m=>{document.head.insertAdjacentHTML("beforeend",'\n \x3c!-- Leaflet-MarkerCluster --\x3e\n <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css">\n <link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css">\n '),Object.assign(globalThis.L,m),this.___cluster=L.markerClusterGroup({spiderfyOnMaxZoom:!1,showCoverageOnHover:!1,zoomToBoundsOnClick:!1}).on("clusterclick",a=>a.layer.spiderfy()).addTo(map),populate()})},displayCenter:function(){var map=this._map;this.___centerMarker&&this.___centerMarker.remove(),this.___centerMarker=L.circleMarker(map.getCenter(),{radius:3,color:"red"}).addTo(map).bindTooltip("<b>center</b>",{direction:"right",permanent:!0}),this.___centerMarker.getTooltip().getElement().setAttribute("tabindex","-1")},displayBounds:function(){var map=this._map;this.___bounds&&this.___bounds.remove();var padding=document.getElementById("pad_input").valueAsNumber,latLngBounds=map.getBounds().pad(padding);this.___bounds=L.rectangle(latLngBounds,{fill:!1,lineCap:"square",color:"yellow",dashArray:"5, 10",weight:2}).addTo(map)},displayPixelBounds:function(){var map=this._map;this.___corners&&this.___corners.remove(),this.___pixelbounds&&this.___pixelbounds.remove();const size=map.getSize(),rect=map._container.getBoundingClientRect(),pixelBounds=map.getPixelBounds(),TL=L.point(rect),TR=L.point(rect).add(L.point(rect.width,0)),BR=L.point(rect).add(L.point(rect.width,rect.height)),BL=L.point(rect).add(L.point(0,rect.height)),topLeft=L.marker(map.containerPointToLatLng(TL),{title:"Top Left corner",rotation:135*L.DomUtil.DEG_TO_RAD}),topRight=L.marker(map.containerPointToLatLng(TR),{title:"Top Right corner",rotation:-135*L.DomUtil.DEG_TO_RAD}),bottomRight=L.marker(map.containerPointToLatLng(BR),{title:"Bottom Right corner",rotation:-45*L.DomUtil.DEG_TO_RAD}),bottomLeft=L.marker(map.containerPointToLatLng(BL),{title:"Bottom Left corner",rotation:-135*L.DomUtil.DEG_TO_RAD});this.___corners=L.featureGroup([topLeft,topRight,bottomRight,bottomLeft]).addTo(map).eachLayer(marker=>marker.getElement().style.filter="hue-rotate(150deg)"),document.getElementById("ogbx").innerHTML=JSON.stringify(pixelBounds.min),document.getElementById("ogby").innerHTML=JSON.stringify(pixelBounds.max)},resetHeading:function(e){null!==e.heading&&this.setBearing(e.heading)},locate:function(){this._map.locate({setView:!0,enableHighAccuracy:!0})}};
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "leaflet-rotate",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "A Leaflet plugin that allows to add rotation functionality to map tiles",
5
+ "type": "module",
5
6
  "main": "dist/leaflet-rotate.js",
7
+ "browser": "dist/leaflet-rotate.js",
6
8
  "module": "src/index.js",
7
9
  "scripts": {
8
10
  "test": "echo \"Error: no test specified\" && exit 1",
9
11
  "build": "rollup -c build/rollup.config.js",
10
- "watch": "rollup -c build/rollup.config.js --watch",
12
+ "dev": "rollup -c build/rollup.config.js --watch",
13
+ "watch": "npm run dev",
11
14
  "version": "npm run build && git add -A dist"
12
15
  },
13
16
  "repository": {
@@ -45,12 +48,12 @@
45
48
  },
46
49
  "homepage": "https://github.com/Raruto/leaflet-rotate#readme",
47
50
  "devDependencies": {
48
- "rollup": "^1.31.0",
49
- "rollup-plugin-commonjs": "^10.1.0",
50
- "rollup-plugin-node-resolve": "^5.2.0",
51
- "rollup-plugin-terser": "^7.0.2"
51
+ "rollup": "^3.10.0",
52
+ "@rollup/plugin-commonjs": "^24.0.0",
53
+ "@rollup/plugin-node-resolve": "^15.0.1",
54
+ "@rollup/plugin-terser": "^0.3.0"
52
55
  },
53
56
  "peerDependencies": {
54
- "leaflet": "^1.7.0"
57
+ "leaflet": "^1.9.3"
55
58
  }
56
59
  }
@@ -1,11 +1,13 @@
1
1
  /**
2
- * L.Control.Rotate
2
+ * A tri-state control for map rotation, states are:
3
+ *
4
+ * - Locked (default)
5
+ * - Unlocked (user can pinch-rotate)
6
+ * - Follow (rotation follows device orientation, if available)
7
+ *
8
+ * @typedef L.Control.Rotate
3
9
  */
4
10
 
5
- // A tri-state control for map rotation. States are:
6
- // Locked (default)
7
- // Unlocked (user can pinch-rotate)
8
- // Follow (rotation follows device orientation, if available)
9
11
  L.Control.Rotate = L.Control.extend({
10
12
 
11
13
  options: {
@@ -35,6 +37,7 @@ L.Control.Rotate = L.Control.extend({
35
37
  link.appendChild(arrow);
36
38
  link.href = '#';
37
39
  link.title = 'Rotate map';
40
+ // link.draggable = false;
38
41
 
39
42
  L.DomEvent
40
43
  .on(link, 'dblclick', L.DomEvent.stopPropagation)
@@ -63,7 +66,7 @@ L.Control.Rotate = L.Control.extend({
63
66
  },
64
67
 
65
68
  _handleMouseDown: function(e) {
66
- L.DomEvent.stopPropagation(e);
69
+ L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
67
70
  this.dragging = true;
68
71
  this.dragstartX = e.pageX;
69
72
  this.dragstartY = e.pageY;
@@ -73,7 +76,7 @@ L.Control.Rotate = L.Control.extend({
73
76
  },
74
77
 
75
78
  _handleMouseUp: function(e) {
76
- L.DomEvent.stopPropagation(e);
79
+ L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
77
80
  this.dragging = false;
78
81
 
79
82
  L.DomEvent
@@ -1,6 +1,9 @@
1
1
  /**
2
- * L.DomUtil
2
+ * @external L.DomUtil
3
+ *
4
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/DomUtil.js
3
5
  */
6
+
4
7
  const domUtilProto = L.extend({}, L.DomUtil);
5
8
 
6
9
  L.extend(L.DomUtil, {
@@ -1,10 +1,13 @@
1
1
  /**
2
- * L.Draggable
2
+ * @external L.Draggable
3
+ *
4
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/Draggable.js
3
5
  */
6
+
4
7
  L.Draggable.include({
5
8
 
6
- updateMapBearing: function(mapBearing) {
7
- this._mapBearing = mapBearing;
8
- },
9
+ // updateMapBearing: function(mapBearing) {
10
+ // this._mapBearing = mapBearing;
11
+ // },
9
12
 
10
- });
13
+ });
@@ -1,28 +1,32 @@
1
1
  /**
2
- * L.Point
2
+ * @external L.Point
3
+ *
4
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/geometry/Point.js
3
5
  */
6
+
4
7
  L.extend(L.Point.prototype, {
5
8
 
6
- // Rotate around (0,0) by applying the 2D rotation matrix:
7
- // ⎡ x' ⎤ = ⎡ cos θ -sin θ ⎤ ⎡ x ⎤
8
- // ⎣ y' ⎦ ⎣ sin θ cos θ ⎦ ⎣ y ⎦
9
- // Theta must be given in radians.
9
+ /**
10
+ * Rotate around (0,0) by applying the 2D rotation matrix:
11
+ *
12
+ * ⎡ x' ⎤ = ⎡ cos θ -sin θ ⎤ ⎡ x ⎤
13
+ * ⎣ y' ⎦ ⎣ sin θ cos θ ⎦ ⎣ y ⎦
14
+ *
15
+ * @param theta must be given in radians.
16
+ */
10
17
  rotate: function(theta) {
11
- if (!theta) { return this; }
12
- var sinTheta = Math.sin(theta);
13
- var cosTheta = Math.cos(theta);
14
-
15
- return new L.Point(
16
- this.x * cosTheta - this.y * sinTheta,
17
- this.x * sinTheta + this.y * cosTheta
18
- );
18
+ return this.rotateFrom(theta, new L.Point(0,0))
19
19
  },
20
20
 
21
- // Rotate around (pivot.x, pivot.y) by:
22
- // 1. subtract (pivot.x, pivot.y)
23
- // 2. rotate around (0, 0)
24
- // 3. add (pivot.x, pivot.y) back
25
- // same as `this.subtract(pivot).rotate(theta).add(pivot)`
21
+ /**
22
+ * Rotate around (pivot.x, pivot.y) by:
23
+ *
24
+ * 1. subtract (pivot.x, pivot.y)
25
+ * 2. rotate around (0, 0)
26
+ * 3. add (pivot.x, pivot.y) back
27
+ *
28
+ * same as `this.subtract(pivot).rotate(theta).add(pivot)`
29
+ */
26
30
  rotateFrom: function(theta, pivot) {
27
31
  if (!theta) { return this; }
28
32
  var sinTheta = Math.sin(theta);
package/src/index.js CHANGED
@@ -1,12 +1,14 @@
1
1
  /**
2
- * Based on Leaflet structure (ver. 1.7)
2
+ * @external L
3
3
  *
4
- * @see https://github.com/Leaflet/Leaflet/blob/master/src/Leaflet.js
4
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/Leaflet.js
5
5
  */
6
6
 
7
7
  // import {version} from '../package.json';
8
8
  // export {version};
9
9
 
10
+ // control
11
+ // export * from './core/index';
10
12
 
11
13
  // core
12
14
  // export * from './core/index';
@@ -41,5 +43,5 @@ export * from './map/handler/TouchRotate';
41
43
  export * from './map/handler/ShiftKeyRotate';
42
44
  export * from './map/handler/TouchZoom';
43
45
 
44
- // control
46
+ // custom controls
45
47
  export * from './control/Rotate';
@@ -1,6 +1,9 @@
1
1
  /**
2
- * L.DivOverlay
2
+ * @external L.DivOverlay
3
+ *
4
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/DivOverlay.js
3
5
  */
6
+
4
7
  const divOverlayProto = L.extend({}, L.DivOverlay.prototype);
5
8
 
6
9
  L.DivOverlay.include({
@@ -10,28 +13,17 @@ L.DivOverlay.include({
10
13
  },
11
14
 
12
15
  _updatePosition: function() {
13
- if (!this._map) { return; }
14
-
15
- var pos = this._map.latLngToLayerPoint(this._latlng),
16
- offset = L.point(this.options.offset),
17
- anchor = this._getAnchor();
18
-
19
- if (this._zoomAnimated) {
20
- // TODO: use divOverlayProto._updatePosition
21
- if (this._map._rotate) {
22
- pos = this._map.rotatedPointToMapPanePoint(pos);
23
- }
24
- L.DomUtil.setPosition(this._container, pos.add(anchor));
25
- } else {
26
- offset = offset.add(pos).add(anchor);
16
+ // 0. update anchor (leaflet v1.9.3)
17
+ divOverlayProto._updatePosition.call(this);
18
+ // 1. subtract anchor
19
+ // 2. rotate element
20
+ // 3. restore anchor
21
+ if (this._map && this._map._rotate && this._zoomAnimated) {
22
+ var anchor = this._getAnchor();
23
+ var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
24
+ L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
27
25
  }
28
26
 
29
- var bottom = this._containerBottom = -offset.y,
30
- left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
31
-
32
- // bottom position the popup in case the height of the popup changes (images loading etc)
33
- this._container.style.bottom = bottom + 'px';
34
- this._container.style.left = left + 'px';
35
27
  },
36
28
 
37
29
  });