@teipublisher/pb-components 1.31.0 → 1.33.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.
@@ -30,9 +30,24 @@ export class PbGeolocation extends PbHighlight {
30
30
  label: {
31
31
  type: String
32
32
  },
33
+ /**
34
+ * Name of the event which triggers a pb-geolocation event, e.g. 'click'.
35
+ * Default is 'mouseover'.
36
+ */
33
37
  event: {
34
38
  type: String
35
39
  },
40
+ /**
41
+ * Zoom level to use for the map if it centers on the location.
42
+ */
43
+ zoom: {
44
+ type: Number
45
+ },
46
+ /**
47
+ * If set, add location to a map automatically upon load by
48
+ * emitting an event. If not set, locations are only added when
49
+ * the configured event is triggered.
50
+ */
36
51
  auto: {
37
52
  type: Boolean
38
53
  }
@@ -43,6 +58,7 @@ export class PbGeolocation extends PbHighlight {
43
58
  super();
44
59
  this.event = 'mouseover';
45
60
  this.auto = false;
61
+ this.zoom = null;
46
62
  }
47
63
 
48
64
  connectedCallback() {
@@ -56,6 +72,7 @@ export class PbGeolocation extends PbHighlight {
56
72
  longitude: this.longitude
57
73
  },
58
74
  label: this.label,
75
+ zoom: this.zoom,
59
76
  popup: this.popup,
60
77
  element: this
61
78
  })
@@ -70,6 +87,7 @@ export class PbGeolocation extends PbHighlight {
70
87
  },
71
88
  label: this.label,
72
89
  popup: this.popup,
90
+ fitBounds: true,
73
91
  element: this
74
92
  });
75
93
  });
@@ -1,5 +1,5 @@
1
1
  import { LitElement, html, css } from 'lit-element';
2
- import * as L from 'leaflet/dist/leaflet-src.esm.js';
2
+ import "@lrnwebcomponents/es-global-bridge";
3
3
  import { pbMixin } from './pb-mixin.js';
4
4
  import { resolveURL } from './utils.js';
5
5
  import './pb-map-layer.js';
@@ -9,9 +9,22 @@ import './pb-map-layer.js';
9
9
  *
10
10
  * @slot - may contain a series of `pb-map-layer` configurations
11
11
  * @fires pb-leaflet-marker-click - Fires event to be processed by the map upon click
12
- * @fires pb-update-map - When received, redraws the map to fit markers passed in with the event
13
- * @fires pb-update - When received, redraws the map to show markers for all pb-geolocation elements
14
- * @fires pb-geolocation - When received, focuses the map on the geocoordinates passed in with the event
12
+ * @fires pb-update-map - When received, redraws the map to fit markers passed in with the event.
13
+ * Event details should include an array of locations, see `pb-geolocation` event below.
14
+ * @fires pb-update - When received, redraws the map to show markers for all pb-geolocation elements found in the content of the pb-view
15
+ * @fires pb-geolocation - When received, focuses the map on the geocoordinates passed in with the event.
16
+ * The event details should include an object:
17
+ * ```
18
+ * {
19
+ * coordinates: {
20
+ * latitude: Number,
21
+ * longitude: Number
22
+ * },
23
+ * label: string - the label to show on mouseover,
24
+ * zoom: Number - fixed zoom level to zoom to,
25
+ * fitBounds: Boolean - if true, recompute current zoom level to show all markers
26
+ * }
27
+ * ```
15
28
  */
16
29
  export class PbLeafletMap extends pbMixin(LitElement) {
17
30
  static get properties() {
@@ -29,6 +42,30 @@ export class PbLeafletMap extends pbMixin(LitElement) {
29
42
  crs: {
30
43
  type: String
31
44
  },
45
+ /**
46
+ * If set, the map will automatically zoom so it can fit all the markers
47
+ */
48
+ fitMarkers: {
49
+ type: Boolean,
50
+ attribute: 'fit-markers'
51
+ },
52
+ /**
53
+ * If set, combine markers into clusters if they are located too close together
54
+ * to display as single markers
55
+ */
56
+ cluster: {
57
+ type: Boolean
58
+ },
59
+ /**
60
+ * Limits up to which zoom level markers are arranged into clusters.
61
+ * Using a higher zoom level here will result in more markers to be shown.
62
+ *
63
+ * Requires `cluster` option to be enabled.
64
+ */
65
+ disableClusteringAt: {
66
+ type: Number,
67
+ attribute: 'disable-clustering-at'
68
+ },
32
69
  /**
33
70
  * If enabled, the map will not automatically scroll to the coordinates received via `pb-geolocation`
34
71
  */
@@ -73,6 +110,9 @@ export class PbLeafletMap extends pbMixin(LitElement) {
73
110
  this.toggle = false;
74
111
  this.noScroll = false;
75
112
  this.disabled = true;
113
+ this.cluster = false;
114
+ this.fitMarkers = false;
115
+ this.disableClusteringAt = null;
76
116
  }
77
117
 
78
118
  connectedCallback() {
@@ -85,7 +125,8 @@ export class PbLeafletMap extends pbMixin(LitElement) {
85
125
  * @param {{ detail: any[]; }} ev
86
126
  */
87
127
  this.subscribeTo('pb-update-map', (ev) => {
88
- const bounds = L.latLngBounds();
128
+ this._markerLayer.clearLayers();
129
+
89
130
  /**
90
131
  * @param {{ latitude: any; longitude: any; label: any; }} loc
91
132
  */
@@ -101,14 +142,9 @@ export class PbLeafletMap extends pbMixin(LitElement) {
101
142
  this.emitTo('pb-leaflet-marker-click', loc);
102
143
  });
103
144
  marker.bindTooltip(loc.label);
104
- marker.addTo(this._map);
105
- bounds.extend([loc.latitude, loc.longitude]);
145
+ this._markerLayer.addLayer(marker);
106
146
  });
107
- if (ev.detail.length > 1) {
108
- this._map.fitBounds(bounds);
109
- } else {
110
- this._map.setZoom(this.zoom);
111
- }
147
+ this._fitBounds();
112
148
  });
113
149
 
114
150
  /**
@@ -117,20 +153,14 @@ export class PbLeafletMap extends pbMixin(LitElement) {
117
153
  * @param {{ detail: { root: { querySelectorAll: (arg0: string) => any[]; }; }; }} ev
118
154
  */
119
155
  this.subscribeTo('pb-update', (ev) => {
120
- this._map.eachLayer((layer) => {
121
- if (layer instanceof L.Marker) {
122
- layer.remove();
123
- }
124
- });
125
- const bounds = L.latLngBounds();
156
+ this._markerLayer.clearLayers();
126
157
  const locations = ev.detail.root.querySelectorAll('pb-geolocation');
127
158
  /**
128
159
  * @param {{ latitude: any; longitude: any; }} loc
129
160
  */
130
161
  locations.forEach((loc) => {
131
162
  const coords = L.latLng(loc.latitude, loc.longitude);
132
- bounds.extend(coords);
133
- const marker = L.marker(coords).addTo(this._map);
163
+ const marker = L.marker(coords).addTo(this._markerLayer);
134
164
  if (loc.label) {
135
165
  marker.bindTooltip(loc.label);
136
166
  }
@@ -141,14 +171,7 @@ export class PbLeafletMap extends pbMixin(LitElement) {
141
171
  this.emitTo('pb-leaflet-marker-click', loc);
142
172
  });
143
173
  });
144
- // this._map.invalidateSize();
145
- if (locations.length === 0) {
146
- this._map.fitWorld();
147
- } else if (locations.length === 1) {
148
- this._map.fitBounds(bounds, {maxZoom: this.zoom});
149
- } else {
150
- this._map.fitBounds(bounds);
151
- }
174
+ this._fitBounds();
152
175
  });
153
176
 
154
177
  /**
@@ -171,7 +194,12 @@ export class PbLeafletMap extends pbMixin(LitElement) {
171
194
  if (ev.detail.popup) {
172
195
  marker.bindPopup(ev.detail.popup);
173
196
  }
174
- marker.addTo(this._map);
197
+ marker.addTo(this._markerLayer);
198
+
199
+ if (ev.detail.fitBounds) {
200
+ this._fitBounds();
201
+ }
202
+
175
203
  console.log('<pb-leaflet-map> added marker');
176
204
  } else {
177
205
  console.log('<pb-leaflet-map> Marker already added to map');
@@ -179,7 +207,7 @@ export class PbLeafletMap extends pbMixin(LitElement) {
179
207
  if (this.toggle) {
180
208
  this.disabled = false;
181
209
  }
182
- this._locationChanged();
210
+ this._locationChanged(this.latitude, this.longitude, ev.detail.zoom);
183
211
  }
184
212
  });
185
213
  }
@@ -188,13 +216,23 @@ export class PbLeafletMap extends pbMixin(LitElement) {
188
216
  if (!this.toggle) {
189
217
  this.disabled = false;
190
218
  }
191
- this._initMap();
219
+ window.ESGlobalBridge.requestAvailability();
220
+ const leafletPath = resolveURL('../lib/leaflet-src.js');
221
+ const pluginPath = resolveURL('../lib/leaflet.markercluster-src.js');
222
+ window.ESGlobalBridge.instance.load("leaflet", leafletPath)
223
+ .then(() => window.ESGlobalBridge.instance.load("plugin", pluginPath));
224
+ window.addEventListener(
225
+ "es-bridge-plugin-loaded",
226
+ this._initMap.bind(this),
227
+ { once: true }
228
+ );
192
229
  }
193
230
 
194
231
  render() {
195
232
  const cssPath = resolveURL(this.cssPath);
196
233
  return html`
197
234
  <link rel="Stylesheet" href="${cssPath}/leaflet.css">
235
+ <link rel="Stylesheet" href="${cssPath}/MarkerCluster.Default.css">
198
236
  <div id="map" style="height: 100%; width: 100%"></div>
199
237
  `;
200
238
  }
@@ -236,6 +274,18 @@ export class PbLeafletMap extends pbMixin(LitElement) {
236
274
  crs
237
275
  });
238
276
  this._configureLayers();
277
+
278
+ if (this.cluster) {
279
+ const options = {};
280
+ if (this.disableClusteringAt) {
281
+ options.disableClusteringAtZoom = this.disableClusteringAt;
282
+ }
283
+ this._markerLayer = L.markerClusterGroup(options);
284
+ } else {
285
+ this._markerLayer = L.layerGroup();
286
+ }
287
+ this._markerLayer.addTo(this._map);
288
+
239
289
  this.signalReady();
240
290
 
241
291
  L.control.scale().addTo(this._map);
@@ -310,27 +360,50 @@ export class PbLeafletMap extends pbMixin(LitElement) {
310
360
  }
311
361
  }
312
362
 
313
- _locationChanged() {
363
+ _fitBounds() {
364
+ if (!this.fitMarkers) {
365
+ return;
366
+ }
367
+ const bounds = L.latLngBounds();
368
+ let len = 0;
369
+ this._markerLayer.eachLayer((layer) => {
370
+ bounds.extend(layer.getLatLng());
371
+ len += 1;
372
+ });
373
+ if (len === 0) {
374
+ this._map.fitWorld();
375
+ } else if (len === 1) {
376
+ this._map.fitBounds(bounds, {maxZoom: this.zoom});
377
+ } else {
378
+ this._map.fitBounds(bounds);
379
+ }
380
+ }
381
+
382
+ _locationChanged(lat, long, zoom) {
314
383
  if (this._map) {
315
- const coords = L.latLng([this.latitude, this.longitude]);
316
- this._map.eachLayer((layer) => {
317
- if (layer instanceof L.Marker) {
318
- if (layer.getLatLng().equals(coords)) {
384
+ const coords = L.latLng([lat, long]);
385
+ this._markerLayer.eachLayer((layer) => {
386
+ if (layer.getLatLng().equals(coords)) {
387
+ if (zoom && !this.noScroll) {
319
388
  layer.openTooltip();
389
+ this._map.setView(coords, zoom);
390
+ } else if (this.cluster) {
391
+ this._markerLayer.zoomToShowLayer(layer, () =>
392
+ layer.openTooltip()
393
+ );
320
394
  } else {
321
- layer.closeTooltip();
395
+ layer.openTooltip();
396
+ this._map.setView(coords, this.zoom);
322
397
  }
323
398
  }
324
399
  });
325
- if (!this.noScroll)
326
- this._map.setView(coords, this.zoom);
327
400
  }
328
401
  }
329
402
 
330
403
  _hasMarker(lat, long) {
331
404
  const coords = L.latLng([lat, long]);
332
405
  let found = false;
333
- this._map.eachLayer((layer) => {
406
+ this._markerLayer.eachLayer((layer) => {
334
407
  if (layer instanceof L.Marker && layer.getLatLng().equals(coords)) {
335
408
  found = true;
336
409
  }
@@ -49,9 +49,6 @@ export class PbSplitList extends pbMixin(LitElement) {
49
49
  _categories: {
50
50
  type: Array
51
51
  },
52
- _items: {
53
- type: Array
54
- },
55
52
  ...super.properties
56
53
  };
57
54
  }
@@ -59,7 +56,6 @@ export class PbSplitList extends pbMixin(LitElement) {
59
56
  constructor() {
60
57
  super();
61
58
  this._categories = [];
62
- this._items = [];
63
59
  this._params = {};
64
60
  this.selected = null;
65
61
  this.subforms = null;
@@ -112,7 +108,7 @@ export class PbSplitList extends pbMixin(LitElement) {
112
108
  })
113
109
  .then((json) => {
114
110
  this._categories = json.categories;
115
- this._items = json.items;
111
+ this.innerHTML = json.items.join('');
116
112
  this.emitTo('pb-end-update');
117
113
  })
118
114
  .catch((error) => {
@@ -152,11 +148,7 @@ export class PbSplitList extends pbMixin(LitElement) {
152
148
  )
153
149
  }
154
150
  </header>
155
- <div id="items" part="items">
156
- ${
157
- this._items.map((item) => html`<div part="item">${unsafeHTML(item)}</div>`)
158
- }
159
- </div>
151
+ <div id="items" part="items"><slot></slot></div>
160
152
  `;
161
153
  }
162
154
 
@@ -167,10 +159,10 @@ export class PbSplitList extends pbMixin(LitElement) {
167
159
  }
168
160
 
169
161
  header {
170
- display: grid;
171
- grid-auto-flow: column;
172
- width: 100%;
162
+ display: flex;
163
+ flex-wrap: wrap;
173
164
  column-gap: 10px;
165
+ width: 100%;
174
166
  }
175
167
 
176
168
  #items {