leaflet-rotate 0.2.8 → 0.4.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.
Files changed (48) hide show
  1. package/.github/workflows/ci.yml +21 -0
  2. package/README.md +6 -2
  3. package/build/build.js +69 -0
  4. package/build/dev.js +24 -0
  5. package/build/server.js +104 -0
  6. package/build/test.js +18 -0
  7. package/cucumber.mjs +5 -0
  8. package/dist/leaflet-rotate-src.js +1425 -1853
  9. package/dist/leaflet-rotate-src.js.map +7 -1
  10. package/dist/leaflet-rotate.js +1 -1
  11. package/dist/leaflet-rotate.js.map +7 -1
  12. package/lib/debug.js +98 -69
  13. package/lib/debug.min.js +1 -1
  14. package/misc/leaflet-heat-rotate.js +96 -0
  15. package/misc/loremIpsum.js +1 -1
  16. package/misc/places.js +1 -1
  17. package/misc/route.js +1 -1
  18. package/package.json +10 -17
  19. package/src/control/Rotate.js +25 -25
  20. package/src/dom/DomUtil.js +31 -47
  21. package/src/dom/Draggable.js +1 -1
  22. package/src/geometry/Point.js +16 -7
  23. package/src/layer/DivOverlay.js +21 -7
  24. package/src/layer/Popup.js +15 -13
  25. package/src/layer/Tooltip.js +5 -5
  26. package/src/layer/marker/Icon.js +8 -8
  27. package/src/layer/marker/Marker.js +32 -18
  28. package/src/layer/tile/GridLayer.js +4 -4
  29. package/src/layer/vector/Renderer.js +51 -7
  30. package/src/map/Map.js +121 -57
  31. package/src/map/handler/CompassBearing.js +10 -8
  32. package/src/map/handler/ContainerMutation.js +2 -2
  33. package/src/map/handler/ShiftKeyRotate.js +4 -4
  34. package/src/map/handler/TouchGestures.js +36 -22
  35. package/src/map/handler/TouchRotate.js +2 -2
  36. package/src/map/handler/TouchZoom.js +4 -4
  37. package/test/features/example.feature +92 -0
  38. package/test/features/gestures.feature +33 -0
  39. package/test/features/overlays.feature +58 -0
  40. package/test/features/rotation.feature +36 -0
  41. package/test/index.html +59 -22
  42. package/test/steps/bearing.steps.js +235 -0
  43. package/test/steps/example.steps.js +424 -0
  44. package/test/steps/gestures.steps.js +145 -0
  45. package/test/steps/overlays.steps.js +427 -0
  46. package/test/support/hooks.js +92 -0
  47. package/build/rollup.config.js +0 -34
  48. package/test/setup/http_server.js +0 -104
@@ -7,6 +7,16 @@
7
7
  * @typedef L.Map.TouchGestures
8
8
  */
9
9
 
10
+ function touchToContainerPoint(map, touch) {
11
+ const container = map.getContainer(),
12
+ rect = container.getBoundingClientRect();
13
+
14
+ return new L.Point(
15
+ touch.clientX - rect.left - container.clientLeft,
16
+ touch.clientY - rect.top - container.clientTop,
17
+ );
18
+ }
19
+
10
20
  L.Map.mergeOptions({
11
21
 
12
22
  /**
@@ -22,27 +32,27 @@ L.Map.mergeOptions({
22
32
 
23
33
  L.Map.TouchGestures = L.Handler.extend({
24
34
 
25
- initialize: function(map) {
35
+ initialize(map) {
26
36
  this._map = map;
27
37
  this.rotate = !!this._map.options.touchRotate;
28
38
  this.zoom = !!this._map.options.touchZoom;
29
39
  },
30
40
 
31
- addHooks: function() {
41
+ addHooks() {
32
42
  L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);
33
43
  },
34
44
 
35
- removeHooks: function() {
45
+ removeHooks() {
36
46
  L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);
37
47
  },
38
48
 
39
- _onTouchStart: function(e) {
40
- var map = this._map;
49
+ _onTouchStart(e) {
50
+ const map = this._map;
41
51
 
42
52
  if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming || this._rotating) { return; }
43
53
 
44
- var p1 = map.mouseEventToContainerPoint(e.touches[0]),
45
- p2 = map.mouseEventToContainerPoint(e.touches[1]),
54
+ const p1 = touchToContainerPoint(map, e.touches[0]),
55
+ p2 = touchToContainerPoint(map, e.touches[1]),
46
56
  vector = p1.subtract(p2);
47
57
 
48
58
  this._centerPoint = map.getSize()._divideBy(2);
@@ -79,19 +89,19 @@ L.Map.TouchGestures = L.Handler.extend({
79
89
  L.DomEvent.preventDefault(e);
80
90
  },
81
91
 
82
- _onTouchMove: function(e) {
92
+ _onTouchMove(e) {
83
93
  if (!e.touches || e.touches.length !== 2 || !(this._zooming || this._rotating)) { return; }
84
94
 
85
- var map = this._map,
86
- p1 = map.mouseEventToContainerPoint(e.touches[0]),
87
- p2 = map.mouseEventToContainerPoint(e.touches[1]),
95
+ const map = this._map,
96
+ p1 = touchToContainerPoint(map, e.touches[0]),
97
+ p2 = touchToContainerPoint(map, e.touches[1]),
88
98
  vector = p1.subtract(p2),
89
- scale = p1.distanceTo(p2) / this._startDist,
90
- delta;
99
+ scale = p1.distanceTo(p2) / this._startDist;
100
+ let delta;
91
101
 
92
102
  if (this._rotating) {
93
- var theta = Math.atan(vector.x / vector.y);
94
- var bearingDelta = (theta - this._startTheta) * L.DomUtil.RAD_TO_DEG;
103
+ const theta = Math.atan(vector.x / vector.y);
104
+ let bearingDelta = (theta - this._startTheta) * (180 / Math.PI);
95
105
  if (vector.y < 0) { bearingDelta += 180; }
96
106
  if (bearingDelta) {
97
107
  /**
@@ -123,7 +133,7 @@ L.Map.TouchGestures = L.Handler.extend({
123
133
  delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
124
134
  if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
125
135
 
126
- var alpha = -map.getBearing() * L.DomUtil.DEG_TO_RAD;
136
+ const alpha = -map.getBearing() * (Math.PI / 180);
127
137
 
128
138
  this._center = map.unproject(map.project(this._pinchStartLatLng).subtract(delta.rotate(alpha)));
129
139
  }
@@ -135,15 +145,21 @@ L.Map.TouchGestures = L.Handler.extend({
135
145
  this._moved = true;
136
146
  }
137
147
 
138
- L.Util.cancelAnimFrame(this._animRequest);
148
+ const moveFn = map._move.bind(map, this._center, this._zoom, { pinch: true, round: false }, undefined);
149
+ moveFn();
139
150
 
140
- var moveFn = map._move.bind(map, this._center, this._zoom, { pinch: true, round: false }, undefined);
141
- this._animRequest = L.Util.requestAnimFrame(moveFn, this, true);
151
+ if (this.zoom) {
152
+ if (map.options.zoomAnimation) {
153
+ map._animateZoomNoDelay(this._center, map._limitZoom(this._zoom));
154
+ } else {
155
+ map._resetView(this._center, map._limitZoom(this._zoom));
156
+ }
157
+ }
142
158
 
143
159
  L.DomEvent.preventDefault(e);
144
160
  },
145
161
 
146
- _onTouchEnd: function() {
162
+ _onTouchEnd() {
147
163
  if (!this._moved || !(this._zooming || this._rotating)) {
148
164
  this._zooming = false;
149
165
  return;
@@ -151,8 +167,6 @@ L.Map.TouchGestures = L.Handler.extend({
151
167
 
152
168
  this._zooming = false;
153
169
  this._rotating = false;
154
- L.Util.cancelAnimFrame(this._animRequest);
155
-
156
170
  L.DomEvent
157
171
  .off(document, 'touchmove', this._onTouchMove, this)
158
172
  .off(document, 'touchend touchcancel', this._onTouchEnd, this);
@@ -17,12 +17,12 @@ L.Map.mergeOptions({
17
17
 
18
18
  L.Map.TouchRotate = L.Handler.extend({
19
19
 
20
- addHooks: function() {
20
+ addHooks() {
21
21
  this._map.touchGestures.enable();
22
22
  this._map.touchGestures.rotate = true;
23
23
  },
24
24
 
25
- removeHooks: function() {
25
+ removeHooks() {
26
26
  this._map.touchGestures.rotate = false;
27
27
  },
28
28
 
@@ -34,14 +34,14 @@ L.Map.mergeOptions({
34
34
 
35
35
  L.Map.TouchZoom = L.Handler.extend({
36
36
 
37
- addHooks: function() {
38
- L.DomUtil.addClass(this._map._container, 'leaflet-touch-zoom');
37
+ addHooks() {
38
+ this._map._container.classList.add('leaflet-touch-zoom');
39
39
  this._map.touchGestures.enable();
40
40
  this._map.touchGestures.zoom = true;
41
41
  },
42
42
 
43
- removeHooks: function() {
44
- L.DomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');
43
+ removeHooks() {
44
+ this._map._container.classList.remove('leaflet-touch-zoom');
45
45
  this._map.touchGestures.zoom = false;
46
46
  },
47
47
 
@@ -0,0 +1,92 @@
1
+ Feature: Rotating a Leaflet map
2
+ Background:
3
+ Given the example page is open
4
+
5
+ @issue-55 @issue-58
6
+ Scenario: Leaflet heat redraws stay aligned after map rotation
7
+ When I redraw a heat layer after rotating, panning, and zooming
8
+ Then the heat points remain aligned with their coordinates
9
+
10
+ @issue-11
11
+ Scenario: The default rotate control appears only when the map is rotated
12
+ When I rotate a map with the default rotate control
13
+ Then the default rotate control visibility follows the bearing
14
+
15
+ @issue-13
16
+ Scenario: Dragging the rotate control changes the map bearing
17
+ When I drag the rotate control
18
+ Then the map bearing follows the control drag
19
+
20
+ @issue-44
21
+ Scenario: The compass control requests device-orientation permission
22
+ When I activate compass mode on a permission-based device
23
+ Then device-orientation permission is requested
24
+
25
+ @issue-7
26
+ Scenario: Compass headings handle absolute, iOS, and unavailable readings
27
+ When I apply compass heading readings
28
+ Then valid compass readings update bearing and invalid readings are ignored
29
+
30
+ @issue-33 @issue-41
31
+ Scenario: Shift-wheel rotation can be disabled without disabling wheel zoom
32
+ When I use shift-wheel rotation with the handler disabled
33
+ Then shift-wheel input zooms without changing the map bearing
34
+
35
+ @debugger
36
+ Scenario: Debugger rotation presets and keyboard slider stay synchronized
37
+ When I use the debugger rotation controls
38
+ Then every debugger rotation control matches the map bearing
39
+
40
+ @debugger
41
+ Scenario: Debugger bounds padding updates from the keyboard
42
+ When I change the debugger bounds padding from the keyboard
43
+ Then the displayed bounds use the selected padding
44
+
45
+ @debugger
46
+ Scenario: Debugger geometry follows an offset and resized map
47
+ When I inspect debugger geometry after resizing and moving the map
48
+ Then the debugger reports the current map geometry
49
+
50
+ @example-ui
51
+ Scenario: Example base-layer radios select one layer
52
+ When I switch between the example base layers
53
+ Then exactly the selected base layer is visible
54
+
55
+ @example-ui
56
+ Scenario: Example zoom controls change and restore the zoom
57
+ When I use the example zoom controls
58
+ Then the zoom returns to its starting level
59
+
60
+ @example-ui
61
+ Scenario: Debugger rotates all example markers
62
+ When I rotate the example markers from the debugger
63
+ Then every example marker has a new rotation
64
+
65
+ @example-ui
66
+ Scenario Outline: Example destination buttons fly to the selected place
67
+ When I select "<place>" from the example page
68
+ Then the map settles at "<place>" at zoom 10
69
+
70
+ Examples:
71
+ | place |
72
+ | Kyiv |
73
+ | London |
74
+ | San Francisco |
75
+ | Washington |
76
+ | Trondheim |
77
+
78
+ @example-ui
79
+ Scenario Outline: Example bounds buttons fit the selected layer
80
+ When I fit the "<layer>" bounds from the example page
81
+ Then the map view contains the "<layer>" bounds
82
+
83
+ Examples:
84
+ | layer |
85
+ | circle |
86
+ | polygon |
87
+ | path |
88
+
89
+ @example-ui
90
+ Scenario: Rectangle button resets zoom and fits the rectangle
91
+ When I fit the rectangle from the example page
92
+ Then the rectangle is fitted at zoom 14
@@ -0,0 +1,33 @@
1
+ Feature: Rotating a Leaflet map
2
+ Background:
3
+ Given the example page is open
4
+
5
+ @issue-43
6
+ Scenario: Pinch zoom refreshes paths during the gesture
7
+ When I move a two-finger pinch gesture
8
+ Then the zoom transition ends before the gesture ends
9
+
10
+ @issue-43
11
+ Scenario: Vector paths follow a rotated two-finger gesture
12
+ When I rotate and zoom two fingers over a vector path
13
+ Then the vector path remains aligned during the gesture
14
+
15
+ @issue-56
16
+ Scenario: Dragging a max-bounds marker preserves callback coordinates on a rotated map
17
+ When I drag a constrained marker on a rotated map
18
+ Then its drag callbacks match the marker and pointer coordinates
19
+
20
+ @issue-60
21
+ Scenario: Interactive layers stay aligned while dragging and rotating the map
22
+ When I drag a map with interactive layers while rotated
23
+ Then the marker and vector path stay at their geographic coordinates
24
+
25
+ @issue-59 @issue-52
26
+ Scenario: Focusing an in-bounds point does not pan an offset rotated map
27
+ When I focus a point near the left edge of an offset map
28
+ Then the map center remains unchanged
29
+
30
+ @issue-65
31
+ Scenario: Two-finger rotation can be disabled
32
+ When I disable touch rotation and rotate two fingers
33
+ Then the map bearing remains unchanged
@@ -0,0 +1,58 @@
1
+ Feature: Rotating a Leaflet map
2
+ Background:
3
+ Given the example page is open
4
+
5
+ @issue-4 @issue-35 @issue-62
6
+ Scenario: Rotated road labels stay upright and aligned with the map
7
+ When I rotate a label marker with the view
8
+ Then the label remains upright while following the map bearing
9
+
10
+ @issue-2 @issue-54
11
+ Scenario: GeoJSON in a custom pane rotates with the map
12
+ When I add GeoJSON to a custom pane inside the rotate pane
13
+ Then the custom-pane GeoJSON stays aligned with its coordinates
14
+
15
+ @issue-32
16
+ Scenario: Canvas overlays rotate with the map
17
+ When I render a Canvas vector layer on a rotated map
18
+ Then the Canvas renderer belongs to the rotating pane
19
+
20
+ @issue-57
21
+ Scenario: SVG paths stay aligned near the latitude limit without zoom animation
22
+ When I zoom an SVG path near the latitude limit
23
+ Then the path stays at its geographic coordinate
24
+
25
+ @issue-15 @issue-51
26
+ Scenario: Popup tip remains anchored when zoom animation is disabled
27
+ When I open a popup on a rotated map without zoom animation
28
+ Then the popup tip stays at the marker coordinate
29
+
30
+ @issue-23
31
+ Scenario: Removing the rotate control detaches its map listener
32
+ When I remove the rotate control and change the map bearing
33
+ Then the map rotates without invoking the removed control
34
+
35
+ @issue-3
36
+ Scenario: Markers remain non-draggable unless requested
37
+ When I create default and draggable markers
38
+ Then only the requested marker is draggable
39
+
40
+ @issue-46
41
+ Scenario: Click coordinates match the rotated map location
42
+ When I click a rotated map at a known container point
43
+ Then the click event reports the matching geographic coordinate
44
+
45
+ @issue-18 @issue-59
46
+ Scenario: Focusing an in-bounds marker does not pan the rotated map
47
+ When I focus a marker near the edge of a rotated map
48
+ Then the map center remains unchanged
49
+
50
+ @issue-51
51
+ Scenario: Opening an edge popup pans only enough to keep it visible
52
+ When I open a popup near the edge of a rotated map
53
+ Then the popup stays inside the map without a large jump
54
+
55
+ @issue-52
56
+ Scenario: Opening a popup in a second rotated map does not move it
57
+ When I open a popup in a second rotated map with map listeners
58
+ Then the second map center remains unchanged and its popup stays anchored
@@ -0,0 +1,36 @@
1
+ Feature: Rotating a Leaflet map
2
+ Background:
3
+ Given the example page is open
4
+
5
+ @issue-43
6
+ Scenario: Rotation is enabled
7
+ Then rotation is enabled on the map
8
+
9
+ @issue-19
10
+ Scenario: Bearing survives zoom
11
+ When I set the bearing to 10 and zoom in twice
12
+ Then the bearing remains 10
13
+
14
+ @issue-19
15
+ Scenario: Bearing survives setting the view
16
+ When I set the bearing to 10 and change the view twice
17
+ Then the bearing remains 10
18
+
19
+ @issue-63
20
+ Scenario: Bearing can animate
21
+ When I animate the bearing to 90 degrees
22
+ Then the bearing reaches 90 degrees gradually
23
+
24
+ @issue-25
25
+ Scenario: Fit bounds zoom is stable
26
+ When I fit the same bounds twice
27
+ Then the map zoom is 14 both times
28
+
29
+ @issue-28
30
+ Scenario: Panning inside a marker keeps its bounds stable
31
+ When I pan inside the Trondheim marker
32
+ Then panning inside keeps the expected bounds
33
+
34
+ @issue-34
35
+ Scenario: Draggable marker listeners are not duplicated
36
+ Then the draggable marker has one drag listener and one drag-end listener
package/test/index.html CHANGED
@@ -6,18 +6,12 @@
6
6
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7
7
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
8
8
 
9
- <!-- Leaflet JS / CSS -->
10
- <script src="https://unpkg.com/leaflet@1.9/dist/leaflet-src.js"></script>
11
- <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9/dist/leaflet.css">
12
-
13
- <!-- Leaflet-Rotate -->
14
- <script src="../dist/leaflet-rotate-src.js"></script>
9
+ <link id="leaflet-css" rel="stylesheet">
15
10
 
16
11
  <!-- include some miscellaneous -->
17
12
  <script src="../misc/route.js"></script>
18
13
  <script src="../misc/places.js"></script>
19
14
  <script src="../misc/loremIpsum.js"></script>
20
- <script src="../lib/debug.js"></script>
21
15
 
22
16
  <style>
23
17
  #map {
@@ -36,6 +30,12 @@
36
30
 
37
31
  <body>
38
32
 
33
+ <label for="leaflet-version">Leaflet version:</label>
34
+ <select id="leaflet-version">
35
+ <option value="1">1.9.4</option>
36
+ <option value="2">2.0.0-alpha.1</option>
37
+ </select>
38
+
39
39
  <div id="map"></div>
40
40
 
41
41
  <hr>
@@ -61,8 +61,37 @@
61
61
  </p>
62
62
  </div>
63
63
 
64
- <script>
65
- var esri = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
64
+ <script type="module">
65
+ const versionSelect = document.getElementById('leaflet-version');
66
+ const params = new URLSearchParams(location.search);
67
+ versionSelect.value = params.get('leaflet') === '2' ? '2' : '1';
68
+ versionSelect.addEventListener('change', () => {
69
+ location.search = `?leaflet=${versionSelect.value}`;
70
+ });
71
+
72
+ const loadScript = src => new Promise((resolve, reject) => {
73
+ const script = document.createElement('script');
74
+ script.src = src;
75
+ script.onload = resolve;
76
+ script.onerror = () => reject(new Error(`Could not load ${src}`));
77
+ document.head.appendChild(script);
78
+ });
79
+
80
+ const version = versionSelect.value;
81
+ document.getElementById('leaflet-css').href = version === '2'
82
+ ? 'https://unpkg.com/leaflet@2.0.0-alpha.1/dist/leaflet.css'
83
+ : 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
84
+
85
+ if (version === '2') {
86
+ globalThis.L = await import('https://unpkg.com/leaflet@2.0.0-alpha.1/dist/leaflet.js');
87
+ } else {
88
+ await loadScript('https://unpkg.com/leaflet@1.9.4/dist/leaflet-src.js');
89
+ }
90
+ await loadScript('../dist/leaflet-rotate-src.js');
91
+ await loadScript('../lib/debug.js');
92
+ const L = globalThis.L;
93
+
94
+ const esri = new L.TileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
66
95
  id: 'mapbox.streets',
67
96
  maxZoom: 24,
68
97
  maxNativeZoom: 18,
@@ -70,14 +99,14 @@
70
99
  // noWrap: true
71
100
  });
72
101
 
73
- var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
102
+ const osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
74
103
  maxZoom: 24,
75
104
  maxNativeZoom: 19,
76
105
  attribution: '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
77
106
  // noWrap: true
78
107
  });
79
108
 
80
- var map = L.map('map', {
109
+ const map = new L.Map('map', {
81
110
  center: [55, 10],
82
111
  zoom: 2,
83
112
  layers: [esri],
@@ -99,6 +128,9 @@
99
128
  touchRotate: true,
100
129
  // touchZoom: true
101
130
  });
131
+ window.map = map;
132
+ window.esri = esri;
133
+ window.osm = osm;
102
134
 
103
135
  // map.setBearing(90);
104
136
  // map.touchRotate.enable();
@@ -111,17 +143,18 @@
111
143
  // map.rotateControl.setPosition('bottomleft');
112
144
  // map.setMaxBounds([[-90,-180], [90,180]]);
113
145
 
114
- var layers = L.control.layers({
115
- 'Empty': L.tileLayer(''),
146
+ const layers = new L.Control.Layers({
147
+ 'Empty': new L.TileLayer(''),
116
148
  'Streets': osm,
117
149
  'Satellite': esri,
118
150
  }, null, {
119
151
  collapsed: false
120
152
  }).addTo(map);
153
+ window.layers = layers;
121
154
 
122
- var markers = [];
123
- for (var i in places) {
124
- markers.push(L.marker(places[i], {
155
+ const markers = [];
156
+ for (const i in places) {
157
+ markers.push(new L.Marker(places[i], {
125
158
  draggable: true
126
159
  })
127
160
  .bindPopup('<b>' + i + '</b><br>' + loremIpsum)
@@ -133,30 +166,34 @@
133
166
  )
134
167
  .addTo(map));
135
168
  }
169
+ window.markers = markers;
136
170
 
137
- var path = L.polyline(route, {
138
- renderer: L.canvas()
171
+ const path = new L.Polyline(route, {
172
+ renderer: new L.Canvas()
139
173
  }).addTo(map);
174
+ window.path = path;
140
175
 
141
- var circle = L.circle([53, 4], 111111)
176
+ const circle = new L.Circle([53, 4], 111111)
142
177
  .addTo(map);
178
+ window.circle = circle;
143
179
 
144
- var polygon = L.polygon([
180
+ const polygon = new L.Polygon([
145
181
  [48, -3],
146
182
  [50, -4],
147
183
  [52, 4]
148
184
  ]).addTo(map);
185
+ window.polygon = polygon;
149
186
 
150
- const rectangle = L.rectangle([
187
+ const rectangle = new L.Rectangle([
151
188
  [60.81123, 25.71632],
152
189
  [60.81028, 25.73166],
153
190
  [60.7997, 25.72892],
154
191
  [60.80061, 25.71362]
155
192
  ]).addTo(map);
193
+ window.rectangle = rectangle;
156
194
 
157
195
  // Display some debug info
158
196
  L.Rotate.debug(map);
159
-
160
197
  </script>
161
198
 
162
199
  <a href="https://github.com/Raruto/leaflet-rotate" class="view-on-github" style="position: fixed;bottom: 10px;left: calc(50% - 60px);z-index: 9999;"> <img alt="View on Github" src="https://raruto.github.io/img/view-on-github.png" title="View on Github"