@panoramax/web-viewer 3.2.3-develop-e277ccb9 → 3.2.3-develop-dbce84df
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 +1 -0
- package/build/index.css +1 -1
- package/build/index.css.map +1 -1
- package/build/index.html +1 -1
- package/build/index.js +29 -25
- package/build/index.js.map +1 -1
- package/build/photo.html +1 -0
- package/config/paths.js +1 -0
- package/config/webpack.config.js +26 -0
- package/docs/03_URL_settings.md +4 -1
- package/docs/09_Develop.md +1 -1
- package/docs/images/class_diagram.drawio +37 -22
- package/docs/images/class_diagram.jpg +0 -0
- package/docs/index.md +15 -1
- package/docs/reference/components/core/PhotoViewer.md +256 -0
- package/docs/reference/components/core/Viewer.md +47 -49
- package/docs/reference/components/menus/MapLegend.md +1 -1
- package/docs/reference/components/ui/Photo.md +8 -0
- package/docs/reference/components/ui/widgets/Legend.md +7 -1
- package/docs/reference.md +3 -2
- package/docs/tutorials/custom_widgets.md +6 -11
- package/docs/tutorials/migrate_v4.md +2 -0
- package/mkdocs.yml +1 -0
- package/package.json +1 -1
- package/public/index.html +14 -9
- package/public/photo.html +55 -0
- package/src/components/core/PhotoViewer.css +65 -0
- package/src/components/core/PhotoViewer.js +441 -0
- package/src/components/core/Viewer.js +71 -306
- package/src/components/core/index.js +1 -0
- package/src/components/menus/MapLegend.js +1 -21
- package/src/components/ui/Photo.js +13 -3
- package/src/components/ui/widgets/Legend.js +32 -1
- package/src/index.js +1 -0
- package/src/translations/nl.json +105 -5
- package/src/utils/API.js +2 -2
- package/src/utils/InitParameters.js +29 -16
- package/src/utils/URLHandler.js +11 -5
- package/src/utils/map.js +2 -2
- package/tests/components/ui/Photo.test.js +6 -6
- package/tests/utils/InitParameters.test.js +1 -0
- package/tests/utils/URLHandler.test.js +16 -6
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/* eslint-disable no-unused-vars */
|
|
2
2
|
|
|
3
3
|
import "./Viewer.css";
|
|
4
|
-
import { SYSTEM as PSSystem, DEFAULTS as PSDefaults } from "@photo-sphere-viewer/core";
|
|
5
|
-
import URLHandler from "../../utils/URLHandler";
|
|
6
4
|
import { linkMapAndPhoto, saveMapParamsToLocalStorage, getMapParamsFromLocalStorage } from "../../utils/map";
|
|
5
|
+
import PhotoViewer from "./PhotoViewer";
|
|
7
6
|
import Basic from "./Basic";
|
|
8
|
-
import Photo, { PSV_DEFAULT_ZOOM, PSV_ANIM_DURATION } from "../ui/Photo";
|
|
9
7
|
import MapMore from "../ui/MapMore";
|
|
10
8
|
import { initMapKeyboardHandler } from "../../utils/map";
|
|
11
9
|
import { isNullId } from "../../utils/utils";
|
|
@@ -14,7 +12,7 @@ import { fa } from "../../utils/widgets";
|
|
|
14
12
|
import { faPanorama } from "@fortawesome/free-solid-svg-icons/faPanorama";
|
|
15
13
|
import { faMap } from "@fortawesome/free-solid-svg-icons/faMap";
|
|
16
14
|
import { querySelectorDeep } from "query-selector-shadow-dom";
|
|
17
|
-
import { default as InitParameters,
|
|
15
|
+
import { default as InitParameters, alterMapState, alterViewerState } from "../../utils/InitParameters";
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
export const PSV_ZOOM_DELTA = 20;
|
|
@@ -26,15 +24,17 @@ const MAP_MOVE_DELTA = 100;
|
|
|
26
24
|
* Viewer is the main component of Panoramax JS library, showing pictures and map.
|
|
27
25
|
*
|
|
28
26
|
* This component has a [CorneredGrid](#Panoramax.components.layout.CorneredGrid) layout, you can use directly any slot element to pass custom widgets.
|
|
27
|
+
*
|
|
28
|
+
* If you need a viewer without map, checkout [Photo Viewer component](#Panoramax.components.core.PhotoViewer).
|
|
29
29
|
* @class Panoramax.components.core.Viewer
|
|
30
30
|
* @element pnx-viewer
|
|
31
|
-
* @extends Panoramax.components.core.
|
|
31
|
+
* @extends Panoramax.components.core.PhotoViewer
|
|
32
32
|
* @property {Panoramax.components.ui.Loader} loader The loader screen
|
|
33
33
|
* @property {Panoramax.utils.API} api The API manager
|
|
34
|
-
* @property {Panoramax.components.ui.MapMore}
|
|
34
|
+
* @property {Panoramax.components.ui.MapMore} map The MapLibre GL map itself
|
|
35
35
|
* @property {Panoramax.components.ui.Photo} psv The Photo Sphere Viewer component itself
|
|
36
36
|
* @property {Panoramax.components.layout.CorneredGrid} grid The grid layout manager
|
|
37
|
-
* @property {Panoramax.components.layout.Mini}
|
|
37
|
+
* @property {Panoramax.components.layout.Mini} mini The reduced/collapsed map/photo component
|
|
38
38
|
* @property {Panoramax.components.ui.Popup} popup The popup container
|
|
39
39
|
* @property {Panoramax.utils.URLHandler} urlHandler The URL query parameters manager
|
|
40
40
|
* @fires Panoramax.components.core.Basic#select
|
|
@@ -65,7 +65,6 @@ const MAP_MOVE_DELTA = 100;
|
|
|
65
65
|
* <pnx-viewer
|
|
66
66
|
* endpoint="https://panoramax.openstreetmap.fr/"
|
|
67
67
|
* widgets="false"
|
|
68
|
-
* map="false"
|
|
69
68
|
* >
|
|
70
69
|
* <p slot="top-right">My custom text</p>
|
|
71
70
|
* </pnx-viewer>
|
|
@@ -77,14 +76,14 @@ const MAP_MOVE_DELTA = 100;
|
|
|
77
76
|
* />
|
|
78
77
|
* ```
|
|
79
78
|
*/
|
|
80
|
-
export default class Viewer extends
|
|
79
|
+
export default class Viewer extends PhotoViewer {
|
|
81
80
|
/**
|
|
82
81
|
* Component properties. All of [Basic properties](#Panoramax.components.core.Basic+properties) are available as well.
|
|
83
82
|
* @memberof Panoramax.components.core.Viewer#
|
|
84
|
-
* @mixes Panoramax.components.core.
|
|
83
|
+
* @mixes Panoramax.components.core.PhotoViewer#properties
|
|
85
84
|
* @type {Object}
|
|
86
85
|
* @property {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md))
|
|
87
|
-
* @property {
|
|
86
|
+
* @property {object} [map] An object with [any map option available in Map or MapMore class](#Panoramax.components.ui.MapMore).<br />Example: `map="{'background': 'aerial', 'theme': 'age'}"`
|
|
88
87
|
* @property {object} [psv] [Any option to pass to Photo component](#Panoramax.components.ui.Photo) as an object.<br />Example: `psv="{'transitionDuration': 500, 'picturesNavigation': 'pic'}"`
|
|
89
88
|
* @property {string} [url-parameters=true] Should the component add and update URL query parameters to save viewer state ?
|
|
90
89
|
* @property {string} [focus=pic] The component showing up as main component (pic, map)
|
|
@@ -99,12 +98,9 @@ export default class Viewer extends Basic {
|
|
|
99
98
|
*/
|
|
100
99
|
static properties = {
|
|
101
100
|
map: {type: Object},
|
|
102
|
-
psv: {type: Object},
|
|
103
|
-
"url-parameters": {type: String},
|
|
104
101
|
focus: {type: String, reflect: true},
|
|
105
102
|
geocoder: {type: String},
|
|
106
|
-
|
|
107
|
-
...Basic.properties
|
|
103
|
+
...PhotoViewer.properties
|
|
108
104
|
};
|
|
109
105
|
|
|
110
106
|
constructor() {
|
|
@@ -112,16 +108,9 @@ export default class Viewer extends Basic {
|
|
|
112
108
|
|
|
113
109
|
// Defaults
|
|
114
110
|
this.map = true;
|
|
115
|
-
this.psv = {};
|
|
116
|
-
this["url-parameters"] = this.getAttribute("url-parameters") || true;
|
|
117
111
|
this.geocoder = this.getAttribute("geocoder") || "nominatim";
|
|
118
|
-
this.widgets = this.getAttribute("widgets") || "true";
|
|
119
|
-
|
|
120
|
-
// Set variables
|
|
121
|
-
this._prevSequence = null;
|
|
122
112
|
|
|
123
113
|
// Init DOM containers
|
|
124
|
-
this.grid = createWebComp("pnx-cornered-grid");
|
|
125
114
|
this.mini = createWebComp("pnx-mini", {
|
|
126
115
|
slot: "bottom-left",
|
|
127
116
|
_parent: this,
|
|
@@ -130,80 +119,71 @@ export default class Viewer extends Basic {
|
|
|
130
119
|
});
|
|
131
120
|
this.mini.addEventListener("expand", this._toggleFocus.bind(this));
|
|
132
121
|
this.grid.appendChild(this.mini);
|
|
133
|
-
this.psvContainer = document.createElement("div");
|
|
134
122
|
this.mapContainer = document.createElement("div");
|
|
135
|
-
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** @private */
|
|
126
|
+
_createInitParamsHandler() {
|
|
127
|
+
this._initParams = new InitParameters(
|
|
128
|
+
InitParameters.GetComponentProperties(Viewer, this),
|
|
129
|
+
Object.assign({}, this.urlHandler?.currentURLParams(), this.urlHandler?.currentURLParams(true)),
|
|
130
|
+
{ map: getMapParamsFromLocalStorage() },
|
|
131
|
+
);
|
|
132
|
+
}
|
|
136
133
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.
|
|
134
|
+
/** @private */
|
|
135
|
+
_initWidgets() {
|
|
136
|
+
if(this._initParams.getParentInit().widgets !== "false") {
|
|
137
|
+
this.grid.appendChild(createWebComp("pnx-widget-zoom", {
|
|
138
|
+
slot: this.isWidthSmall() ? "top-left" : "bottom-right",
|
|
139
|
+
class: this.isWidthSmall() ? "pnx-only-map pnx-print-hidden" : "pnx-print-hidden",
|
|
140
|
+
_parent: this
|
|
141
|
+
}));
|
|
142
|
+
this.grid.appendChild(createWebComp("pnx-widget-share", {slot: "bottom-right", class: "pnx-print-hidden", _parent: this}));
|
|
143
|
+
|
|
144
|
+
this.legend = createWebComp("pnx-widget-legend", {
|
|
145
|
+
slot: this.isWidthSmall() ? "top" : "top-left",
|
|
146
|
+
_parent: this,
|
|
147
|
+
focus: this._initParams.getParentPostInit().focus,
|
|
148
|
+
picture: this._initParams.getParentPostInit().picture,
|
|
142
149
|
});
|
|
150
|
+
this.grid.appendChild(this.legend);
|
|
151
|
+
this.grid.appendChild(createWebComp("pnx-widget-player", {slot: "top", _parent: this, class: "pnx-only-psv pnx-print-hidden"}));
|
|
152
|
+
|
|
153
|
+
this.grid.appendChild(createWebComp("pnx-widget-geosearch", {
|
|
154
|
+
slot: this.isWidthSmall() ? "top-right" : "top-left",
|
|
155
|
+
_parent: this,
|
|
156
|
+
class: "pnx-only-map pnx-print-hidden",
|
|
157
|
+
geocoder: this._initParams.getParentPostInit().geocoder,
|
|
158
|
+
}));
|
|
159
|
+
this.grid.appendChild(createWebComp("pnx-widget-mapfilters", {
|
|
160
|
+
slot: this.isWidthSmall() ? "top-right" : "top-left",
|
|
161
|
+
_parent: this,
|
|
162
|
+
"user-search": this.api._endpoints.user_search !== null && this.api._endpoints.user_tiles !== null,
|
|
163
|
+
"quality-score": this.map?._hasQualityScore?.() || false,
|
|
164
|
+
class: "pnx-only-map pnx-print-hidden",
|
|
165
|
+
}));
|
|
166
|
+
this.grid.appendChild(createWebComp("pnx-widget-maplayers", { slot: "top-right", _parent: this, class: "pnx-only-map pnx-print-hidden" }));
|
|
143
167
|
}
|
|
144
168
|
}
|
|
145
169
|
|
|
146
170
|
/** @private */
|
|
147
171
|
connectedCallback() {
|
|
148
|
-
|
|
172
|
+
Basic.prototype.connectedCallback.call(this);
|
|
149
173
|
this._moveChildToGrid();
|
|
150
174
|
|
|
151
175
|
this.onceAPIReady().then(async () => {
|
|
152
176
|
this.loader.setAttribute("value", 30);
|
|
153
|
-
this.
|
|
154
|
-
InitParameters.GetComponentProperties(Viewer, this),
|
|
155
|
-
Object.assign({}, this.urlHandler?.currentURLParams(), this.urlHandler?.currentURLParams(true)),
|
|
156
|
-
{ map: getMapParamsFromLocalStorage() },
|
|
157
|
-
);
|
|
177
|
+
this._createInitParamsHandler();
|
|
158
178
|
|
|
159
|
-
const myInitParams = this._initParams.getParentInit();
|
|
160
179
|
const myPostInitParams = this._initParams.getParentPostInit();
|
|
161
180
|
|
|
162
181
|
this._initPSV();
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this.grid.removeChild(this.mini);
|
|
166
|
-
this.psvContainer.setAttribute("slot", "bg");
|
|
167
|
-
this.grid.appendChild(this.psvContainer);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Init various widgets
|
|
171
|
-
if(myInitParams.widgets !== "false") {
|
|
172
|
-
this.grid.appendChild(createWebComp("pnx-widget-zoom", {
|
|
173
|
-
slot: this.isWidthSmall() ? "top-left" : "bottom-right",
|
|
174
|
-
class: this.isWidthSmall() ? "pnx-only-map pnx-print-hidden" : "pnx-print-hidden",
|
|
175
|
-
_parent: this
|
|
176
|
-
}));
|
|
177
|
-
this.grid.appendChild(createWebComp("pnx-widget-share", {slot: "bottom-right", class: "pnx-print-hidden", _parent: this}));
|
|
178
|
-
|
|
179
|
-
if(this.map) {
|
|
180
|
-
this.grid.appendChild(createWebComp("pnx-widget-geosearch", {
|
|
181
|
-
slot: this.isWidthSmall() ? "top-right" : "top-left",
|
|
182
|
-
_parent: this,
|
|
183
|
-
class: "pnx-only-map pnx-print-hidden",
|
|
184
|
-
geocoder: myPostInitParams.geocoder,
|
|
185
|
-
}));
|
|
186
|
-
this.grid.appendChild(createWebComp("pnx-widget-mapfilters", {
|
|
187
|
-
slot: this.isWidthSmall() ? "top-right" : "top-left",
|
|
188
|
-
_parent: this,
|
|
189
|
-
"user-search": this.api._endpoints.user_search !== null && this.api._endpoints.user_tiles !== null,
|
|
190
|
-
"quality-score": this.map?._hasQualityScore?.() || false,
|
|
191
|
-
class: "pnx-only-map pnx-print-hidden",
|
|
192
|
-
}));
|
|
193
|
-
this.grid.appendChild(createWebComp("pnx-widget-maplayers", { slot: "top-right", _parent: this, class: "pnx-only-map pnx-print-hidden" }));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
this.legend = createWebComp("pnx-widget-legend", {
|
|
197
|
-
slot: this.isWidthSmall() ? "top" : "top-left",
|
|
198
|
-
_parent: this,
|
|
199
|
-
focus: myPostInitParams.focus
|
|
200
|
-
});
|
|
201
|
-
this.grid.appendChild(this.legend);
|
|
202
|
-
this.grid.appendChild(createWebComp("pnx-widget-player", {slot: "top", _parent: this, class: "pnx-only-psv pnx-print-hidden"}));
|
|
203
|
-
}
|
|
204
|
-
|
|
182
|
+
await this._initMap();
|
|
183
|
+
this._initWidgets();
|
|
205
184
|
alterViewerState(this, myPostInitParams);
|
|
206
185
|
this._handleKeyboardManagement();
|
|
186
|
+
|
|
207
187
|
if(myPostInitParams.picture) {
|
|
208
188
|
this.psv.addEventListener("picture-loaded", () => this.loader.dismiss(), {once: true});
|
|
209
189
|
}
|
|
@@ -234,48 +214,23 @@ export default class Viewer extends Basic {
|
|
|
234
214
|
attributeChangedCallback(name, old, value) {
|
|
235
215
|
super.attributeChangedCallback(name, old, value);
|
|
236
216
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
217
|
+
if(name === "picture") {
|
|
218
|
+
this.legend?.setAttribute?.("picture", value);
|
|
219
|
+
|
|
220
|
+
// First pic load : show map in mini component
|
|
221
|
+
if(isNullId(old) && !isNullId(value)) {
|
|
222
|
+
this.mini.removeAttribute("collapsed");
|
|
223
|
+
}
|
|
224
|
+
if(isNullId(value) && this.map && this.isMapWide()) {
|
|
225
|
+
this.mini.classList.add("pnx-hidden");
|
|
226
|
+
}
|
|
243
227
|
}
|
|
228
|
+
|
|
244
229
|
if(name === "focus") {
|
|
245
230
|
this._setFocus(value);
|
|
246
231
|
}
|
|
247
232
|
}
|
|
248
233
|
|
|
249
|
-
/** @private */
|
|
250
|
-
render() {
|
|
251
|
-
return [this.loader, this.grid, this.popup, this.slot];
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Waiting for Photo Sphere Viewer to be available.
|
|
256
|
-
* @returns {Promise} When PSV is ready to use
|
|
257
|
-
* @memberof Panoramax.components.core.Viewer#
|
|
258
|
-
*/
|
|
259
|
-
oncePSVReady() {
|
|
260
|
-
let waiter;
|
|
261
|
-
return new Promise(resolve => {
|
|
262
|
-
waiter = setInterval(() => {
|
|
263
|
-
if(typeof this.psv === "object") {
|
|
264
|
-
if(this.psv.container) {
|
|
265
|
-
clearInterval(waiter);
|
|
266
|
-
resolve();
|
|
267
|
-
}
|
|
268
|
-
else if(this.psv.addEventListener) {
|
|
269
|
-
this.psv.addEventListener("ready", () => {
|
|
270
|
-
clearInterval(waiter);
|
|
271
|
-
resolve();
|
|
272
|
-
}, {once: true});
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}, 250);
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
|
|
279
234
|
/**
|
|
280
235
|
* Waiting for map to be available.
|
|
281
236
|
* @returns {Promise} When map is ready to use
|
|
@@ -303,67 +258,6 @@ export default class Viewer extends Basic {
|
|
|
303
258
|
});
|
|
304
259
|
}
|
|
305
260
|
|
|
306
|
-
/**
|
|
307
|
-
* Waits for first picture to display on PSV.
|
|
308
|
-
* @returns {Promise}
|
|
309
|
-
* @fulfil {undefined} When picture is shown
|
|
310
|
-
* @memberof Panoramax.components.core.Viewer#
|
|
311
|
-
*/
|
|
312
|
-
onceFirstPicLoaded() {
|
|
313
|
-
return this.oncePSVReady().then(() => {
|
|
314
|
-
if(this.psv.getPictureMetadata()) { return Promise.resolve(); }
|
|
315
|
-
else {
|
|
316
|
-
return new Promise(resolve => {
|
|
317
|
-
this.psv.addEventListener("picture-loaded", resolve, {once: true});
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/** @private */
|
|
324
|
-
_initPSV() {
|
|
325
|
-
try {
|
|
326
|
-
this.psv = new Photo(this, this.psvContainer, {
|
|
327
|
-
shouldGoFast: this._psvShouldGoFast.bind(this),
|
|
328
|
-
keyboard: "always",
|
|
329
|
-
keyboardActions: {
|
|
330
|
-
...PSDefaults.keyboardActions,
|
|
331
|
-
"8": "ROTATE_UP",
|
|
332
|
-
"2": "ROTATE_DOWN",
|
|
333
|
-
"4": "ROTATE_LEFT",
|
|
334
|
-
"6": "ROTATE_RIGHT",
|
|
335
|
-
|
|
336
|
-
"PageUp": () => this.psv.goToNextPicture(),
|
|
337
|
-
"9": () => this.psv.goToNextPicture(),
|
|
338
|
-
|
|
339
|
-
"PageDown": () => this.psv.goToPrevPicture(),
|
|
340
|
-
"3": () => this.psv.goToPrevPicture(),
|
|
341
|
-
|
|
342
|
-
"5": () => this.moveCenter(),
|
|
343
|
-
"*": () => this.moveCenter(),
|
|
344
|
-
|
|
345
|
-
"Home": () => this._toggleFocus(),
|
|
346
|
-
"7": () => this._toggleFocus(),
|
|
347
|
-
|
|
348
|
-
"End": () => this.mini.toggleAttribute("collapsed"),
|
|
349
|
-
"1": () => this.mini.toggleAttribute("collapsed"),
|
|
350
|
-
|
|
351
|
-
" ": () => this.psv.toggleSequencePlaying(),
|
|
352
|
-
"0": () => this.psv.toggleSequencePlaying(),
|
|
353
|
-
},
|
|
354
|
-
...this._initParams.getPSVInit()
|
|
355
|
-
});
|
|
356
|
-
this.oncePSVReady().then(() => {
|
|
357
|
-
this.loader.setAttribute("value", 50);
|
|
358
|
-
alterPSVState(this.psv, this._initParams.getPSVPostInit());
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
catch(e) {
|
|
362
|
-
let err = !PSSystem.isWebGLSupported ? this._t.pnx.error_webgl : this._t.pnx.error_psv;
|
|
363
|
-
this.loader.dismiss(e, err);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
261
|
/**
|
|
368
262
|
* Inits MapLibre GL component
|
|
369
263
|
*
|
|
@@ -424,69 +318,6 @@ export default class Viewer extends Basic {
|
|
|
424
318
|
}
|
|
425
319
|
}
|
|
426
320
|
|
|
427
|
-
/**
|
|
428
|
-
* Given context, should tiles be loaded in PSV.
|
|
429
|
-
* @private
|
|
430
|
-
*/
|
|
431
|
-
_psvShouldGoFast() {
|
|
432
|
-
return (this.psv._sequencePlaying && this.psv.getTransitionDuration() < 1000)
|
|
433
|
-
|| (this.map && this.isMapWide());
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/** @private */
|
|
437
|
-
_moveChildToGrid() {
|
|
438
|
-
for(let i=0; i < this.childNodes.length; i++) {
|
|
439
|
-
let n = this.childNodes[i];
|
|
440
|
-
if(n.getAttribute?.("slot")) {
|
|
441
|
-
// Add parent + translation for our components
|
|
442
|
-
if(n.tagName?.toLowerCase().startsWith("pnx-")) {
|
|
443
|
-
n._parent = this;
|
|
444
|
-
n._t = this._t;
|
|
445
|
-
}
|
|
446
|
-
this.grid.appendChild(n);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Change full-page popup visibility and content
|
|
453
|
-
* @memberof Panoramax.components.core.Viewer#
|
|
454
|
-
* @param {boolean} visible True to make it appear
|
|
455
|
-
* @param {string|Element[]} [content] The new popup content
|
|
456
|
-
*/
|
|
457
|
-
setPopup(visible, content = null) {
|
|
458
|
-
if(visible) { this.popup.setAttribute("visible", ""); }
|
|
459
|
-
else { this.popup.removeAttribute("visible"); }
|
|
460
|
-
|
|
461
|
-
this.popup.innerHTML = "";
|
|
462
|
-
if(typeof content === "string") { this.popup.innerHTML = content; }
|
|
463
|
-
else if(Array.isArray(content)) { content.forEach(c => this.popup.appendChild(c)); }
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/** @private */
|
|
467
|
-
_onPopupClose() {
|
|
468
|
-
this.dispatchEvent(new CustomEvent("focus-changed", { detail: { focus: this.map && this.isMapWide() ? "map" : "pic" } }));
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/** @private */
|
|
472
|
-
_showQualityScoreDoc() {
|
|
473
|
-
this.setPopup(true, [createWebComp("pnx-quality-score-doc", {_t: this._t})]);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
/** @private */
|
|
477
|
-
_showReportForm() {
|
|
478
|
-
if(!this.psv.getPictureMetadata()) { throw new Error("No picture currently selected"); }
|
|
479
|
-
this.setPopup(true, [createWebComp("pnx-report-form", {_parent: this})]);
|
|
480
|
-
this.dispatchEvent(new CustomEvent("focus-changed", { detail: { focus: "meta" } }));
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/** @private */
|
|
484
|
-
_showPictureMetadata() {
|
|
485
|
-
if(!this.psv.getPictureMetadata()) { throw new Error("No picture currently selected"); }
|
|
486
|
-
this.setPopup(true, [createWebComp("pnx-picture-metadata", {_parent: this})]);
|
|
487
|
-
this.dispatchEvent(new CustomEvent("focus-changed", { detail: { focus: "meta" } }));
|
|
488
|
-
}
|
|
489
|
-
|
|
490
321
|
/**
|
|
491
322
|
* Move the view of main component to its center.
|
|
492
323
|
* For map, center view on selected picture.
|
|
@@ -501,47 +332,10 @@ export default class Viewer extends Basic {
|
|
|
501
332
|
this.map.flyTo({ center: meta.gps, zoom: 20 });
|
|
502
333
|
}
|
|
503
334
|
else {
|
|
504
|
-
|
|
505
|
-
speed: PSV_ANIM_DURATION,
|
|
506
|
-
yaw: 0,
|
|
507
|
-
pitch: 0,
|
|
508
|
-
zoom: PSV_DEFAULT_ZOOM
|
|
509
|
-
});
|
|
335
|
+
super.moveCenter();
|
|
510
336
|
}
|
|
511
337
|
}
|
|
512
338
|
|
|
513
|
-
/**
|
|
514
|
-
* Moves the view of main component slightly to the left.
|
|
515
|
-
* @memberof Panoramax.components.core.Viewer#
|
|
516
|
-
*/
|
|
517
|
-
moveLeft() {
|
|
518
|
-
this._moveToDirection("left");
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* Moves the view of main component slightly to the right.
|
|
523
|
-
* @memberof Panoramax.components.core.Viewer#
|
|
524
|
-
*/
|
|
525
|
-
moveRight() {
|
|
526
|
-
this._moveToDirection("right");
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/**
|
|
530
|
-
* Moves the view of main component slightly to the top.
|
|
531
|
-
* @memberof Panoramax.components.core.Viewer#
|
|
532
|
-
*/
|
|
533
|
-
moveUp() {
|
|
534
|
-
this._moveToDirection("up");
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Moves the view of main component slightly to the bottom.
|
|
539
|
-
* @memberof Panoramax.components.core.Viewer#
|
|
540
|
-
*/
|
|
541
|
-
moveDown() {
|
|
542
|
-
this._moveToDirection("down");
|
|
543
|
-
}
|
|
544
|
-
|
|
545
339
|
/**
|
|
546
340
|
* Moves map or picture viewer to given direction.
|
|
547
341
|
* @param {string} dir Direction to move to (up, left, down, right)
|
|
@@ -567,43 +361,16 @@ export default class Viewer extends Basic {
|
|
|
567
361
|
this.map.panBy(pan);
|
|
568
362
|
}
|
|
569
363
|
else {
|
|
570
|
-
|
|
571
|
-
switch(dir) {
|
|
572
|
-
case "up":
|
|
573
|
-
pos.pitch += PSV_MOVE_DELTA;
|
|
574
|
-
break;
|
|
575
|
-
case "left":
|
|
576
|
-
pos.yaw -= PSV_MOVE_DELTA;
|
|
577
|
-
break;
|
|
578
|
-
case "down":
|
|
579
|
-
pos.pitch -= PSV_MOVE_DELTA;
|
|
580
|
-
break;
|
|
581
|
-
case "right":
|
|
582
|
-
pos.yaw += PSV_MOVE_DELTA;
|
|
583
|
-
break;
|
|
584
|
-
}
|
|
585
|
-
this._psvAnimate({ speed: PSV_ANIM_DURATION, ...pos });
|
|
364
|
+
super._moveToDirection(dir);
|
|
586
365
|
}
|
|
587
366
|
}
|
|
588
367
|
|
|
589
|
-
/**
|
|
590
|
-
* Overrided PSV animate function to ensure a single animation plays at once.
|
|
591
|
-
* @param {object} options PSV animate options
|
|
592
|
-
* @private
|
|
593
|
-
*/
|
|
594
|
-
_psvAnimate(options) {
|
|
595
|
-
if(this._lastPsvAnim) { this._lastPsvAnim.cancel(); }
|
|
596
|
-
this._lastPsvAnim = this.psv.animate(options);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
368
|
/**
|
|
600
369
|
* Is the map shown as main element instead of viewer (wide map mode) ?
|
|
601
370
|
* @memberof Panoramax.components.core.Viewer#
|
|
602
371
|
* @returns {boolean} True if map is wider than viewer
|
|
603
|
-
* @throws {Error} If map is not enabled
|
|
604
372
|
*/
|
|
605
373
|
isMapWide() {
|
|
606
|
-
if(!this.map) { throw new Error("Map is not enabled"); }
|
|
607
374
|
return this.mapContainer.parentNode == this.grid;
|
|
608
375
|
}
|
|
609
376
|
|
|
@@ -695,11 +462,9 @@ export default class Viewer extends Basic {
|
|
|
695
462
|
/**
|
|
696
463
|
* Toggle the viewer focus (either on picture or map)
|
|
697
464
|
* @memberof Panoramax.components.core.Viewer#
|
|
698
|
-
* @throws {Error} If map is not enabled
|
|
699
465
|
* @private
|
|
700
466
|
*/
|
|
701
467
|
_toggleFocus() {
|
|
702
|
-
if(!this.map) { throw new Error("Map is not enabled"); }
|
|
703
468
|
this._setFocus(this.isMapWide() ? "pic" : "map");
|
|
704
469
|
}
|
|
705
470
|
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import {LitElement, html, nothing, css} from "lit";
|
|
2
|
-
import { fa } from "../../utils/widgets";
|
|
3
|
-
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
|
|
4
|
-
import PanoramaxImg from "../../img/panoramax.svg";
|
|
5
2
|
|
|
6
3
|
/**
|
|
7
|
-
* Map legend displays information about map sources
|
|
4
|
+
* Map legend displays information about map sources.
|
|
8
5
|
* @class Panoramax.components.menus.MapLegend
|
|
9
6
|
* @element pnx-map-legend
|
|
10
7
|
* @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
|
|
@@ -22,14 +19,6 @@ export default class MapLegend extends LitElement {
|
|
|
22
19
|
small {
|
|
23
20
|
font-size: 1em;
|
|
24
21
|
}
|
|
25
|
-
.presentation {
|
|
26
|
-
display: flex;
|
|
27
|
-
gap: 5px;
|
|
28
|
-
align-items: center;
|
|
29
|
-
}
|
|
30
|
-
.logo {
|
|
31
|
-
width: 45px;
|
|
32
|
-
}
|
|
33
22
|
`;
|
|
34
23
|
|
|
35
24
|
/** @private */
|
|
@@ -37,15 +26,6 @@ export default class MapLegend extends LitElement {
|
|
|
37
26
|
const mapAttrib = this._parent?.map?._attribution?._innerContainer;
|
|
38
27
|
|
|
39
28
|
return html`
|
|
40
|
-
<div class="presentation">
|
|
41
|
-
<img class="logo" src=${PanoramaxImg} alt="" />
|
|
42
|
-
<div>
|
|
43
|
-
Panoramax est le géocommun des photos de rues.
|
|
44
|
-
<pnx-link-button title=${this._parent?._t.map.more_panoramax} kind="outline" href="https://panoramax.fr" target="_blank">
|
|
45
|
-
${fa(faInfoCircle, { styles: {height: "12px", "margin-inline": "3px"}})}
|
|
46
|
-
</pnx-link-button>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
29
|
${mapAttrib && mapAttrib.innerHTML.length > 0 ? html`${this._parent?._t.map.map_data}<br />${mapAttrib}` : nothing}
|
|
50
30
|
`;
|
|
51
31
|
}
|
|
@@ -3,7 +3,7 @@ import LoaderImgBase from "../../img/loader_base.jpg";
|
|
|
3
3
|
import LogoDead from "../../img/logo_dead.svg";
|
|
4
4
|
import {
|
|
5
5
|
getDistance, positionToXYZ, xyzToPosition,
|
|
6
|
-
getRelativeHeading, BASE_PANORAMA_ID,
|
|
6
|
+
getRelativeHeading, BASE_PANORAMA_ID, isNullId,
|
|
7
7
|
} from "../../utils/utils";
|
|
8
8
|
import { apiFeatureToPSVNode } from "../../utils/picture";
|
|
9
9
|
|
|
@@ -155,7 +155,7 @@ export default class Photo extends PSViewer {
|
|
|
155
155
|
* @memberof Panoramax.components.ui.Photo#
|
|
156
156
|
*/
|
|
157
157
|
async _getNodeFromAPI(picId) {
|
|
158
|
-
if(
|
|
158
|
+
if(isNullId(picId)) { return BASE_PANORAMA_NODE; }
|
|
159
159
|
|
|
160
160
|
const picApiResponse = await fetch(
|
|
161
161
|
this._parent.api.getPictureMetadataUrl(picId, this._picturesSequences[picId]),
|
|
@@ -490,10 +490,20 @@ export default class Photo extends PSViewer {
|
|
|
490
490
|
* @returns {object} Picture metadata
|
|
491
491
|
*/
|
|
492
492
|
getPictureMetadata() {
|
|
493
|
-
if(this._myVTour?.state?.currentNode?.id
|
|
493
|
+
if(isNullId(this._myVTour?.state?.currentNode?.id)) { return null; }
|
|
494
494
|
return this._myVTour.state.currentNode ? Object.assign({}, this._myVTour.state.currentNode) : null;
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
+
/**
|
|
498
|
+
* Get current picture ID, or loading picture ID if any.
|
|
499
|
+
* @memberof Panoramax.components.ui.Photo#
|
|
500
|
+
* @returns {string|null} Picture ID (current or loading), or null if none is selected.
|
|
501
|
+
*/
|
|
502
|
+
getPictureId() {
|
|
503
|
+
const id = this._myVTour?.state?.loadingNode || this._myVTour?.state?.currentNode?.id;
|
|
504
|
+
return isNullId(id) ? null : id;
|
|
505
|
+
}
|
|
506
|
+
|
|
497
507
|
/**
|
|
498
508
|
* Handler for select event.
|
|
499
509
|
* @private
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import {LitElement, html, css} from "lit";
|
|
2
2
|
import { panel } from "../../styles";
|
|
3
|
+
import { fa } from "../../../utils/widgets";
|
|
4
|
+
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
|
|
5
|
+
import PanoramaxImg from "../../../img/panoramax.svg";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Legend widget, handling switch between map and photo components.
|
|
9
|
+
* Also displays a default "About Panoramax" message.
|
|
6
10
|
* @class Panoramax.components.ui.widgets.Legend
|
|
7
11
|
* @element pnx-widget-legend
|
|
8
12
|
* @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
|
|
9
13
|
* @example
|
|
10
14
|
* ```html
|
|
11
|
-
* <pnx-widget-legend
|
|
15
|
+
* <pnx-widget-legend
|
|
16
|
+
* _parent=${viewer}
|
|
17
|
+
* focus="map"
|
|
18
|
+
* picture="PICTURE-ID-IF-ANY"
|
|
19
|
+
* />
|
|
12
20
|
* ```
|
|
13
21
|
*/
|
|
14
22
|
export default class Legend extends LitElement {
|
|
@@ -22,6 +30,15 @@ export default class Legend extends LitElement {
|
|
|
22
30
|
max-width: 80vh;
|
|
23
31
|
z-index: 120;
|
|
24
32
|
}
|
|
33
|
+
.presentation {
|
|
34
|
+
font-size: 0.9em;
|
|
35
|
+
display: flex;
|
|
36
|
+
gap: 5px;
|
|
37
|
+
align-items: center;
|
|
38
|
+
}
|
|
39
|
+
.logo {
|
|
40
|
+
width: 45px;
|
|
41
|
+
}
|
|
25
42
|
`];
|
|
26
43
|
|
|
27
44
|
/**
|
|
@@ -29,13 +46,27 @@ export default class Legend extends LitElement {
|
|
|
29
46
|
* @memberof Panoramax.components.ui.widgets.Legend#
|
|
30
47
|
* @type {Object}
|
|
31
48
|
* @property {string} [focus] The focused main component (map, pic)
|
|
49
|
+
* @property {string} [picture] The picture ID
|
|
32
50
|
*/
|
|
33
51
|
static properties = {
|
|
34
52
|
focus: {type: String},
|
|
53
|
+
picture: {type: String},
|
|
35
54
|
};
|
|
36
55
|
|
|
37
56
|
render() {
|
|
38
57
|
return html`<div class="pnx-panel pnx-padded" part="panel">
|
|
58
|
+
<div
|
|
59
|
+
class="presentation"
|
|
60
|
+
style=${this.focus != "map" && this.picture ? "display: none": ""}
|
|
61
|
+
>
|
|
62
|
+
<img class="logo" src=${PanoramaxImg} alt="" />
|
|
63
|
+
<div>
|
|
64
|
+
Panoramax est le géocommun des photos de rues.
|
|
65
|
+
<pnx-link-button title=${this._parent?._t.map.more_panoramax} kind="outline" href="https://panoramax.fr" target="_blank">
|
|
66
|
+
${fa(faInfoCircle, { styles: {height: "12px", "margin-inline": "3px"}})}
|
|
67
|
+
</pnx-link-button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
39
70
|
<pnx-picture-legend
|
|
40
71
|
._parent=${this._parent}
|
|
41
72
|
style=${this.focus == "map" ? "display: none": ""}
|
package/src/index.js
CHANGED
|
@@ -5,3 +5,4 @@ export * as utils from "./utils";
|
|
|
5
5
|
export {default as Viewer} from "./components/core/Viewer";
|
|
6
6
|
export {default as CoverageMap} from "./components/core/CoverageMap";
|
|
7
7
|
export {default as Editor} from "./components/core/Editor";
|
|
8
|
+
export {default as PhotoViewer} from "./components/core/PhotoViewer";
|