@teipublisher/pb-components 2.15.3 → 2.17.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/CHANGELOG.md +14 -0
- package/css/leaflet/Control.Geocoder.css +126 -0
- package/dist/demo/demos.json +2 -1
- package/dist/pb-components-bundle.js +7 -2
- package/dist/pb-elements.json +27 -10
- package/dist/pb-leaflet-map.js +6 -5
- package/i18n/common/en.json +3 -0
- package/lib/Control.Geocoder.min.js +2 -0
- package/lib/Control.Geocoder.min.js.map +1 -0
- package/package.json +2 -1
- package/pb-elements.json +27 -10
- package/src/pb-events.js +38 -0
- package/src/pb-leaflet-map.js +545 -463
- package/src/pb-view-annotate.js +27 -16
package/src/pb-leaflet-map.js
CHANGED
|
@@ -1,464 +1,546 @@
|
|
|
1
|
-
import { LitElement, html, css } from 'lit-element';
|
|
2
|
-
import "@lrnwebcomponents/es-global-bridge";
|
|
3
|
-
import { pbMixin } from './pb-mixin.js';
|
|
4
|
-
import { resolveURL } from './utils.js';
|
|
5
|
-
import
|
|
6
|
-
import './pb-map-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @
|
|
16
|
-
* @fires pb-
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @fires pb-
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this.
|
|
127
|
-
this.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
this.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
1
|
+
import { LitElement, html, css } from 'lit-element';
|
|
2
|
+
import "@lrnwebcomponents/es-global-bridge";
|
|
3
|
+
import { pbMixin } from './pb-mixin.js';
|
|
4
|
+
import { resolveURL } from './utils.js';
|
|
5
|
+
import { get as i18n } from "./pb-i18n.js";
|
|
6
|
+
import './pb-map-layer.js';
|
|
7
|
+
import './pb-map-icon.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A wrapper component for [leaflet](https://leafletjs.com/) displaying a map.
|
|
11
|
+
*
|
|
12
|
+
* The map layers displayed can be configured via nested `pb-map-layer` (see docs) elements,
|
|
13
|
+
* icons via `pb-map-icon`.
|
|
14
|
+
*
|
|
15
|
+
* @slot - may contain a series of `pb-map-layer` configurations
|
|
16
|
+
* @fires pb-leaflet-marker-click - Fires event to be processed by the map upon click
|
|
17
|
+
* @fires pb-update-map - When received, redraws the map to fit markers passed in with the event.
|
|
18
|
+
* Event details should include an array of locations, see `pb-geolocation` event below.
|
|
19
|
+
* @fires pb-update - When received, redraws the map to show markers for all pb-geolocation elements found in the content of the pb-view
|
|
20
|
+
* @fires pb-geolocation - When received, focuses the map on the geocoordinates passed in with the event.
|
|
21
|
+
* The event details should include an object:
|
|
22
|
+
* ```
|
|
23
|
+
* {
|
|
24
|
+
* coordinates: {
|
|
25
|
+
* latitude: Number,
|
|
26
|
+
* longitude: Number
|
|
27
|
+
* },
|
|
28
|
+
* label: string - the label to show on mouseover,
|
|
29
|
+
* zoom: Number - fixed zoom level to zoom to,
|
|
30
|
+
* fitBounds: Boolean - if true, recompute current zoom level to show all markers
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
* @fires pb-geocode - emitted if geocoding is enabled and the user searches or selects a location from the map
|
|
34
|
+
*/
|
|
35
|
+
export class PbLeafletMap extends pbMixin(LitElement) {
|
|
36
|
+
static get properties() {
|
|
37
|
+
return {
|
|
38
|
+
...super.properties,
|
|
39
|
+
latitude: {
|
|
40
|
+
type: Number
|
|
41
|
+
},
|
|
42
|
+
longitude: {
|
|
43
|
+
type: Number
|
|
44
|
+
},
|
|
45
|
+
zoom: {
|
|
46
|
+
type: Number
|
|
47
|
+
},
|
|
48
|
+
crs: {
|
|
49
|
+
type: String
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* If set, the map will automatically zoom so it can fit all the markers
|
|
53
|
+
*/
|
|
54
|
+
fitMarkers: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
attribute: 'fit-markers'
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* If set, combine markers into clusters if they are located too close together
|
|
60
|
+
* to display as single markers
|
|
61
|
+
*/
|
|
62
|
+
cluster: {
|
|
63
|
+
type: Boolean
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* Limits up to which zoom level markers are arranged into clusters.
|
|
67
|
+
* Using a higher zoom level here will result in more markers to be shown.
|
|
68
|
+
*
|
|
69
|
+
* Requires `cluster` option to be enabled.
|
|
70
|
+
*/
|
|
71
|
+
disableClusteringAt: {
|
|
72
|
+
type: Number,
|
|
73
|
+
attribute: 'disable-clustering-at'
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* If enabled, the map will not automatically scroll to the coordinates received via `pb-geolocation`
|
|
77
|
+
*/
|
|
78
|
+
noScroll: {
|
|
79
|
+
type: Boolean,
|
|
80
|
+
attribute: 'no-scroll'
|
|
81
|
+
},
|
|
82
|
+
accessToken: {
|
|
83
|
+
type: String,
|
|
84
|
+
attribute: 'access-token'
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* If enabled, the map will remain invisible until an event is received from `pb-geolocation`.
|
|
88
|
+
* In this case the map also offers a close button to hide it again.
|
|
89
|
+
*/
|
|
90
|
+
toggle: {
|
|
91
|
+
type: Boolean
|
|
92
|
+
},
|
|
93
|
+
imagesPath: {
|
|
94
|
+
type: String,
|
|
95
|
+
attribute: 'images-path'
|
|
96
|
+
},
|
|
97
|
+
cssPath: {
|
|
98
|
+
type: String,
|
|
99
|
+
attribute: 'css-path'
|
|
100
|
+
},
|
|
101
|
+
/**
|
|
102
|
+
* Enables geocoding: an additional control will allow users to search for a place.
|
|
103
|
+
* Reverse geocoding is also possible: single clicking on the map will request information
|
|
104
|
+
* about the current location.
|
|
105
|
+
*
|
|
106
|
+
* In both cases, a `pb-geocode` event will be emitted containing additional information
|
|
107
|
+
* about the place in the event details (see demo).
|
|
108
|
+
*
|
|
109
|
+
* For lookups the free OSM/Nominatim service is used.
|
|
110
|
+
*/
|
|
111
|
+
geoCoding: {
|
|
112
|
+
type: Boolean,
|
|
113
|
+
attribute: 'geo-coding'
|
|
114
|
+
},
|
|
115
|
+
_map: {
|
|
116
|
+
type: Object
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
constructor() {
|
|
122
|
+
super();
|
|
123
|
+
this.latitude = 51.505;
|
|
124
|
+
this.longitude = -0.09;
|
|
125
|
+
this.zoom = 15;
|
|
126
|
+
this.crs = 'EPSG3857';
|
|
127
|
+
this.accessToken = '';
|
|
128
|
+
this.imagesPath = '../images/leaflet/';
|
|
129
|
+
this.cssPath = '../css/leaflet';
|
|
130
|
+
this.toggle = false;
|
|
131
|
+
this.noScroll = false;
|
|
132
|
+
this.disabled = true;
|
|
133
|
+
this.cluster = false;
|
|
134
|
+
this.fitMarkers = false;
|
|
135
|
+
this.disableClusteringAt = null;
|
|
136
|
+
this._icons = {};
|
|
137
|
+
this.geoCoding = false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
connectedCallback() {
|
|
141
|
+
super.connectedCallback();
|
|
142
|
+
|
|
143
|
+
this._layers = this.querySelectorAll('pb-map-layer');
|
|
144
|
+
this._markers = this.querySelectorAll('pb-map-icon');
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Custom event which passes an array of pb-geolocation within event details
|
|
148
|
+
* @param {{ detail: any[]; }} ev
|
|
149
|
+
*/
|
|
150
|
+
this.subscribeTo('pb-update-map', (ev) => {
|
|
151
|
+
this._markerLayer.clearLayers();
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {{ latitude: any; longitude: any; label: any; }} loc
|
|
155
|
+
*/
|
|
156
|
+
/**
|
|
157
|
+
* @param {{ latitude: any; longitude: any; label: any; }} loc
|
|
158
|
+
*/
|
|
159
|
+
ev.detail.forEach((loc) => {
|
|
160
|
+
const marker = L.marker([loc.latitude, loc.longitude]);
|
|
161
|
+
if (loc.label) {
|
|
162
|
+
marker.bindTooltip(loc.label);
|
|
163
|
+
}
|
|
164
|
+
marker.addEventListener('click', () => {
|
|
165
|
+
this.emitTo('pb-leaflet-marker-click', loc);
|
|
166
|
+
});
|
|
167
|
+
marker.bindTooltip(loc.label);
|
|
168
|
+
this.setMarkerIcon(marker);
|
|
169
|
+
this._markerLayer.addLayer(marker);
|
|
170
|
+
});
|
|
171
|
+
this._fitBounds();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* React to pb-update event triggered by a pb-view
|
|
176
|
+
*
|
|
177
|
+
* @param {{ detail: { root: { querySelectorAll: (arg0: string) => any[]; }; }; }} ev
|
|
178
|
+
*/
|
|
179
|
+
this.subscribeTo('pb-update', (ev) => {
|
|
180
|
+
this._markerLayer.clearLayers();
|
|
181
|
+
const locations = ev.detail.root.querySelectorAll('pb-geolocation');
|
|
182
|
+
/**
|
|
183
|
+
* @param {{ latitude: any; longitude: any; }} loc
|
|
184
|
+
*/
|
|
185
|
+
locations.forEach((loc) => {
|
|
186
|
+
const coords = L.latLng(loc.latitude, loc.longitude);
|
|
187
|
+
const marker = L.marker(coords).addTo(this._markerLayer);
|
|
188
|
+
if (loc.label) {
|
|
189
|
+
marker.bindTooltip(loc.label);
|
|
190
|
+
}
|
|
191
|
+
if (loc.popup) {
|
|
192
|
+
marker.bindPopup(loc.popup);
|
|
193
|
+
}
|
|
194
|
+
marker.addEventListener('click', () => {
|
|
195
|
+
this.emitTo('pb-leaflet-marker-click', loc);
|
|
196
|
+
});
|
|
197
|
+
this.setMarkerIcon(marker);
|
|
198
|
+
});
|
|
199
|
+
this._fitBounds();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* React to events send by pb-geolocation
|
|
204
|
+
*
|
|
205
|
+
* @param {{ detail: { coordinates: { latitude: number; longitude: number; }, label: string; }; }} ev
|
|
206
|
+
*/
|
|
207
|
+
this.subscribeTo('pb-geolocation', (ev) => {
|
|
208
|
+
if (ev.detail.coordinates) {
|
|
209
|
+
this.latitude = ev.detail.coordinates.latitude;
|
|
210
|
+
this.longitude = ev.detail.coordinates.longitude;
|
|
211
|
+
if (ev.detail.clear) {
|
|
212
|
+
this._markerLayer.clearLayers();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!this._hasMarker(this.latitude, this.longitude)) {
|
|
216
|
+
const marker = L.marker([this.latitude, this.longitude]);
|
|
217
|
+
marker.addEventListener('click', () => {
|
|
218
|
+
this.emitTo('pb-leaflet-marker-click', ev.detail.element);
|
|
219
|
+
});
|
|
220
|
+
if (ev.detail.label) {
|
|
221
|
+
marker.bindTooltip(ev.detail.label);
|
|
222
|
+
}
|
|
223
|
+
if (ev.detail.popup) {
|
|
224
|
+
marker.bindPopup(ev.detail.popup);
|
|
225
|
+
}
|
|
226
|
+
this.setMarkerIcon(marker);
|
|
227
|
+
marker.addTo(this._markerLayer);
|
|
228
|
+
|
|
229
|
+
if (ev.detail.fitBounds) {
|
|
230
|
+
this._fitBounds();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log('<pb-leaflet-map> added marker');
|
|
234
|
+
} else {
|
|
235
|
+
console.log('<pb-leaflet-map> Marker already added to map');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (this.toggle) {
|
|
239
|
+
this.disabled = false;
|
|
240
|
+
}
|
|
241
|
+
const activateMarker = ev.detail.event;
|
|
242
|
+
this._locationChanged(this.latitude, this.longitude, ev.detail.zoom, activateMarker);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The underlying leafletjs map. Can be used for custom scripts.
|
|
249
|
+
*
|
|
250
|
+
* Will be null until the component is fully loaded. Listen to `pb-ready` on the component to
|
|
251
|
+
* be sure it has initialized.
|
|
252
|
+
*/
|
|
253
|
+
get map() {
|
|
254
|
+
return this._map;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
setMarkerIcon(layer) {
|
|
258
|
+
if (this._icons && this._icons.default) {
|
|
259
|
+
layer.setIcon(this._icons.default);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async firstUpdated() {
|
|
264
|
+
if (!this.toggle) {
|
|
265
|
+
this.disabled = false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (window.L !== undefined) {
|
|
269
|
+
this._initMap();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
window.ESGlobalBridge.requestAvailability();
|
|
274
|
+
const leafletPath = resolveURL('../lib/leaflet-src.js');
|
|
275
|
+
const pluginPath = resolveURL('../lib/leaflet.markercluster-src.js');
|
|
276
|
+
const geoCodingPath = resolveURL('../lib/Control.Geocoder.min.js');
|
|
277
|
+
await window.ESGlobalBridge.instance.load("leaflet", leafletPath);
|
|
278
|
+
await window.ESGlobalBridge.instance.load("plugin", pluginPath);
|
|
279
|
+
if (this.geoCoding) {
|
|
280
|
+
await window.ESGlobalBridge.instance.load("geocoding", geoCodingPath);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
window.addEventListener(
|
|
284
|
+
`es-bridge-${this.geocoding ? 'geoCoding' : 'plugin'}-loaded`,
|
|
285
|
+
this._initMap.bind(this),
|
|
286
|
+
{ once: true }
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
render() {
|
|
291
|
+
const cssPath = resolveURL(this.cssPath);
|
|
292
|
+
return html`
|
|
293
|
+
<link rel="Stylesheet" href="${cssPath}/leaflet.css">
|
|
294
|
+
<link rel="Stylesheet" href="${cssPath}/MarkerCluster.Default.css">
|
|
295
|
+
${this.geoCoding ? html`<link rel="Stylesheet" href="${cssPath}/Control.Geocoder.css">` : null}
|
|
296
|
+
<div id="map" style="height: 100%; width: 100%"></div>
|
|
297
|
+
`;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
static get styles() {
|
|
301
|
+
return css`
|
|
302
|
+
:host {
|
|
303
|
+
display: block;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
:host([disabled]) {
|
|
307
|
+
visibility: hidden;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.close {
|
|
311
|
+
border-radius: 4px;
|
|
312
|
+
background-color: #fff;
|
|
313
|
+
color: inherit;
|
|
314
|
+
padding: 8px;
|
|
315
|
+
font-size: 18px;
|
|
316
|
+
font-weight: bold;
|
|
317
|
+
text-decoration: none;
|
|
318
|
+
cursor: pointer;
|
|
319
|
+
}
|
|
320
|
+
`;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
_initMap() {
|
|
324
|
+
if (this._map) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
L.Icon.Default.imagePath = resolveURL(this.imagesPath);
|
|
329
|
+
|
|
330
|
+
const crs = L.CRS[this.crs] || L.CRS.EPSG3857;
|
|
331
|
+
this._map = L.map(this.shadowRoot.getElementById('map'), {
|
|
332
|
+
zoom: this.zoom,
|
|
333
|
+
center: L.latLng(this.latitude, this.longitude),
|
|
334
|
+
crs
|
|
335
|
+
});
|
|
336
|
+
this._configureLayers();
|
|
337
|
+
this._configureMarkers();
|
|
338
|
+
|
|
339
|
+
if (this.cluster) {
|
|
340
|
+
const options = {};
|
|
341
|
+
if (this.disableClusteringAt) {
|
|
342
|
+
options.disableClusteringAtZoom = this.disableClusteringAt;
|
|
343
|
+
}
|
|
344
|
+
this._markerLayer = L.markerClusterGroup(options);
|
|
345
|
+
} else {
|
|
346
|
+
this._markerLayer = L.layerGroup();
|
|
347
|
+
}
|
|
348
|
+
this._markerLayer.addTo(this._map);
|
|
349
|
+
|
|
350
|
+
this.signalReady();
|
|
351
|
+
|
|
352
|
+
L.control.scale().addTo(this._map);
|
|
353
|
+
|
|
354
|
+
if (this.toggle) {
|
|
355
|
+
let container;
|
|
356
|
+
L.Control.CloseButton = L.Control.extend({
|
|
357
|
+
options: {
|
|
358
|
+
position: 'topright'
|
|
359
|
+
},
|
|
360
|
+
onAdd: (map) => {
|
|
361
|
+
container = L.DomUtil.create('div');
|
|
362
|
+
container.className = 'close';
|
|
363
|
+
container.innerHTML = 'X';
|
|
364
|
+
L.DomEvent.on(container, 'click', this._hide.bind(this));
|
|
365
|
+
return container;
|
|
366
|
+
},
|
|
367
|
+
onRemove: (map) => {
|
|
368
|
+
L.DomEvent.off(container, 'click', this._hide.bind(this));
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
L.control.closeButton = (options) => new L.Control.CloseButton(options);
|
|
372
|
+
L.control.closeButton({ position: 'topright' }).addTo(this._map);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
this._configureGeoCoding();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
_configureGeoCoding() {
|
|
379
|
+
if (!this.geoCoding) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const geocoder = L.Control.Geocoder.nominatim({
|
|
383
|
+
geocodingQueryParams: {
|
|
384
|
+
'accept-language': 'en'
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
const control = L.Control.geocoder({
|
|
388
|
+
defaultMarkGeocode: false,
|
|
389
|
+
geocoder,
|
|
390
|
+
placeholder: i18n('search.search'),
|
|
391
|
+
suggestMinLength: 3
|
|
392
|
+
});
|
|
393
|
+
control.on('markgeocode', (e) => {
|
|
394
|
+
const {geocode} = e;
|
|
395
|
+
const options = {
|
|
396
|
+
coordinates: {
|
|
397
|
+
longitude: geocode.center.lng,
|
|
398
|
+
latitude: geocode.center.lat,
|
|
399
|
+
},
|
|
400
|
+
name: geocode.name,
|
|
401
|
+
label: geocode.html,
|
|
402
|
+
properties: geocode.properties
|
|
403
|
+
};
|
|
404
|
+
this.emitTo('pb-geocode', options);
|
|
405
|
+
});
|
|
406
|
+
control.addTo(this._map);
|
|
407
|
+
|
|
408
|
+
this._map.on('click', (e) => {
|
|
409
|
+
geocoder.reverse(e.latlng, this._map.options.crs.scale(this._map.getZoom()), (results) => {
|
|
410
|
+
const geocode = results[0];
|
|
411
|
+
const options = {
|
|
412
|
+
coordinates: {
|
|
413
|
+
longitude: geocode.center.lng,
|
|
414
|
+
latitude: geocode.center.lat,
|
|
415
|
+
},
|
|
416
|
+
name: geocode.name,
|
|
417
|
+
label: geocode.html,
|
|
418
|
+
properties: geocode.properties
|
|
419
|
+
};
|
|
420
|
+
this.emitTo('pb-geocode', options);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
_configureMarkers() {
|
|
426
|
+
if (this._markers.length === 0) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
this._icons = {};
|
|
431
|
+
this._markers.forEach(config => {
|
|
432
|
+
if (config.iconUrl) {
|
|
433
|
+
this._icons[config.name] = L.icon(config.options);
|
|
434
|
+
}
|
|
435
|
+
})
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
_configureLayers() {
|
|
439
|
+
if (this._layers.length === 0) {
|
|
440
|
+
// configure a default layer
|
|
441
|
+
L.tileLayer('https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token={accessToken}', {
|
|
442
|
+
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
|
|
443
|
+
maxZoom: 18,
|
|
444
|
+
zoomOffset: -1,
|
|
445
|
+
tileSize: 512,
|
|
446
|
+
accessToken: this.accessToken
|
|
447
|
+
}).addTo(this._map);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
const layers = L.control.layers(null, null, { collapsed: false });
|
|
451
|
+
this._layers.forEach(config => {
|
|
452
|
+
let layer;
|
|
453
|
+
switch (config.type) {
|
|
454
|
+
case 'geojson':
|
|
455
|
+
config.data().then((data) => {
|
|
456
|
+
layer = L.geoJSON([data]);
|
|
457
|
+
this._addLayer(config, layer, layers);
|
|
458
|
+
});
|
|
459
|
+
break;
|
|
460
|
+
default:
|
|
461
|
+
layer = L.tileLayer(config.url, config.options);
|
|
462
|
+
this._addLayer(config, layer, layers);
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
// only show layer control if there's more than one layer
|
|
467
|
+
if (this._layers.length > 1) {
|
|
468
|
+
layers.addTo(this._map);
|
|
469
|
+
}
|
|
470
|
+
this._layers = null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
_addLayer(config, layer, layers) {
|
|
474
|
+
if (config.show) {
|
|
475
|
+
layer.addTo(this._map);
|
|
476
|
+
}
|
|
477
|
+
if (config.label) {
|
|
478
|
+
if (config.base) {
|
|
479
|
+
layers.addBaseLayer(layer, config.label);
|
|
480
|
+
} else {
|
|
481
|
+
layers.addOverlay(layer, config.label);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
_fitBounds() {
|
|
487
|
+
if (!this.fitMarkers) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const bounds = L.latLngBounds();
|
|
491
|
+
let len = 0;
|
|
492
|
+
this._markerLayer.eachLayer((layer) => {
|
|
493
|
+
bounds.extend(layer.getLatLng());
|
|
494
|
+
len += 1;
|
|
495
|
+
});
|
|
496
|
+
if (len === 0) {
|
|
497
|
+
this._map.fitWorld();
|
|
498
|
+
} else if (len === 1) {
|
|
499
|
+
this._map.fitBounds(bounds, {maxZoom: this.zoom});
|
|
500
|
+
} else {
|
|
501
|
+
this._map.fitBounds(bounds);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
_locationChanged(lat, long, zoom, setActive) {
|
|
506
|
+
if (this._map) {
|
|
507
|
+
const coords = L.latLng([lat, long]);
|
|
508
|
+
this._markerLayer.eachLayer((layer) => {
|
|
509
|
+
if (layer.getLatLng().equals(coords)) {
|
|
510
|
+
if (zoom && !this.noScroll) {
|
|
511
|
+
layer.openTooltip();
|
|
512
|
+
this._map.setView(coords, zoom);
|
|
513
|
+
} else if (this.cluster) {
|
|
514
|
+
this._markerLayer.zoomToShowLayer(layer, () =>
|
|
515
|
+
layer.openTooltip()
|
|
516
|
+
);
|
|
517
|
+
} else {
|
|
518
|
+
layer.openTooltip();
|
|
519
|
+
this._map.setView(coords, this.zoom);
|
|
520
|
+
}
|
|
521
|
+
if (setActive && this._icons && this._icons.active) {
|
|
522
|
+
layer.setIcon(this._icons.active);
|
|
523
|
+
}
|
|
524
|
+
} else if (this._icons && this._icons.default && layer.getIcon() !== this._icons.default) {
|
|
525
|
+
layer.setIcon(this._icons.default);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
_hasMarker(lat, long) {
|
|
532
|
+
const coords = L.latLng([lat, long]);
|
|
533
|
+
let found = null;
|
|
534
|
+
this._markerLayer.eachLayer((layer) => {
|
|
535
|
+
if (layer instanceof L.Marker && layer.getLatLng().equals(coords)) {
|
|
536
|
+
found = layer;
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
return found;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
_hide() {
|
|
543
|
+
this.disabled = true;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
464
546
|
customElements.define('pb-leaflet-map', PbLeafletMap);
|