@raruto/leaflet-elevation 2.2.8 → 2.3.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/README.md +9 -4
- package/dist/leaflet-elevation.js +44 -27
- package/dist/leaflet-elevation.js.map +1 -1
- package/dist/leaflet-elevation.min.js +1 -1
- package/dist/leaflet-elevation.min.js.map +1 -1
- package/libs/leaflet-edgescale.js +636 -0
- package/libs/leaflet-edgescale.min.js +1 -0
- package/package.json +72 -69
- package/src/control.js +17 -1
- package/src/options.js +1 -0
- package/src/utils.spec.js +50 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023, GPL-3.0+ Project, Raruto
|
|
3
|
+
*
|
|
4
|
+
* This file is free software: you may copy, redistribute and/or modify it
|
|
5
|
+
* under the terms of the GNU General Public License as published by the
|
|
6
|
+
* Free Software Foundation, either version 2 of the License, or (at your
|
|
7
|
+
* option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* This file is distributed in the hope that it will be useful, but
|
|
10
|
+
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
+
* General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with this program. If not, see .
|
|
16
|
+
*
|
|
17
|
+
* This file incorporates work covered by the following copyright and
|
|
18
|
+
* permission notice:
|
|
19
|
+
*
|
|
20
|
+
* Copyright (c) GPL-3.0+ Project - 2018- Dražen Tutić - https://github.com/dtutic/Leaflet.EdgeScaleBar
|
|
21
|
+
* Copyright (c) MIT License (MIT) - 2015- Xisco Guaita - https://github.com/xguaita/Leaflet.MapCenterCoord
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Original source: https://github.com/xguaita/Leaflet.MapCenterCoord
|
|
26
|
+
*/
|
|
27
|
+
L.Control.EdgeScale = L.Control.extend({
|
|
28
|
+
|
|
29
|
+
// Defaults
|
|
30
|
+
options: {
|
|
31
|
+
position: 'bottomleft',
|
|
32
|
+
icon: true,
|
|
33
|
+
coords: true,
|
|
34
|
+
bar: true,
|
|
35
|
+
onMove: true,
|
|
36
|
+
template: '{y} | {x}', // https://en.wikipedia.org/wiki/ISO_6709
|
|
37
|
+
projected: false,
|
|
38
|
+
formatProjected: '#.##0,000',
|
|
39
|
+
latlngFormat: 'DD', // DD, DM, DMS
|
|
40
|
+
latlngDesignators: true,
|
|
41
|
+
latLngFormatter: undefined,
|
|
42
|
+
iconStyle: {
|
|
43
|
+
background: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xml:space='preserve' viewBox='0 0 100 100'%3E%3Cg stroke='%23fff'%3E%3Ccircle cx='50' cy='50.2' r='3.9' stroke-width='2' /%3E%3Cpath stroke-width='3' d='M5 54h32a4 4 0 1 0 0-8H5a4 4 0 1 0 0 8z M54 5a4 4 0 1 0-8 0v32a4 4 0 1 0 8 0V5z M99 50c0-2-2-4-4-4H63a4 4 0 1 0 0 8h32c2 0 4-1 4-4zM46 95a4 4 0 1 0 8 0V64a4 4 0 1 0-8 0v31z'/%3E%3C/g%3E%3C/svg%3E%0A")`,
|
|
44
|
+
width: '24px',
|
|
45
|
+
height: '24px',
|
|
46
|
+
left: 'calc(50% - 12px)',
|
|
47
|
+
top: 'calc(50% - 12px)',
|
|
48
|
+
content: '',
|
|
49
|
+
display: 'block',
|
|
50
|
+
position: 'absolute',
|
|
51
|
+
zIndex: 999,
|
|
52
|
+
pointerEvents: 'none',
|
|
53
|
+
},
|
|
54
|
+
containerStyle: {
|
|
55
|
+
backgroundColor: 'rgba(255, 255, 255, 0.7)',
|
|
56
|
+
boxShadow: '0 0 5px #bbb',
|
|
57
|
+
borderRadius: '3px',
|
|
58
|
+
padding: '3px 2px',
|
|
59
|
+
color: '#333',
|
|
60
|
+
font: '11px/1.5 Consolas, monaco, monospace',
|
|
61
|
+
writingMode: 'vertical-lr',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
initialize: function(options) {
|
|
66
|
+
L.setOptions(this, options);
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
onAdd: function (map) {
|
|
70
|
+
|
|
71
|
+
if (this.options.bar) {
|
|
72
|
+
this._scaleBar = (new L.Control.EdgeScale.Layer(true === this.options.bar ? {} : this.options.bar)).addTo(map);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// create a DOM element and put it into overlayPane
|
|
76
|
+
if (this.options.icon) {
|
|
77
|
+
this._icon = L.DomUtil.create('div', 'leaflet-crosshair');
|
|
78
|
+
Object.assign(this._icon.style, this.options.iconStyle);
|
|
79
|
+
map.getContainer().insertBefore(this._icon, map.getContainer().firstChild);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Control container
|
|
83
|
+
this._container = L.DomUtil.create('div', 'leaflet-control-mapcentercoord');
|
|
84
|
+
|
|
85
|
+
Object.assign(this._container.style, this.options.containerStyle);
|
|
86
|
+
|
|
87
|
+
if (!this.options.coords) {
|
|
88
|
+
this._container.style.display = 'none';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
L.DomEvent.disableClickPropagation(this._container);
|
|
92
|
+
|
|
93
|
+
this._container.innerHTML = this._getMapCenterCoord();
|
|
94
|
+
|
|
95
|
+
// Add events listeners for updating coordinates & icon's position
|
|
96
|
+
map.on('move', this._onMapMove, this);
|
|
97
|
+
map.on('moveend', this._onMapMove, this);
|
|
98
|
+
|
|
99
|
+
return this._container;
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
onRemove: function (map) {
|
|
103
|
+
if (this.options.bar) {
|
|
104
|
+
this._scaleBar.remove();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// remove icon's DOM elements and listeners
|
|
108
|
+
if (this.options.icon) {
|
|
109
|
+
map.getContainer().removeChild(this._icon);
|
|
110
|
+
}
|
|
111
|
+
map.off('move', this._onMapMove, this);
|
|
112
|
+
map.off('moveend', this._onMapMove, this);
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// update coordinates
|
|
116
|
+
_onMapMove: function (e) {
|
|
117
|
+
if (this.options.onMove || 'moveend' === e.type) {
|
|
118
|
+
this._container.innerHTML = this._getMapCenterCoord();
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
_getMapCenterCoord: function () {
|
|
123
|
+
const center = this._map.getCenter();
|
|
124
|
+
return this.options.projected
|
|
125
|
+
? this._getProjectedCoord(this._map.options.crs.project(center))
|
|
126
|
+
: this._getLatLngCoord(center);
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
_getProjectedCoord: function (center) {
|
|
130
|
+
return L.Util.template(
|
|
131
|
+
this.options.template,
|
|
132
|
+
{
|
|
133
|
+
x: this._format(this.options.formatProjected, center.x),
|
|
134
|
+
y: this._format(this.options.formatProjected, center.y)
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
_getLatLngCoord: function (latLng) {
|
|
140
|
+
|
|
141
|
+
const { latLngFormatter, latlngFormat, latlngDesignators: designators } = this.options;
|
|
142
|
+
|
|
143
|
+
if (undefined !== latLngFormatter ) {
|
|
144
|
+
return latLngFormatter(latLng.lat, latLng.lng);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let lat, lng, deg, min;
|
|
148
|
+
|
|
149
|
+
// make a copy of center so we aren't affecting leaflet's internal state
|
|
150
|
+
let center = {
|
|
151
|
+
lat: latLng.lat,
|
|
152
|
+
lng: latLng.lng,
|
|
153
|
+
lng_neg: latLng.lng < 0,
|
|
154
|
+
lat_neg: latLng.lat < 0,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// 180 degrees & negative
|
|
158
|
+
if (center.lng < 0) {
|
|
159
|
+
center.lng = Math.abs(center.lng);
|
|
160
|
+
}
|
|
161
|
+
if (center.lng > 180) {
|
|
162
|
+
center.lng = 360 - center.lng;
|
|
163
|
+
center.lng_neg = !center.lng_neg;
|
|
164
|
+
}
|
|
165
|
+
if (center.lat < 0) {
|
|
166
|
+
center.lat = Math.abs(center.lat);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// format
|
|
170
|
+
if ('DM' === latlngFormat) {
|
|
171
|
+
deg = parseInt(center.lng);
|
|
172
|
+
lng = deg + 'º ' + this._format('00.000', (center.lng - deg) * 60) + "'";
|
|
173
|
+
deg = parseInt(center.lat);
|
|
174
|
+
lat = deg + 'º ' + this._format('00.000', (center.lat - deg) * 60) + "'";
|
|
175
|
+
} else if ('DMS' === latlngFormat) {
|
|
176
|
+
deg = parseInt(center.lng);
|
|
177
|
+
min = (center.lng - deg) * 60;
|
|
178
|
+
lng = deg + 'º ' + this._format('00', parseInt(min)) + "' " + this._format('00.0', (min - parseInt(min)) * 60) + "''";
|
|
179
|
+
deg = parseInt(center.lat);
|
|
180
|
+
min = (center.lat - deg) * 60;
|
|
181
|
+
lat = deg + 'º ' + this._format('00', parseInt(min)) + "' " + this._format('00.0', (min - parseInt(min)) * 60) + "''";
|
|
182
|
+
} else { // 'DD'
|
|
183
|
+
lng = this._format('#0.00000', center.lng) + 'º';
|
|
184
|
+
lat = this._format('##0.00000', center.lat) + 'º';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return L.Util.template(this.options.template, {
|
|
188
|
+
x: (!designators && center.lng_neg ? '-' : '') + lng + (designators ? (center.lng_neg ? ' W' : ' E') : ''),
|
|
189
|
+
y: (!designators && center.lat_neg ? '-' : '') + lat + (designators ? (center.lat_neg ? ' S' : ' N') : '')
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* IntegraXor Web SCADA - JavaScript Number Formatter
|
|
195
|
+
*
|
|
196
|
+
* @see https://code.google.com/p/javascript-number-formatter
|
|
197
|
+
* @authors KPL, KHL
|
|
198
|
+
*/
|
|
199
|
+
_format: function (m, v) {
|
|
200
|
+
if (!m || isNaN(+v)) {
|
|
201
|
+
return v; // return as it is.
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
v = m.charAt(0) == '-' ? -v : +v; // convert any string to number according to formation sign.
|
|
205
|
+
let isNegative = v < 0 ? v = -v : 0; // process only abs(), and turn on flag.
|
|
206
|
+
|
|
207
|
+
let result = m.match(/[^\d\-\+#]/g); // search for separator for grp & decimal, anything not digit, not +/- sign, not #.
|
|
208
|
+
let Decimal = (result && result[result.length - 1]) || '.'; // treat the right most symbol as decimal
|
|
209
|
+
let Group = (result && result[1] && result[0]) || ','; // treat the left most symbol as group separator
|
|
210
|
+
|
|
211
|
+
m = m.split(Decimal); // split the decimal for the format string if any.
|
|
212
|
+
v = v.toFixed(m[1] && m[1].length); // Fix the decimal first, toFixed will auto fill trailing zero.
|
|
213
|
+
v = +(v) + ''; // convert number to string to trim off *all* trailing decimal zero(es)
|
|
214
|
+
|
|
215
|
+
let pos_trail_zero = m[1] && m[1].lastIndexOf('0'); // fill back any trailing zero according to format (look for last zero in format)
|
|
216
|
+
let part = v.split('.');
|
|
217
|
+
|
|
218
|
+
if (!part[1] || part[1] && part[1].length <= pos_trail_zero) { // integer will get !part[1]
|
|
219
|
+
v = (+v).toFixed(pos_trail_zero + 1);
|
|
220
|
+
}
|
|
221
|
+
let szSep = m[0].split(Group); // look for separator
|
|
222
|
+
m[0] = szSep.join(''); // join back without separator for counting the pos of any leading 0.
|
|
223
|
+
|
|
224
|
+
let pos_lead_zero = m[0] && m[0].indexOf('0');
|
|
225
|
+
if (pos_lead_zero > -1) {
|
|
226
|
+
while (part[0].length < (m[0].length - pos_lead_zero)) {
|
|
227
|
+
part[0] = '0' + part[0];
|
|
228
|
+
}
|
|
229
|
+
} else if (+part[0] == 0) {
|
|
230
|
+
part[0] = '';
|
|
231
|
+
}
|
|
232
|
+
v = v.split('.');
|
|
233
|
+
v[0] = part[0];
|
|
234
|
+
|
|
235
|
+
var pos_separator = (szSep[1] && szSep[szSep.length - 1].length); // process the first group separator from decimal (.) only, the rest ignore. Get the length of the last slice of split result.
|
|
236
|
+
if (pos_separator) {
|
|
237
|
+
let integer = v[0];
|
|
238
|
+
let str = '';
|
|
239
|
+
let offset = integer.length % pos_separator;
|
|
240
|
+
for (let i = 0, l = integer.length; i < l; i++) {
|
|
241
|
+
str += integer.charAt(i); // ie6 only support charAt for sz.
|
|
242
|
+
if (
|
|
243
|
+
!((i - offset + 1) % pos_separator) &&
|
|
244
|
+
i < l - pos_separator // -pos_separator so that won't trail separator on full length
|
|
245
|
+
) {
|
|
246
|
+
str += Group;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
v[0] = str;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
v[1] = (m[1] && v[1]) ? Decimal + v[1] : "";
|
|
253
|
+
return (isNegative ? '-' : '') + v[0] + v[1]; // put back any negation and combine integer and fraction.
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Original Source: https://github.com/dtutic/Leaflet.EdgeScaleBar
|
|
260
|
+
*
|
|
261
|
+
* Draws the metric scale bars in Web Mercator map along top and right edges.
|
|
262
|
+
* Authors: Dražen Tutić (dtutic@geof.hr), Ana Kuveždić Divjak (akuvezdic@geof.hr)
|
|
263
|
+
* University of Zagreb, Faculty of Geodesy, GEOF-OSGL Lab
|
|
264
|
+
* Inspired by LatLonGraticule Leaflet plugin by: lanwei@cloudybay.com.tw
|
|
265
|
+
*/
|
|
266
|
+
L.Control.EdgeScale.Layer = L.Layer.extend({
|
|
267
|
+
|
|
268
|
+
includes: L.Evented ? L.Evented.prototype : L.Mixin.Events,
|
|
269
|
+
|
|
270
|
+
options: {
|
|
271
|
+
opacity: 1,
|
|
272
|
+
weight: 0.8,
|
|
273
|
+
gradient: {
|
|
274
|
+
size: 10,
|
|
275
|
+
opacity: 0.5,
|
|
276
|
+
},
|
|
277
|
+
color: '#000',
|
|
278
|
+
font: '11px Arial',
|
|
279
|
+
zoomInterval: [
|
|
280
|
+
{start: 0, end: 2, interval: 5000000},
|
|
281
|
+
{start: 3, end: 3, interval: 2000000},
|
|
282
|
+
{start: 4, end: 4, interval: 1000000},
|
|
283
|
+
{start: 5, end: 5, interval: 500000},
|
|
284
|
+
{start: 6, end: 7, interval: 200000},
|
|
285
|
+
{start: 8, end: 8, interval: 100000},
|
|
286
|
+
{start: 9, end: 9, interval: 50000},
|
|
287
|
+
{start: 10, end: 10, interval: 20000},
|
|
288
|
+
{start: 11, end: 11, interval: 10000},
|
|
289
|
+
{start: 12, end: 12, interval: 5000},
|
|
290
|
+
{start: 13, end: 13, interval: 2000},
|
|
291
|
+
{start: 14, end: 14, interval: 1000},
|
|
292
|
+
{start: 15, end: 15, interval: 500},
|
|
293
|
+
{start: 16, end: 16, interval: 200},
|
|
294
|
+
{start: 17, end: 17, interval: 100},
|
|
295
|
+
{start: 18, end: 18, interval: 50},
|
|
296
|
+
{start: 19, end: 19, interval: 20},
|
|
297
|
+
{start: 20, end: 20, interval: 10}
|
|
298
|
+
],
|
|
299
|
+
pane: 'edgescalePane'
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
initialize: function (options) {
|
|
303
|
+
|
|
304
|
+
L.setOptions(this, options);
|
|
305
|
+
|
|
306
|
+
// Constants of the WGS84 ellipsoid needed to calculate meridian length or latitute
|
|
307
|
+
const a = this._a = 6378137.0;
|
|
308
|
+
const b = this._b = 6356752.3142;
|
|
309
|
+
const n = this._n = (a - b)/(a + b);
|
|
310
|
+
const a2 = a * a;
|
|
311
|
+
const b2 = b * b;
|
|
312
|
+
const n2 = n * n;
|
|
313
|
+
const n3 = n2 * n;
|
|
314
|
+
const n4 = n3 * n;
|
|
315
|
+
const n5 = n4 * n;
|
|
316
|
+
this._A = a * (1.0 - n) * (1.0 - n2) * (1.0 + 9.0/4.0 * n2 + 225.0/64.0 * n4);
|
|
317
|
+
this._e2 = (a2 - b2) / a2;
|
|
318
|
+
this._ic1 = 1.5 * n - 29.0/12.0 * n3 + 553.0/80.0 * n5;
|
|
319
|
+
this._ic2 = 21.0/8.0 * n2 - 1537.0/128.0 * n4;
|
|
320
|
+
this._ic3 = 151.0/24.0 * n3 - 32373.0/640.0 * n5;
|
|
321
|
+
this._ic4 = 1097.0/64.0 * n4;
|
|
322
|
+
this._ic5 = 8011.0/150.0 * n5;
|
|
323
|
+
this._c1 = -1.5 * n + 31.0/24.0 * n3 - 669.0/640.0 * n5;
|
|
324
|
+
this._c2 = 15.0/18.0 * n2 - 435.0/128.0 * n4;
|
|
325
|
+
this._c3 = -35.0/12.0 * n3 + 651.0/80.0 * n5;
|
|
326
|
+
this._c4 = 315.0/64.0 * n4;
|
|
327
|
+
this._c5 = -693.0/80.0 * n5;
|
|
328
|
+
|
|
329
|
+
// Latitude limit of the Web Mercator projection
|
|
330
|
+
this._LIMIT_PHI = 1.484419982;
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
onAdd: function (map) {
|
|
334
|
+
this._map = map;
|
|
335
|
+
|
|
336
|
+
let pane = map.getPane(this.options.pane);
|
|
337
|
+
if (!pane) {
|
|
338
|
+
pane = this._pane = map.createPane('edgescalePane', map.getPane('norotatePane') || map.getPane('mapPane'));
|
|
339
|
+
pane.style.zIndex = 625; // This pane is above markers but below popups.
|
|
340
|
+
pane.style.pointerEvents = 'none';
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
this._pane = pane;
|
|
344
|
+
|
|
345
|
+
// if (this._renderer) this._renderer.remove()
|
|
346
|
+
// this._renderer = L.canvas({ pane: "edgescalePane" }).addTo(this._map); // default leaflet svg renderer
|
|
347
|
+
|
|
348
|
+
if (!this._canvas) {
|
|
349
|
+
this._initCanvas();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
this._pane.appendChild(this._canvas);
|
|
353
|
+
|
|
354
|
+
map.on('viewreset', this._reset, this);
|
|
355
|
+
map.on('move', this._reset, this);
|
|
356
|
+
map.on('moveend', this._reset, this);
|
|
357
|
+
map.on('rotate', this._reset, this);
|
|
358
|
+
|
|
359
|
+
this._reset();
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
onRemove: function (map) {
|
|
363
|
+
this._pane.removeChild(this._canvas);
|
|
364
|
+
|
|
365
|
+
map.off('viewreset', this._reset, this);
|
|
366
|
+
map.off('move', this._reset, this);
|
|
367
|
+
map.off('moveend', this._reset, this);
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
addTo: function (map) {
|
|
371
|
+
map.addLayer(this);
|
|
372
|
+
return this;
|
|
373
|
+
},
|
|
374
|
+
|
|
375
|
+
setOpacity: function (opacity) {
|
|
376
|
+
this.options.opacity = opacity;
|
|
377
|
+
L.DomUtil.setOpacity(this._canvas, this.options.opacity);
|
|
378
|
+
return this;
|
|
379
|
+
},
|
|
380
|
+
|
|
381
|
+
bringToFront: function () {
|
|
382
|
+
if (this._canvas) {
|
|
383
|
+
this._pane.appendChild(this._canvas);
|
|
384
|
+
}
|
|
385
|
+
return this;
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
bringToBack: function () {
|
|
389
|
+
if (this._canvas) {
|
|
390
|
+
this._pane.insertBefore(this._canvas, pane.firstChild);
|
|
391
|
+
}
|
|
392
|
+
return this;
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
_initCanvas: function () {
|
|
396
|
+
this._canvas = L.DomUtil.create('canvas', '');
|
|
397
|
+
this._ctx = this._canvas.getContext('2d');
|
|
398
|
+
|
|
399
|
+
this.setOpacity();
|
|
400
|
+
|
|
401
|
+
L.extend(this._canvas, {
|
|
402
|
+
onselectstart: L.Util.falseFn,
|
|
403
|
+
onmousemove: L.Util.falseFn,
|
|
404
|
+
onload: L.bind(this._onCanvasLoad, this)
|
|
405
|
+
});
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
_reset: function () {
|
|
409
|
+
var canvas = this._canvas,
|
|
410
|
+
size = this._map.getSize();
|
|
411
|
+
|
|
412
|
+
this._setCanvasPosition();
|
|
413
|
+
|
|
414
|
+
canvas.width = size.x;
|
|
415
|
+
canvas.height = size.y;
|
|
416
|
+
canvas.style.width = size.x + 'px';
|
|
417
|
+
canvas.style.height = size.y + 'px';
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* @TODO add support for "leaflet-rotate"
|
|
421
|
+
*/
|
|
422
|
+
if (this._map._bearing) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const { gradient } = this.options;
|
|
427
|
+
|
|
428
|
+
// horizontal gradient
|
|
429
|
+
if (!this._hor_gradient) {
|
|
430
|
+
this._hor_gradient = this._ctx.createLinearGradient(0, 0, 0, gradient.size);
|
|
431
|
+
this._hor_gradient.addColorStop(0,"rgba(255, 255, 255, " + gradient.opacity + ")");
|
|
432
|
+
this._hor_gradient.addColorStop(1,"rgba(255, 255, 255, 0)");
|
|
433
|
+
}
|
|
434
|
+
this._ctx.fillStyle = this._hor_gradient;
|
|
435
|
+
this._ctx.fillRect(0, 0, size.x, gradient.size);
|
|
436
|
+
|
|
437
|
+
// vertical gradient
|
|
438
|
+
if (!this._vert_gradient) {
|
|
439
|
+
this._vert_gradient = this._ctx.createLinearGradient(0, 0, gradient.size, 0);
|
|
440
|
+
this._vert_gradient.addColorStop(0,"rgba(255, 255, 255, " + gradient.opacity + ")");
|
|
441
|
+
this._vert_gradient.addColorStop(1,"rgba(255, 255, 255, 0)");
|
|
442
|
+
}
|
|
443
|
+
this._ctx.fillStyle = this._vert_gradient;
|
|
444
|
+
this._ctx.fillRect(0, 0, gradient.size, size.y);
|
|
445
|
+
|
|
446
|
+
this._ctx.beginPath();
|
|
447
|
+
this._ctx.moveTo(0,0);
|
|
448
|
+
this._ctx.lineTo(size.x,0);
|
|
449
|
+
this._ctx.lineTo(size.x,size.y);
|
|
450
|
+
this._ctx.stroke();
|
|
451
|
+
|
|
452
|
+
this._calcInterval();
|
|
453
|
+
this._draw();
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
_onCanvasLoad: function () {
|
|
457
|
+
this.fire('load');
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
_calcInterval: function() {
|
|
461
|
+
const { zoomInterval } = this.options;
|
|
462
|
+
const zoom = this._map.getZoom();
|
|
463
|
+
|
|
464
|
+
if (undefined !== zoomInterval) {
|
|
465
|
+
// Manually set scale using a custom this.options.zoomInterval object
|
|
466
|
+
for (const idx in zoomInterval) {
|
|
467
|
+
const dict = zoomInterval[idx];
|
|
468
|
+
if (dict.start <= zoom && dict.end && dict.end >= zoom) {
|
|
469
|
+
this._interval = dict.interval;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
// Autamatically get current scale using L.Control.Scale
|
|
475
|
+
// Source: https://gis.stackexchange.com/a/198444
|
|
476
|
+
this._interval = L.Control.Scale.prototype._getRoundNum(
|
|
477
|
+
this._map
|
|
478
|
+
.containerPointToLatLng([0, this._map.getSize().y / 2 ])
|
|
479
|
+
.distanceTo(
|
|
480
|
+
this._map.containerPointToLatLng([L.Control.Scale.prototype.options.maxWidth, this._map.getSize().y / 2 ]
|
|
481
|
+
)
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
this._currZoom = zoom;
|
|
487
|
+
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
_draw: function() {
|
|
491
|
+
this._ctx.strokeStyle = this.options.color;
|
|
492
|
+
this._create_lat_ticks();
|
|
493
|
+
this._create_lon_ticks();
|
|
494
|
+
|
|
495
|
+
this._ctx.fillStyle = this.options.color;
|
|
496
|
+
this._ctx.font = this.options.font;
|
|
497
|
+
|
|
498
|
+
const size = this._map.getSize();
|
|
499
|
+
const text = this._interval >= 1000 ? (this._interval / 1000 + ' km') : this._interval + ' m';
|
|
500
|
+
|
|
501
|
+
this._ctx.textAlign = 'left';
|
|
502
|
+
this._ctx.textBaseline = 'middle';
|
|
503
|
+
this._ctx.fillText(text, +12, size.y / 2);
|
|
504
|
+
|
|
505
|
+
this._ctx.textAlign = 'center';
|
|
506
|
+
this._ctx.textBaseline = 'top';
|
|
507
|
+
this._ctx.fillText(text, size.x / 2, 12);
|
|
508
|
+
},
|
|
509
|
+
|
|
510
|
+
_create_lat_ticks: function() {
|
|
511
|
+
const { weight } = this.options;
|
|
512
|
+
const size = this._map.getSize();
|
|
513
|
+
const to_rad = Math.PI/180.0;
|
|
514
|
+
const center = this._merLength(this._map.containerPointToLatLng(L.point(0, size.y / 2)).lat * to_rad);
|
|
515
|
+
const top = this._merLength(this._map.containerPointToLatLng(L.point(0,0)).lat * to_rad);
|
|
516
|
+
const bottom = this._merLength(this._map.containerPointToLatLng(L.point(0, size.y)).lat * to_rad);
|
|
517
|
+
|
|
518
|
+
// draw major ticks
|
|
519
|
+
for (let i = center + this._interval / 2; i < top; i = i + this._interval) {
|
|
520
|
+
const phi = this._invmerLength(i);
|
|
521
|
+
if ((phi < this._LIMIT_PHI) && (phi > -this._LIMIT_PHI)) {
|
|
522
|
+
this._draw_lat_tick(phi, 10, weight * 1.5);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
for (let i = center - this._interval / 2; i > bottom; i = i - this._interval) {
|
|
526
|
+
const phi = this._invmerLength(i);
|
|
527
|
+
if ((phi > -this._LIMIT_PHI) && (phi < this._LIMIT_PHI)) {
|
|
528
|
+
this._draw_lat_tick(phi, 10, weight * 1.5);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// draw minor ticks
|
|
533
|
+
for (let i = center; i < top; i = i + this._interval / 10.0) {
|
|
534
|
+
const phi = this._invmerLength(i);
|
|
535
|
+
if ((phi < this._LIMIT_PHI) && (phi > -this._LIMIT_PHI)) {
|
|
536
|
+
this._draw_lat_tick(phi, 4, weight);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
for (let i = center - this._interval / 10; i > bottom; i = i - this._interval / 10.0) {
|
|
540
|
+
const phi = this._invmerLength(i);
|
|
541
|
+
if ((phi > -this._LIMIT_PHI) && (phi < this._LIMIT_PHI)) {
|
|
542
|
+
this._draw_lat_tick(phi, 4, weight);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
_create_lon_ticks: function() {
|
|
548
|
+
const { weight } = this.options;
|
|
549
|
+
const size = this._map.getSize();
|
|
550
|
+
const to_rad = Math.PI/180.0;
|
|
551
|
+
const to_deg = 180.0/Math.PI;
|
|
552
|
+
const center = this._map.containerPointToLatLng(L.point(size.x / 2, 0));
|
|
553
|
+
const left = this._map.containerPointToLatLng(L.point(0, 0));
|
|
554
|
+
const right = this._map.containerPointToLatLng(L.point(size.x, 0));
|
|
555
|
+
const sinPhi2 = Math.pow(Math.sin(center.lat * to_rad), 2);
|
|
556
|
+
const N = this._a / Math.sqrt(1.0 - this._e2 * sinPhi2);
|
|
557
|
+
const dl = this._interval / (N * Math.cos(center.lat * to_rad)) * to_deg;
|
|
558
|
+
|
|
559
|
+
// draw major ticks
|
|
560
|
+
for (let i = center.lng + dl / 2; i < right.lng; i = i + dl) this._draw_lon_tick(i, 10, weight * 1.5);
|
|
561
|
+
for (let i = center.lng - dl / 2; i > left.lng; i = i - dl) this._draw_lon_tick(i, 10, weight * 1.5);
|
|
562
|
+
|
|
563
|
+
// draw minor ticks
|
|
564
|
+
for (let i = center.lng; i < right.lng; i = i + dl / 10) this._draw_lon_tick(i, 4, weight);
|
|
565
|
+
for (let i = center.lng - dl / 10; i > left.lng; i = i - dl / 10) this._draw_lon_tick(i, 4, weight);
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
_setCanvasPosition: function() {
|
|
569
|
+
let lt = this._map.containerPointToLayerPoint([0, 0]);
|
|
570
|
+
/**
|
|
571
|
+
* @TODO add support for "leaflet-rotate"
|
|
572
|
+
*/
|
|
573
|
+
if (this._map._bearing) {
|
|
574
|
+
lt = this._map.rotatedPointToMapPanePoint(
|
|
575
|
+
this._map.containerPointToLayerPoint(L.point(this._map._container.getBoundingClientRect()))
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
L.DomUtil.setPosition(this._canvas, lt);
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
_latLngToCanvasPoint: function (latlng) {
|
|
582
|
+
return L.point(
|
|
583
|
+
this._map
|
|
584
|
+
.project(L.latLng(latlng))
|
|
585
|
+
._subtract(this._map.getPixelOrigin())
|
|
586
|
+
).add(this._map._getMapPanePos());
|
|
587
|
+
},
|
|
588
|
+
|
|
589
|
+
_draw_lat_tick: function (phi, lenght, weight) {
|
|
590
|
+
const to_deg = 180.0/Math.PI;
|
|
591
|
+
const size = this._map.getSize();
|
|
592
|
+
const y = this._latLngToCanvasPoint(L.latLng(phi * to_deg, 0.0)).y;
|
|
593
|
+
this._ctx.lineWidth = weight;
|
|
594
|
+
this._ctx.beginPath();
|
|
595
|
+
this._ctx.moveTo(0, y);
|
|
596
|
+
this._ctx.lineTo(+ lenght, y);
|
|
597
|
+
this._ctx.stroke();
|
|
598
|
+
},
|
|
599
|
+
|
|
600
|
+
_draw_lon_tick: function(lam, lenght, weight) {
|
|
601
|
+
const x = this._latLngToCanvasPoint(L.latLng(0.0, lam)).x;
|
|
602
|
+
this._ctx.lineWidth = weight;
|
|
603
|
+
this._ctx.beginPath();
|
|
604
|
+
this._ctx.moveTo(x, 0);
|
|
605
|
+
this._ctx.lineTo(x, lenght);
|
|
606
|
+
this._ctx.stroke();
|
|
607
|
+
},
|
|
608
|
+
|
|
609
|
+
_merLength: function(phi) {
|
|
610
|
+
const cos2 = Math.cos(2.0 * phi);
|
|
611
|
+
const sin2 = Math.sin(2.0 * phi);
|
|
612
|
+
return this._A * (phi + sin2 * (this._c1 + (this._c2 + (this._c3 + (this._c4 + this._c5 * cos2) * cos2) *cos2) * cos2));
|
|
613
|
+
},
|
|
614
|
+
|
|
615
|
+
_invmerLength: function(s) {
|
|
616
|
+
const psi = s/this._A;
|
|
617
|
+
const cos2 = Math.cos(2.0 * psi);
|
|
618
|
+
const sin2 = Math.sin(2.0 * psi);
|
|
619
|
+
return psi + sin2 * (this._ic1 + (this._ic2 + (this._ic3 + (this._ic4 + this._ic5 * cos2) * cos2) * cos2) * cos2);
|
|
620
|
+
},
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
L.control.edgeScale = function (options) {
|
|
624
|
+
return new L.Control.EdgeScale(options);
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
L.Map.mergeOptions({
|
|
628
|
+
edgeScaleControl: false
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
L.Map.addInitHook(function () {
|
|
632
|
+
if (this.options.edgeScaleControl) {
|
|
633
|
+
this.edgeScaleControl = new L.Control.EdgeScale();
|
|
634
|
+
this.addControl(this.edgeScaleControl);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
L.Control.EdgeScale=L.Control.extend({options:{position:"bottomleft",icon:!0,coords:!0,bar:!0,onMove:!0,template:"{y} | {x}",projected:!1,formatProjected:"#.##0,000",latlngFormat:"DD",latlngDesignators:!0,latLngFormatter:void 0,iconStyle:{background:"url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xml:space='preserve' viewBox='0 0 100 100'%3E%3Cg stroke='%23fff'%3E%3Ccircle cx='50' cy='50.2' r='3.9' stroke-width='2' /%3E%3Cpath stroke-width='3' d='M5 54h32a4 4 0 1 0 0-8H5a4 4 0 1 0 0 8z M54 5a4 4 0 1 0-8 0v32a4 4 0 1 0 8 0V5z M99 50c0-2-2-4-4-4H63a4 4 0 1 0 0 8h32c2 0 4-1 4-4zM46 95a4 4 0 1 0 8 0V64a4 4 0 1 0-8 0v31z'/%3E%3C/g%3E%3C/svg%3E%0A\")",width:"24px",height:"24px",left:"calc(50% - 12px)",top:"calc(50% - 12px)",content:"",display:"block",position:"absolute",zIndex:999,pointerEvents:"none"},containerStyle:{backgroundColor:"rgba(255, 255, 255, 0.7)",boxShadow:"0 0 5px #bbb",borderRadius:"3px",padding:"3px 2px",color:"#333",font:"11px/1.5 Consolas, monaco, monospace",writingMode:"vertical-lr"}},initialize:function(options){L.setOptions(this,options)},onAdd:function(map){return this.options.bar&&(this._scaleBar=new L.Control.EdgeScale.Layer(!0===this.options.bar?{}:this.options.bar).addTo(map)),this.options.icon&&(this._icon=L.DomUtil.create("div","leaflet-crosshair"),Object.assign(this._icon.style,this.options.iconStyle),map.getContainer().insertBefore(this._icon,map.getContainer().firstChild)),this._container=L.DomUtil.create("div","leaflet-control-mapcentercoord"),Object.assign(this._container.style,this.options.containerStyle),this.options.coords||(this._container.style.display="none"),L.DomEvent.disableClickPropagation(this._container),this._container.innerHTML=this._getMapCenterCoord(),map.on("move",this._onMapMove,this),map.on("moveend",this._onMapMove,this),this._container},onRemove:function(map){this.options.bar&&this._scaleBar.remove(),this.options.icon&&map.getContainer().removeChild(this._icon),map.off("move",this._onMapMove,this),map.off("moveend",this._onMapMove,this)},_onMapMove:function(e){(this.options.onMove||"moveend"===e.type)&&(this._container.innerHTML=this._getMapCenterCoord())},_getMapCenterCoord:function(){const center=this._map.getCenter();return this.options.projected?this._getProjectedCoord(this._map.options.crs.project(center)):this._getLatLngCoord(center)},_getProjectedCoord:function(center){return L.Util.template(this.options.template,{x:this._format(this.options.formatProjected,center.x),y:this._format(this.options.formatProjected,center.y)})},_getLatLngCoord:function(latLng){const{latLngFormatter:latLngFormatter,latlngFormat:latlngFormat,latlngDesignators:designators}=this.options;if(void 0!==latLngFormatter)return latLngFormatter(latLng.lat,latLng.lng);let lat,lng,deg,min,center={lat:latLng.lat,lng:latLng.lng,lng_neg:latLng.lng<0,lat_neg:latLng.lat<0};return center.lng<0&&(center.lng=Math.abs(center.lng)),center.lng>180&&(center.lng=360-center.lng,center.lng_neg=!center.lng_neg),center.lat<0&&(center.lat=Math.abs(center.lat)),"DM"===latlngFormat?(deg=parseInt(center.lng),lng=deg+"º "+this._format("00.000",60*(center.lng-deg))+"'",deg=parseInt(center.lat),lat=deg+"º "+this._format("00.000",60*(center.lat-deg))+"'"):"DMS"===latlngFormat?(deg=parseInt(center.lng),min=60*(center.lng-deg),lng=deg+"º "+this._format("00",parseInt(min))+"' "+this._format("00.0",60*(min-parseInt(min)))+"''",deg=parseInt(center.lat),min=60*(center.lat-deg),lat=deg+"º "+this._format("00",parseInt(min))+"' "+this._format("00.0",60*(min-parseInt(min)))+"''"):(lng=this._format("#0.00000",center.lng)+"º",lat=this._format("##0.00000",center.lat)+"º"),L.Util.template(this.options.template,{x:(!designators&¢er.lng_neg?"-":"")+lng+(designators?center.lng_neg?" W":" E":""),y:(!designators&¢er.lat_neg?"-":"")+lat+(designators?center.lat_neg?" S":" N":"")})},_format:function(m,v){if(!m||isNaN(+v))return v;let isNegative=(v="-"==m.charAt(0)?-v:+v)<0?v=-v:0,result=m.match(/[^\d\-\+#]/g),Decimal=result&&result[result.length-1]||".",Group=result&&result[1]&&result[0]||",";m=m.split(Decimal),v=+(v=v.toFixed(m[1]&&m[1].length))+"";let pos_trail_zero=m[1]&&m[1].lastIndexOf("0"),part=v.split(".");(!part[1]||part[1]&&part[1].length<=pos_trail_zero)&&(v=(+v).toFixed(pos_trail_zero+1));let szSep=m[0].split(Group);m[0]=szSep.join("");let pos_lead_zero=m[0]&&m[0].indexOf("0");if(pos_lead_zero>-1)for(;part[0].length<m[0].length-pos_lead_zero;)part[0]="0"+part[0];else 0==+part[0]&&(part[0]="");(v=v.split("."))[0]=part[0];var pos_separator=szSep[1]&&szSep[szSep.length-1].length;if(pos_separator){let integer=v[0],str="",offset=integer.length%pos_separator;for(let i=0,l=integer.length;i<l;i++)str+=integer.charAt(i),!((i-offset+1)%pos_separator)&&i<l-pos_separator&&(str+=Group);v[0]=str}return v[1]=m[1]&&v[1]?Decimal+v[1]:"",(isNegative?"-":"")+v[0]+v[1]}}),L.Control.EdgeScale.Layer=L.Layer.extend({includes:L.Evented?L.Evented.prototype:L.Mixin.Events,options:{opacity:1,weight:.8,gradient:{size:10,opacity:.5},color:"#000",font:"11px Arial",zoomInterval:[{start:0,end:2,interval:5e6},{start:3,end:3,interval:2e6},{start:4,end:4,interval:1e6},{start:5,end:5,interval:5e5},{start:6,end:7,interval:2e5},{start:8,end:8,interval:1e5},{start:9,end:9,interval:5e4},{start:10,end:10,interval:2e4},{start:11,end:11,interval:1e4},{start:12,end:12,interval:5e3},{start:13,end:13,interval:2e3},{start:14,end:14,interval:1e3},{start:15,end:15,interval:500},{start:16,end:16,interval:200},{start:17,end:17,interval:100},{start:18,end:18,interval:50},{start:19,end:19,interval:20},{start:20,end:20,interval:10}],pane:"edgescalePane"},initialize:function(options){L.setOptions(this,options);const a=this._a=6378137,b=this._b=6356752.3142,n=this._n=(a-b)/(a+b),a2=a*a,b2=b*b,n2=n*n,n3=n2*n,n4=n3*n,n5=n4*n;this._A=a*(1-n)*(1-n2)*(1+9/4*n2+225/64*n4),this._e2=(a2-b2)/a2,this._ic1=1.5*n-29/12*n3+6.9125*n5,this._ic2=21/8*n2-1537/128*n4,this._ic3=151/24*n3-32373/640*n5,this._ic4=1097/64*n4,this._ic5=8011/150*n5,this._c1=-1.5*n+31/24*n3-669/640*n5,this._c2=15/18*n2-435/128*n4,this._c3=-35/12*n3+8.1375*n5,this._c4=315/64*n4,this._c5=-8.6625*n5,this._LIMIT_PHI=1.484419982},onAdd:function(map){this._map=map;let pane=map.getPane(this.options.pane);pane||(pane=this._pane=map.createPane("edgescalePane",map.getPane("norotatePane")||map.getPane("mapPane")),pane.style.zIndex=625,pane.style.pointerEvents="none"),this._pane=pane,this._canvas||this._initCanvas(),this._pane.appendChild(this._canvas),map.on("viewreset",this._reset,this),map.on("move",this._reset,this),map.on("moveend",this._reset,this),map.on("rotate",this._reset,this),this._reset()},onRemove:function(map){this._pane.removeChild(this._canvas),map.off("viewreset",this._reset,this),map.off("move",this._reset,this),map.off("moveend",this._reset,this)},addTo:function(map){return map.addLayer(this),this},setOpacity:function(opacity){return this.options.opacity=opacity,L.DomUtil.setOpacity(this._canvas,this.options.opacity),this},bringToFront:function(){return this._canvas&&this._pane.appendChild(this._canvas),this},bringToBack:function(){return this._canvas&&this._pane.insertBefore(this._canvas,pane.firstChild),this},_initCanvas:function(){this._canvas=L.DomUtil.create("canvas",""),this._ctx=this._canvas.getContext("2d"),this.setOpacity(),L.extend(this._canvas,{onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:L.bind(this._onCanvasLoad,this)})},_reset:function(){var canvas=this._canvas,size=this._map.getSize();if(this._setCanvasPosition(),canvas.width=size.x,canvas.height=size.y,canvas.style.width=size.x+"px",canvas.style.height=size.y+"px",this._map._bearing)return;const{gradient:gradient}=this.options;this._hor_gradient||(this._hor_gradient=this._ctx.createLinearGradient(0,0,0,gradient.size),this._hor_gradient.addColorStop(0,"rgba(255, 255, 255, "+gradient.opacity+")"),this._hor_gradient.addColorStop(1,"rgba(255, 255, 255, 0)")),this._ctx.fillStyle=this._hor_gradient,this._ctx.fillRect(0,0,size.x,gradient.size),this._vert_gradient||(this._vert_gradient=this._ctx.createLinearGradient(0,0,gradient.size,0),this._vert_gradient.addColorStop(0,"rgba(255, 255, 255, "+gradient.opacity+")"),this._vert_gradient.addColorStop(1,"rgba(255, 255, 255, 0)")),this._ctx.fillStyle=this._vert_gradient,this._ctx.fillRect(0,0,gradient.size,size.y),this._ctx.beginPath(),this._ctx.moveTo(0,0),this._ctx.lineTo(size.x,0),this._ctx.lineTo(size.x,size.y),this._ctx.stroke(),this._calcInterval(),this._draw()},_onCanvasLoad:function(){this.fire("load")},_calcInterval:function(){const{zoomInterval:zoomInterval}=this.options,zoom=this._map.getZoom();if(void 0!==zoomInterval)for(const idx in zoomInterval){const dict=zoomInterval[idx];if(dict.start<=zoom&&dict.end&&dict.end>=zoom){this._interval=dict.interval;break}}else this._interval=L.Control.Scale.prototype._getRoundNum(this._map.containerPointToLatLng([0,this._map.getSize().y/2]).distanceTo(this._map.containerPointToLatLng([L.Control.Scale.prototype.options.maxWidth,this._map.getSize().y/2])));this._currZoom=zoom},_draw:function(){this._ctx.strokeStyle=this.options.color,this._create_lat_ticks(),this._create_lon_ticks(),this._ctx.fillStyle=this.options.color,this._ctx.font=this.options.font;const size=this._map.getSize(),text=this._interval>=1e3?this._interval/1e3+" km":this._interval+" m";this._ctx.textAlign="left",this._ctx.textBaseline="middle",this._ctx.fillText(text,12,size.y/2),this._ctx.textAlign="center",this._ctx.textBaseline="top",this._ctx.fillText(text,size.x/2,12)},_create_lat_ticks:function(){const{weight:weight}=this.options,size=this._map.getSize(),to_rad=Math.PI/180,center=this._merLength(this._map.containerPointToLatLng(L.point(0,size.y/2)).lat*to_rad),top=this._merLength(this._map.containerPointToLatLng(L.point(0,0)).lat*to_rad),bottom=this._merLength(this._map.containerPointToLatLng(L.point(0,size.y)).lat*to_rad);for(let i=center+this._interval/2;i<top;i+=this._interval){const phi=this._invmerLength(i);phi<this._LIMIT_PHI&&phi>-this._LIMIT_PHI&&this._draw_lat_tick(phi,10,1.5*weight)}for(let i=center-this._interval/2;i>bottom;i-=this._interval){const phi=this._invmerLength(i);phi>-this._LIMIT_PHI&&phi<this._LIMIT_PHI&&this._draw_lat_tick(phi,10,1.5*weight)}for(let i=center;i<top;i+=this._interval/10){const phi=this._invmerLength(i);phi<this._LIMIT_PHI&&phi>-this._LIMIT_PHI&&this._draw_lat_tick(phi,4,weight)}for(let i=center-this._interval/10;i>bottom;i-=this._interval/10){const phi=this._invmerLength(i);phi>-this._LIMIT_PHI&&phi<this._LIMIT_PHI&&this._draw_lat_tick(phi,4,weight)}},_create_lon_ticks:function(){const{weight:weight}=this.options,size=this._map.getSize(),to_rad=Math.PI/180,to_deg=180/Math.PI,center=this._map.containerPointToLatLng(L.point(size.x/2,0)),left=this._map.containerPointToLatLng(L.point(0,0)),right=this._map.containerPointToLatLng(L.point(size.x,0)),sinPhi2=Math.pow(Math.sin(center.lat*to_rad),2),N=this._a/Math.sqrt(1-this._e2*sinPhi2),dl=this._interval/(N*Math.cos(center.lat*to_rad))*to_deg;for(let i=center.lng+dl/2;i<right.lng;i+=dl)this._draw_lon_tick(i,10,1.5*weight);for(let i=center.lng-dl/2;i>left.lng;i-=dl)this._draw_lon_tick(i,10,1.5*weight);for(let i=center.lng;i<right.lng;i+=dl/10)this._draw_lon_tick(i,4,weight);for(let i=center.lng-dl/10;i>left.lng;i-=dl/10)this._draw_lon_tick(i,4,weight)},_setCanvasPosition:function(){let lt=this._map.containerPointToLayerPoint([0,0]);this._map._bearing&&(lt=this._map.rotatedPointToMapPanePoint(this._map.containerPointToLayerPoint(L.point(this._map._container.getBoundingClientRect())))),L.DomUtil.setPosition(this._canvas,lt)},_latLngToCanvasPoint:function(latlng){return L.point(this._map.project(L.latLng(latlng))._subtract(this._map.getPixelOrigin())).add(this._map._getMapPanePos())},_draw_lat_tick:function(phi,lenght,weight){const to_deg=180/Math.PI,size=this._map.getSize(),y=this._latLngToCanvasPoint(L.latLng(phi*to_deg,0)).y;this._ctx.lineWidth=weight,this._ctx.beginPath(),this._ctx.moveTo(0,y),this._ctx.lineTo(+lenght,y),this._ctx.stroke()},_draw_lon_tick:function(lam,lenght,weight){const x=this._latLngToCanvasPoint(L.latLng(0,lam)).x;this._ctx.lineWidth=weight,this._ctx.beginPath(),this._ctx.moveTo(x,0),this._ctx.lineTo(x,lenght),this._ctx.stroke()},_merLength:function(phi){const cos2=Math.cos(2*phi),sin2=Math.sin(2*phi);return this._A*(phi+sin2*(this._c1+(this._c2+(this._c3+(this._c4+this._c5*cos2)*cos2)*cos2)*cos2))},_invmerLength:function(s){const psi=s/this._A,cos2=Math.cos(2*psi),sin2=Math.sin(2*psi);return psi+sin2*(this._ic1+(this._ic2+(this._ic3+(this._ic4+this._ic5*cos2)*cos2)*cos2)*cos2)}}),L.control.edgeScale=function(options){return new L.Control.EdgeScale(options)},L.Map.mergeOptions({edgeScaleControl:!1}),L.Map.addInitHook((function(){this.options.edgeScaleControl&&(this.edgeScaleControl=new L.Control.EdgeScale,this.addControl(this.edgeScaleControl))}));
|