@panoramax/web-viewer 3.2.3-develop-dfee2adc → 3.2.3-develop-357c83ca

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.
@@ -89,6 +89,7 @@ jest.mock("maplibre-gl", () => ({
89
89
  constructor(opts) {
90
90
  this._mapOpts = opts;
91
91
  this._handlers = {};
92
+ this._handlersOnce = {};
92
93
  }
93
94
  getContainer() {
94
95
  return this._mapOpts.container;
@@ -98,6 +99,7 @@ jest.mock("maplibre-gl", () => ({
98
99
  addLayer() {;}
99
100
  getLayer() {;}
100
101
  setLayoutProperty() {;}
102
+ setPaintProperty() {;}
101
103
  getStyle() {
102
104
  return {
103
105
  layers: [],
@@ -110,8 +112,16 @@ jest.mock("maplibre-gl", () => ({
110
112
  if(!this._handlers[type]) { this._handlers[type] = []; }
111
113
  this._handlers[type].push(handler);
112
114
  }
115
+ once(type, handler) {
116
+ if(!this._handlersOnce[type]) { this._handlersOnce[type] = []; }
117
+ this._handlersOnce[type].push(handler);
118
+ }
113
119
  fire(type, opts) {
114
120
  this._handlers[type]?.forEach(f => f(opts));
121
+ this._handlersOnce?.[type]?.forEach(f => f(opts));
122
+ if(this._handlersOnce?.[type]) {
123
+ this._handlersOnce[type] = [];
124
+ }
115
125
  }
116
126
  },
117
127
  LngLat: function() {
@@ -164,13 +164,28 @@ Event for sequence/picture selection
164
164
  <a name="Panoramax.components.core.Basic+event_ready"></a>
165
165
 
166
166
  ### "ready"
167
- Event for component being ready to use (API loaded)
167
+ Event when component is ready to use.
168
+ This happens when loader screen disappear, with picture and map loaded.
169
+
170
+ To follow more precisely loading steps, you can also watch for sub-components `ready` events.
171
+ ```js
172
+ // Watch API-readiness
173
+ viewer.addEventListener("api:ready", ...); // From parent
174
+ viewer.api.addEventListener("ready", ...); // Or on sub-component
175
+ ```
168
176
 
169
177
  **Kind**: event emitted by [<code>Basic</code>](#Panoramax.components.core.Basic)
170
178
  <a name="Panoramax.components.core.Basic+event_broken"></a>
171
179
 
172
180
  ### "broken"
173
- Event for viewer failing to initially load
181
+ Event for viewer failing to initially load.
182
+
183
+ To follow more precisely loading failures, you can also watch for sub-components `broken` events.
184
+ ```js
185
+ // Watch API breaks
186
+ viewer.addEventListener("api:broken", ...); // From parent
187
+ viewer.api.addEventListener("broken", ...); // Or on sub-component
188
+ ```
174
189
 
175
190
  **Kind**: event emitted by [<code>Basic</code>](#Panoramax.components.core.Basic)
176
191
  **Properties**
@@ -178,13 +178,28 @@ Event for sequence/picture selection
178
178
  <a name="Panoramax.components.core.Basic+event_ready"></a>
179
179
 
180
180
  ### "ready"
181
- Event for component being ready to use (API loaded)
181
+ Event when component is ready to use.
182
+ This happens when loader screen disappear, with picture and map loaded.
183
+
184
+ To follow more precisely loading steps, you can also watch for sub-components `ready` events.
185
+ ```js
186
+ // Watch API-readiness
187
+ viewer.addEventListener("api:ready", ...); // From parent
188
+ viewer.api.addEventListener("ready", ...); // Or on sub-component
189
+ ```
182
190
 
183
191
  **Kind**: event emitted by [<code>CoverageMap</code>](#Panoramax.components.core.CoverageMap)
184
192
  <a name="Panoramax.components.core.Basic+event_broken"></a>
185
193
 
186
194
  ### "broken"
187
- Event for viewer failing to initially load
195
+ Event for viewer failing to initially load.
196
+
197
+ To follow more precisely loading failures, you can also watch for sub-components `broken` events.
198
+ ```js
199
+ // Watch API breaks
200
+ viewer.addEventListener("api:broken", ...); // From parent
201
+ viewer.api.addEventListener("broken", ...); // Or on sub-component
202
+ ```
188
203
 
189
204
  **Kind**: event emitted by [<code>CoverageMap</code>](#Panoramax.components.core.CoverageMap)
190
205
  **Properties**
@@ -193,13 +193,28 @@ Event for sequence/picture selection
193
193
  <a name="Panoramax.components.core.Basic+event_ready"></a>
194
194
 
195
195
  ### "ready"
196
- Event for component being ready to use (API loaded)
196
+ Event when component is ready to use.
197
+ This happens when loader screen disappear, with picture and map loaded.
198
+
199
+ To follow more precisely loading steps, you can also watch for sub-components `ready` events.
200
+ ```js
201
+ // Watch API-readiness
202
+ viewer.addEventListener("api:ready", ...); // From parent
203
+ viewer.api.addEventListener("ready", ...); // Or on sub-component
204
+ ```
197
205
 
198
206
  **Kind**: event emitted by [<code>Editor</code>](#Panoramax.components.core.Editor)
199
207
  <a name="Panoramax.components.core.Basic+event_broken"></a>
200
208
 
201
209
  ### "broken"
202
- Event for viewer failing to initially load
210
+ Event for viewer failing to initially load.
211
+
212
+ To follow more precisely loading failures, you can also watch for sub-components `broken` events.
213
+ ```js
214
+ // Watch API breaks
215
+ viewer.addEventListener("api:broken", ...); // From parent
216
+ viewer.api.addEventListener("broken", ...); // Or on sub-component
217
+ ```
203
218
 
204
219
  **Kind**: event emitted by [<code>Editor</code>](#Panoramax.components.core.Editor)
205
220
  **Properties**
@@ -273,13 +273,28 @@ Event for sequence/picture selection
273
273
  <a name="Panoramax.components.core.Basic+event_ready"></a>
274
274
 
275
275
  ### "ready"
276
- Event for component being ready to use (API loaded)
276
+ Event when component is ready to use.
277
+ This happens when loader screen disappear, with picture and map loaded.
278
+
279
+ To follow more precisely loading steps, you can also watch for sub-components `ready` events.
280
+ ```js
281
+ // Watch API-readiness
282
+ viewer.addEventListener("api:ready", ...); // From parent
283
+ viewer.api.addEventListener("ready", ...); // Or on sub-component
284
+ ```
277
285
 
278
286
  **Kind**: event emitted by [<code>PhotoViewer</code>](#Panoramax.components.core.PhotoViewer)
279
287
  <a name="Panoramax.components.core.Basic+event_broken"></a>
280
288
 
281
289
  ### "broken"
282
- Event for viewer failing to initially load
290
+ Event for viewer failing to initially load.
291
+
292
+ To follow more precisely loading failures, you can also watch for sub-components `broken` events.
293
+ ```js
294
+ // Watch API breaks
295
+ viewer.addEventListener("api:broken", ...); // From parent
296
+ viewer.api.addEventListener("broken", ...); // Or on sub-component
297
+ ```
283
298
 
284
299
  **Kind**: event emitted by [<code>PhotoViewer</code>](#Panoramax.components.core.PhotoViewer)
285
300
  **Properties**
@@ -316,13 +316,28 @@ Event for sequence/picture selection
316
316
  <a name="Panoramax.components.core.Basic+event_ready"></a>
317
317
 
318
318
  ### "ready"
319
- Event for component being ready to use (API loaded)
319
+ Event when component is ready to use.
320
+ This happens when loader screen disappear, with picture and map loaded.
321
+
322
+ To follow more precisely loading steps, you can also watch for sub-components `ready` events.
323
+ ```js
324
+ // Watch API-readiness
325
+ viewer.addEventListener("api:ready", ...); // From parent
326
+ viewer.api.addEventListener("ready", ...); // Or on sub-component
327
+ ```
320
328
 
321
329
  **Kind**: event emitted by [<code>Viewer</code>](#Panoramax.components.core.Viewer)
322
330
  <a name="Panoramax.components.core.Basic+event_broken"></a>
323
331
 
324
332
  ### "broken"
325
- Event for viewer failing to initially load
333
+ Event for viewer failing to initially load.
334
+
335
+ To follow more precisely loading failures, you can also watch for sub-components `broken` events.
336
+ ```js
337
+ // Watch API breaks
338
+ viewer.addEventListener("api:broken", ...); // From parent
339
+ viewer.api.addEventListener("broken", ...); // Or on sub-component
340
+ ```
326
341
 
327
342
  **Kind**: event emitted by [<code>Viewer</code>](#Panoramax.components.core.Viewer)
328
343
  **Properties**
@@ -3,7 +3,7 @@
3
3
  ## Panoramax.components.ui.Map ⇐ <code>[maplibregl.Map](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/)</code>
4
4
  **Kind**: static class of <code>Panoramax.components.ui</code>
5
5
  **Extends**: <code>[maplibregl.Map](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/)</code>
6
- **Emits**: [<code>background-changed</code>](#Panoramax.components.ui.Map+event_background-changed), [<code>users-changed</code>](#Panoramax.components.ui.Map+event_users-changed), [<code>sequence-hover</code>](#Panoramax.components.ui.Map+event_sequence-hover), [<code>sequence-click</code>](#Panoramax.components.ui.Map+event_sequence-click), [<code>picture-click</code>](#Panoramax.components.ui.Map+event_picture-click)
6
+ **Emits**: [<code>background-changed</code>](#Panoramax.components.ui.Map+event_background-changed), [<code>users-changed</code>](#Panoramax.components.ui.Map+event_users-changed), [<code>sequence-hover</code>](#Panoramax.components.ui.Map+event_sequence-hover), [<code>sequence-click</code>](#Panoramax.components.ui.Map+event_sequence-click), [<code>picture-click</code>](#Panoramax.components.ui.Map+event_picture-click), [<code>ready</code>](#Panoramax.components.ui.Map+event_ready)
7
7
 
8
8
  * [.Map](#Panoramax.components.ui.Map) ⇐ <code>[maplibregl.Map](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/)</code>
9
9
  * [new Map(parent, container, [options])](#new_Panoramax.components.ui.Map_new)
@@ -18,6 +18,8 @@
18
18
  * [.filterUserLayersContent(dataType, filter)](#Panoramax.components.ui.Map+filterUserLayersContent)
19
19
  * [.displayPictureMarker(lon, lat, heading, [skipCenter])](#Panoramax.components.ui.Map+displayPictureMarker)
20
20
  * [.reloadLayersStyles()](#Panoramax.components.ui.Map+reloadLayersStyles)
21
+ * [.addEventListener(type, listener)](#Panoramax.components.ui.Map+addEventListener)
22
+ * ["ready"](#Panoramax.components.ui.Map+event_ready)
21
23
  * ["background-changed"](#Panoramax.components.ui.Map+event_background-changed)
22
24
  * ["users-changed"](#Panoramax.components.ui.Map+event_users-changed)
23
25
  * ["sequence-hover"](#Panoramax.components.ui.Map+event_sequence-hover)
@@ -36,6 +38,7 @@ A more complete version of Map (with filters & themes) is available through [Map
36
38
  ⚠️ This class doesn't inherit from [EventTarget](https://developer.mozilla.org/fr/docs/Web/API/EventTarget), so it doesn't have `addEventListener` and `dispatchEvent` functions.
37
39
  It uses instead [`on`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#on) and `fire` functions from MapLibre Map class.
38
40
  `fire` function doesn't take directly [`Event`](https://developer.mozilla.org/fr/docs/Web/API/Event) objects, but a string and object data.
41
+ A shorthand `addEventListener` function is added for simpler usage.
39
42
 
40
43
 
41
44
  | Param | Type | Default | Description |
@@ -150,6 +153,27 @@ Forces reload of pictures/sequences layer styles.
150
153
  This is useful after a map theme change.
151
154
 
152
155
  **Kind**: instance method of [<code>Map</code>](#Panoramax.components.ui.Map)
156
+ <a name="Panoramax.components.ui.Map+addEventListener"></a>
157
+
158
+ ### map.addEventListener(type, listener)
159
+ Listen to map events.
160
+ This is a binder to [`on`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#on) and [`once`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#once) MapLibre GL functions.
161
+
162
+ **Kind**: instance method of [<code>Map</code>](#Panoramax.components.ui.Map)
163
+
164
+ | Param | Type | Default | Description |
165
+ | --- | --- | --- | --- |
166
+ | type | <code>string</code> | | The event type to listen for |
167
+ | listener | <code>function</code> | | The event handler |
168
+ | [options.once] | <code>boolean</code> | <code>false</code> | Set to true to only listen to first event. |
169
+
170
+ <a name="Panoramax.components.ui.Map+event_ready"></a>
171
+
172
+ ### "ready"
173
+ Event when map is ready to display.
174
+ This includes Maplibre initial load, enough map data display and styling.
175
+
176
+ **Kind**: event emitted by [<code>Map</code>](#Panoramax.components.ui.Map)
153
177
  <a name="Panoramax.components.ui.Map+event_background-changed"></a>
154
178
 
155
179
  ### "background-changed"
@@ -18,7 +18,9 @@
18
18
  * [.filterUserLayersContent(dataType, filter)](Map.md/#Panoramax.components.ui.Map+filterUserLayersContent)
19
19
  * [.displayPictureMarker(lon, lat, heading, [skipCenter])](#Panoramax.components.ui.Map+displayPictureMarker)
20
20
  * [.reloadLayersStyles()](Map.md/#Panoramax.components.ui.Map+reloadLayersStyles)
21
+ * [.addEventListener(type, listener)](Map.md/#Panoramax.components.ui.Map+addEventListener)
21
22
  * ["filters-changed"](#Panoramax.components.ui.MapMore+event_filters-changed)
23
+ * ["ready"](Map.md/#Panoramax.components.ui.Map+event_ready)
22
24
  * ["background-changed"](Map.md/#Panoramax.components.ui.Map+event_background-changed)
23
25
  * ["users-changed"](Map.md/#Panoramax.components.ui.Map+event_users-changed)
24
26
  * ["sequence-hover"](Map.md/#Panoramax.components.ui.Map+event_sequence-hover)
@@ -151,6 +153,20 @@ Forces reload of pictures/sequences layer styles.
151
153
  This is useful after a map theme change.
152
154
 
153
155
  **Kind**: instance method of [<code>MapMore</code>](#Panoramax.components.ui.MapMore)
156
+ <a name="Panoramax.components.ui.Map+addEventListener"></a>
157
+
158
+ ### mapMore.addEventListener(type, listener)
159
+ Listen to map events.
160
+ This is a binder to [`on`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#on) and [`once`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#once) MapLibre GL functions.
161
+
162
+ **Kind**: instance method of [<code>MapMore</code>](#Panoramax.components.ui.MapMore)
163
+
164
+ | Param | Type | Default | Description |
165
+ | --- | --- | --- | --- |
166
+ | type | <code>string</code> | | The event type to listen for |
167
+ | listener | <code>function</code> | | The event handler |
168
+ | [options.once] | <code>boolean</code> | <code>false</code> | Set to true to only listen to first event. |
169
+
154
170
  <a name="Panoramax.components.ui.MapMore+event_filters-changed"></a>
155
171
 
156
172
  ### "filters-changed"
@@ -168,6 +184,13 @@ Event for filters changes
168
184
  | [theme] | <code>string</code> | Map theme |
169
185
  | [qualityscore] | <code>Array.&lt;number&gt;</code> | QualityScore values, as a list of 1 to 5 grades |
170
186
 
187
+ <a name="Panoramax.components.ui.Map+event_ready"></a>
188
+
189
+ ### "ready"
190
+ Event when map is ready to display.
191
+ This includes Maplibre initial load, enough map data display and styling.
192
+
193
+ **Kind**: event emitted by [<code>MapMore</code>](#Panoramax.components.ui.MapMore)
171
194
  <a name="Panoramax.components.ui.Map+event_background-changed"></a>
172
195
 
173
196
  ### "background-changed"
@@ -3,7 +3,7 @@
3
3
  ## Panoramax.components.ui.Photo ⇐ <code>[photo-sphere-viewer.core.Viewer](https://photo-sphere-viewer.js.org/api/classes/Core.Viewer.html)</code>
4
4
  **Kind**: static class of <code>Panoramax.components.ui</code>
5
5
  **Extends**: <code>[photo-sphere-viewer.core.Viewer](https://photo-sphere-viewer.js.org/api/classes/Core.Viewer.html)</code>
6
- **Emits**: [<code>picture-loading</code>](#Panoramax.components.ui.Photo+event_picture-loading), [<code>picture-preview-started</code>](#Panoramax.components.ui.Photo+event_picture-preview-started), [<code>picture-preview-stopped</code>](#Panoramax.components.ui.Photo+event_picture-preview-stopped), [<code>view-rotated</code>](#Panoramax.components.ui.Photo+event_view-rotated), [<code>picture-loaded</code>](#Panoramax.components.ui.Photo+event_picture-loaded), [<code>picture-tiles-loaded</code>](#Panoramax.components.ui.Photo+event_picture-tiles-loaded), [<code>transition-duration-changed</code>](#Panoramax.components.ui.Photo+event_transition-duration-changed), [<code>sequence-playing</code>](#Panoramax.components.ui.Photo+event_sequence-playing), [<code>sequence-stopped</code>](#Panoramax.components.ui.Photo+event_sequence-stopped), [<code>pictures-navigation-changed</code>](#Panoramax.components.ui.Photo+event_pictures-navigation-changed)
6
+ **Emits**: [<code>picture-loading</code>](#Panoramax.components.ui.Photo+event_picture-loading), [<code>picture-preview-started</code>](#Panoramax.components.ui.Photo+event_picture-preview-started), [<code>picture-preview-stopped</code>](#Panoramax.components.ui.Photo+event_picture-preview-stopped), [<code>view-rotated</code>](#Panoramax.components.ui.Photo+event_view-rotated), [<code>picture-loaded</code>](#Panoramax.components.ui.Photo+event_picture-loaded), [<code>picture-tiles-loaded</code>](#Panoramax.components.ui.Photo+event_picture-tiles-loaded), [<code>transition-duration-changed</code>](#Panoramax.components.ui.Photo+event_transition-duration-changed), [<code>sequence-playing</code>](#Panoramax.components.ui.Photo+event_sequence-playing), [<code>sequence-stopped</code>](#Panoramax.components.ui.Photo+event_sequence-stopped), [<code>pictures-navigation-changed</code>](#Panoramax.components.ui.Photo+event_pictures-navigation-changed), [<code>ready</code>](#Panoramax.components.ui.Photo+event_ready)
7
7
 
8
8
  * [.Photo](#Panoramax.components.ui.Photo) ⇐ <code>[photo-sphere-viewer.core.Viewer](https://photo-sphere-viewer.js.org/api/classes/Core.Viewer.html)</code>
9
9
  * [new Photo(parent, container, [options])](#new_Panoramax.components.ui.Photo_new)
@@ -29,6 +29,7 @@
29
29
  * [.getPicturesNavigation()](#Panoramax.components.ui.Photo+getPicturesNavigation) ⇒ <code>string</code>
30
30
  * [.setPicturesNavigation(pn)](#Panoramax.components.ui.Photo+setPicturesNavigation)
31
31
  * [.forceRefresh()](#Panoramax.components.ui.Photo+forceRefresh)
32
+ * ["ready"](#Panoramax.components.ui.Photo+event_ready)
32
33
  * ["picture-loading"](#Panoramax.components.ui.Photo+event_picture-loading)
33
34
  * ["picture-preview-started"](#Panoramax.components.ui.Photo+event_picture-preview-started)
34
35
  * ["picture-preview-stopped"](#Panoramax.components.ui.Photo+event_picture-preview-stopped)
@@ -251,6 +252,13 @@ Switch the allowed navigation between pictures.
251
252
  Force reload of texture and tiles.
252
253
 
253
254
  **Kind**: instance method of [<code>Photo</code>](#Panoramax.components.ui.Photo)
255
+ <a name="Panoramax.components.ui.Photo+event_ready"></a>
256
+
257
+ ### "ready"
258
+ Triggered once when the panorama image has been loaded and the viewer is ready to perform the first render.
259
+
260
+ **Kind**: event emitted by [<code>Photo</code>](#Panoramax.components.ui.Photo)
261
+ **See**: [Photo Sphere Viewer documentation](https://photo-sphere-viewer.js.org/guide/events.html#ready)
254
262
  <a name="Panoramax.components.ui.Photo+event_picture-loading"></a>
255
263
 
256
264
  ### "picture-loading"
@@ -2,6 +2,7 @@
2
2
 
3
3
  ## Panoramax.utils.API
4
4
  **Kind**: static class of <code>Panoramax.utils</code>
5
+ **Emits**: [<code>ready</code>](#Panoramax.utils.API+event_ready), [<code>broken</code>](#Panoramax.utils.API+event_broken)
5
6
 
6
7
  * [.API](#Panoramax.utils.API)
7
8
  * [new API(endpoint, [options])](#new_Panoramax.utils.API_new)
@@ -24,6 +25,8 @@
24
25
  * [.searchUsers(query)](#Panoramax.utils.API+searchUsers) ⇒ <code>Promise</code>
25
26
  * [.getUserName(userId)](#Panoramax.utils.API+getUserName) ⇒ <code>Promise</code>
26
27
  * [.sendReport(data)](#Panoramax.utils.API+sendReport) ⇒ <code>Promise</code>
28
+ * ["broken"](#Panoramax.utils.API+event_broken)
29
+ * ["ready"](#Panoramax.utils.API+event_ready)
27
30
  * _static_
28
31
  * [.isValidHttpUrl(str)](#Panoramax.utils.API.isValidHttpUrl) ⇒ <code>boolean</code>
29
32
  * [.isIdValid(id)](#Panoramax.utils.API.isIdValid) ⇒ <code>boolean</code>
@@ -281,6 +284,26 @@ Send a report to API
281
284
  | --- | --- | --- |
282
285
  | data | <code>object</code> | The input form data |
283
286
 
287
+ <a name="Panoramax.utils.API+event_broken"></a>
288
+
289
+ ### "broken"
290
+ Event when API is broken.
291
+ This happens on any API loading or map styling issue.
292
+
293
+ **Kind**: event emitted by [<code>API</code>](#Panoramax.utils.API)
294
+ **Properties**
295
+
296
+ | Name | Type | Description |
297
+ | --- | --- | --- |
298
+ | detail.error | <code>Error</code> | The original error |
299
+
300
+ <a name="Panoramax.utils.API+event_ready"></a>
301
+
302
+ ### "ready"
303
+ Event when API is ready to use.
304
+ This happens after initial API read and map styles load.
305
+
306
+ **Kind**: event emitted by [<code>API</code>](#Panoramax.utils.API)
284
307
  <a name="Panoramax.utils.API.isValidHttpUrl"></a>
285
308
 
286
309
  ### API.isValidHttpUrl(str) ⇒ <code>boolean</code>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panoramax/web-viewer",
3
- "version": "3.2.3-develop-dfee2adc",
3
+ "version": "3.2.3-develop-357c83ca",
4
4
  "description": "Panoramax web viewer for geolocated pictures",
5
5
  "main": "build/index.js",
6
6
  "author": "Panoramax team",
@@ -100,7 +100,7 @@
100
100
  "@photo-sphere-viewer/virtual-tour-plugin": "5.12.1",
101
101
  "json5": "^2.2.3",
102
102
  "lit": "^3.2.1",
103
- "maplibre-gl": "^5.2.0",
103
+ "maplibre-gl": "^5.3.0",
104
104
  "pmtiles": "^4.3.0",
105
105
  "query-selector-shadow-dom": "^1.0.1"
106
106
  },
@@ -59,7 +59,7 @@ export default class Basic extends LitElement {
59
59
  this.users = ["geovisio"];
60
60
  this.mapstyle = this.getAttribute("mapstyle") || DEFAULT_TILES;
61
61
  this.lang = this.getAttribute("lang") || null;
62
- this.endpoint = null; // No default
62
+ this.endpoint = this.getAttribute("endpoint") || null; // No default
63
63
  this.picture = null;
64
64
  this.sequence = null;
65
65
 
@@ -83,6 +83,18 @@ export default class Basic extends LitElement {
83
83
 
84
84
  connectedCallback() {
85
85
  super.connectedCallback();
86
+
87
+ if(
88
+ !(this._loadsAPI && this.endpoint && this._loadsAPI === this.endpoint)
89
+ && !(this.api && this.api._endpoint === this.endpoint)
90
+ && this.endpoint
91
+ ) {
92
+ if(this._loadsAPI || this.api) {
93
+ delete this.api;
94
+ delete this._loadsAPI;
95
+ }
96
+ this._setupAPI();
97
+ }
86
98
  }
87
99
 
88
100
  /**
@@ -310,20 +322,8 @@ export default class Basic extends LitElement {
310
322
  if(prefix && this.getSubComponentsNames().includes(prefix)) {
311
323
  const subType = type.substring(prefix.length+1);
312
324
 
313
- // Special handling for map: not eventtarget
314
- if(prefix === "map") {
315
- if(this.map?.on) {
316
- if(options?.once) { this.map.once(subType, listener); }
317
- else { this.map.on(subType, listener); }
318
- }
319
- else {
320
- setTimeout(() => {
321
- this.addEventListener(type, listener, options);
322
- }, 50);
323
- }
324
- }
325
325
  // Add directly if available
326
- else if(this[prefix]?.addEventListener) {
326
+ if(this[prefix]?.addEventListener) {
327
327
  this[prefix].addEventListener(subType, listener, options);
328
328
  }
329
329
  // Wait for addEventListener to be available
@@ -340,7 +340,9 @@ export default class Basic extends LitElement {
340
340
  /** @private */
341
341
  static GetJSONConverter() {
342
342
  return {
343
- fromAttribute: (value) => JSON5.parse(value),
343
+ fromAttribute: (value) => {
344
+ return typeof value === "object" ? value : JSON5.parse(value);
345
+ },
344
346
  toAttribute: (value) => JSON.stringify(value)
345
347
  };
346
348
  }
@@ -253,11 +253,11 @@ export default class Viewer extends PhotoViewer {
253
253
  return new Promise(resolve => {
254
254
  waiter = setInterval(() => {
255
255
  if(typeof this.map === "object") {
256
- if(this.map.loaded?.()) {
256
+ if(this.map?.loaded?.()) {
257
257
  clearInterval(waiter);
258
258
  resolve();
259
259
  }
260
- else if(this.map.once) {
260
+ else if(this.map?.once) {
261
261
  this.map.once("render", () => {
262
262
  clearInterval(waiter);
263
263
  resolve();
@@ -110,7 +110,15 @@ export default class Loader extends LitElement {
110
110
  setTimeout(() => this.parentNode.removeChild(this), 2000);
111
111
 
112
112
  /**
113
- * Event for component being ready to use (API loaded)
113
+ * Event when component is ready to use.
114
+ * This happens when loader screen disappear, with picture and map loaded.
115
+ *
116
+ * To follow more precisely loading steps, you can also watch for sub-components `ready` events.
117
+ * ```js
118
+ * // Watch API-readiness
119
+ * viewer.addEventListener("api:ready", ...); // From parent
120
+ * viewer.api.addEventListener("ready", ...); // Or on sub-component
121
+ * ```
114
122
  * @event Panoramax.components.core.Basic#ready
115
123
  * @type {CustomEvent}
116
124
  */
@@ -138,7 +146,14 @@ export default class Loader extends LitElement {
138
146
  const errLabel = errMeaningful || "Panoramax JS had a blocking exception";
139
147
 
140
148
  /**
141
- * Event for viewer failing to initially load
149
+ * Event for viewer failing to initially load.
150
+ *
151
+ * To follow more precisely loading failures, you can also watch for sub-components `broken` events.
152
+ * ```js
153
+ * // Watch API breaks
154
+ * viewer.addEventListener("api:broken", ...); // From parent
155
+ * viewer.api.addEventListener("broken", ...); // Or on sub-component
156
+ * ```
142
157
  * @event Panoramax.components.core.Basic#broken
143
158
  * @type {CustomEvent}
144
159
  * @property {string} detail.error The user-friendly error message to display
@@ -28,6 +28,7 @@ maplibregl.addProtocol("pmtiles", new pmtiles.Protocol().tile);
28
28
  * ⚠️ This class doesn't inherit from [EventTarget](https://developer.mozilla.org/fr/docs/Web/API/EventTarget), so it doesn't have `addEventListener` and `dispatchEvent` functions.
29
29
  * It uses instead [`on`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#on) and `fire` functions from MapLibre Map class.
30
30
  * `fire` function doesn't take directly [`Event`](https://developer.mozilla.org/fr/docs/Web/API/Event) objects, but a string and object data.
31
+ * A shorthand `addEventListener` function is added for simpler usage.
31
32
  * @class Panoramax.components.ui.Map
32
33
  * @extends [maplibregl.Map](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/)
33
34
  * @param {Panoramax.components.core.Basic} parent The parent view
@@ -41,6 +42,7 @@ maplibregl.addProtocol("pmtiles", new pmtiles.Protocol().tile);
41
42
  * @fires Panoramax.components.ui.Map#sequence-hover
42
43
  * @fires Panoramax.components.ui.Map#sequence-click
43
44
  * @fires Panoramax.components.ui.Map#picture-click
45
+ * @fires Panoramax.components.ui.Map#ready
44
46
  * @example
45
47
  * const map = new Panoramax.components.ui.Map(viewer, mapNode, {center: {lat: 48.7, lng: -1.7}});
46
48
  */
@@ -103,7 +105,7 @@ export default class Map extends maplibregl.Map {
103
105
 
104
106
  // Timeout for initial loading
105
107
  setTimeout(() => {
106
- if(!this.loaded() && this._parent.loader.isVisible()) {
108
+ if(!this.loaded() && this._parent?.loader.isVisible()) {
107
109
  this._parent.loader.dismiss({}, this._parent._t.map.slow_loading, () => {});
108
110
  }
109
111
  }, 15000);
@@ -118,6 +120,14 @@ export default class Map extends maplibregl.Map {
118
120
  this.resize();
119
121
  await this.setVisibleUsers(this._parent.users);
120
122
  this.reloadLayersStyles();
123
+
124
+ /**
125
+ * Event when map is ready to display.
126
+ * This includes Maplibre initial load, enough map data display and styling.
127
+ * @event Panoramax.components.ui.Map#ready
128
+ * @type {maplibregl.util.evented.Event}
129
+ */
130
+ this.fire("ready");
121
131
  }
122
132
 
123
133
  /**
@@ -917,4 +927,17 @@ export default class Map extends maplibregl.Map {
917
927
  });
918
928
  }
919
929
  }
930
+
931
+ /**
932
+ * Listen to map events.
933
+ * This is a binder to [`on`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#on) and [`once`](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#once) MapLibre GL functions.
934
+ * @param {string} type The event type to listen for
935
+ * @param {function} listener The event handler
936
+ * @param {boolean} [options.once=false] Set to true to only listen to first event.
937
+ * @memberof Panoramax.components.ui.Map#
938
+ */
939
+ addEventListener(type, listener, options = {}) {
940
+ if(options?.once) { this.once(type, listener); }
941
+ else { this.on(type, listener); }
942
+ }
920
943
  }
@@ -43,6 +43,14 @@ export const PIC_MAX_STAY_DURATION = 3000;
43
43
 
44
44
  PSViewer.useNewAnglesOrder = true;
45
45
 
46
+ /**
47
+ * Triggered once when the panorama image has been loaded and the viewer is ready to perform the first render.
48
+ * @see [Photo Sphere Viewer documentation](https://photo-sphere-viewer.js.org/guide/events.html#ready)
49
+ * @event Panoramax.components.ui.Photo#ready
50
+ * @memberof Panoramax.components.ui.Photo
51
+ * @type {Event}
52
+ */
53
+
46
54
  /**
47
55
  * Photo is the component showing a single picture.
48
56
  * It uses Photo Sphere Viewer as a basis, and pre-configure dialog with STAC API.
@@ -68,6 +76,7 @@ PSViewer.useNewAnglesOrder = true;
68
76
  * @fires Panoramax.components.ui.Photo#sequence-playing
69
77
  * @fires Panoramax.components.ui.Photo#sequence-stopped
70
78
  * @fires Panoramax.components.ui.Photo#pictures-navigation-changed
79
+ * @fires Panoramax.components.ui.Photo#ready
71
80
  * @example
72
81
  * const psv = new Panoramax.components.ui.Photo(viewer, psvNode, {transitionDuration: 500})
73
82
  */
package/src/utils/API.js CHANGED
@@ -6,6 +6,8 @@ import { isNullId } from "./utils";
6
6
  *
7
7
  * @class Panoramax.utils.API
8
8
  * @typicalname api
9
+ * @fires Panoramax.utils.API#ready
10
+ * @fires Panoramax.utils.API#broken
9
11
  * @param {string} endpoint The endpoint. It corresponds to the <a href="https://github.com/radiantearth/stac-api-spec/blob/main/overview.md#example-landing-page">STAC landing page</a>, with all links describing the API capabilites.
10
12
  * @param {object} [options] Options
11
13
  * @param {string|object} [options.style] General map style
@@ -14,10 +16,14 @@ import { isNullId } from "./utils";
14
16
  * @param {object} [options.fetch] Set custom options for fetch calls made against API ([same syntax as fetch options parameter](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters))
15
17
  * @param {string[]} [options.users] List of initial user IDs to load map styles for
16
18
  */
17
- export default class API {
19
+ export default class API extends EventTarget {
18
20
  constructor(endpoint, options = {}) {
21
+ super();
22
+
19
23
  if(endpoint === null || endpoint === undefined || typeof endpoint !== "string") {
20
- throw new Error("endpoint parameter is empty or not a valid string");
24
+ const e = new Error("endpoint parameter is empty or not a valid string");
25
+ this.dispatchEvent(new CustomEvent("broken", {detail: {error: e}}));
26
+ throw e;
21
27
  }
22
28
 
23
29
  // Parse local endpoints
@@ -27,7 +33,9 @@ export default class API {
27
33
 
28
34
  // Check endpoint
29
35
  if(!API.isValidHttpUrl(endpoint)) {
30
- throw new Error(`endpoint parameter is not a valid URL: ${endpoint}`);
36
+ const e = new Error(`endpoint parameter is not a valid URL: ${endpoint}`);
37
+ this.dispatchEvent(new CustomEvent("broken", {detail: {error: e}}));
38
+ throw e;
31
39
  }
32
40
 
33
41
  this._endpoint = endpoint;
@@ -43,11 +51,30 @@ export default class API {
43
51
  .catch(e => {
44
52
  this._isReady = -1;
45
53
  console.error(e);
54
+
55
+ /**
56
+ * Event when API is broken.
57
+ * This happens on any API loading or map styling issue.
58
+ * @event Panoramax.utils.API#broken
59
+ * @type {CustomEvent}
60
+ * @property {Error} detail.error The original error
61
+ */
62
+ this.dispatchEvent(new CustomEvent("broken", {detail: {error: e}}));
63
+
46
64
  return Promise.reject("Viewer failed to communicate with API");
47
65
  })
48
66
  .then(() => this._loadMapStyles(options.style, options.users))
49
67
  .then(() => {
50
68
  this._isReady = 1;
69
+
70
+ /**
71
+ * Event when API is ready to use.
72
+ * This happens after initial API read and map styles load.
73
+ * @event Panoramax.utils.API#ready
74
+ * @type {Event}
75
+ */
76
+ this.dispatchEvent(new Event("ready"));
77
+
51
78
  return "API is ready";
52
79
  });
53
80
  }