@panoramax/web-viewer 3.2.2 → 3.2.3-develop-557df57a
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 +19 -1
- package/build/editor.html +1 -1
- package/build/index.css +2 -2
- package/build/index.css.map +1 -1
- package/build/index.js +6 -6
- package/build/index.js.map +1 -1
- package/docs/02_Usage.md +15 -9
- package/package.json +2 -2
- package/public/editor.html +3 -3
- package/src/Editor.js +34 -34
- package/src/StandaloneMap.js +1 -1
- package/src/Viewer.js +10 -5
- package/src/components/CoreView.js +2 -1
- package/src/components/Loader.css +19 -1
- package/src/components/Loader.js +9 -1
- package/src/components/Map.js +75 -15
- package/src/components/Photo.js +19 -4
- package/src/translations/br.json +1 -0
- package/src/translations/da.json +2 -2
- package/src/translations/de.json +4 -3
- package/src/translations/en.json +1 -1
- package/src/translations/eo.json +9 -3
- package/src/translations/es.json +1 -1
- package/src/translations/fr.json +1 -1
- package/src/translations/it.json +9 -3
- package/src/translations/ja.json +182 -0
- package/src/translations/zh_Hant.json +3 -2
- package/src/utils/API.js +20 -3
- package/src/utils/Utils.js +16 -1
- package/src/viewer/URLHash.js +11 -0
- package/src/viewer/Widgets.js +14 -8
- package/tests/components/Map.test.js +8 -8
- package/tests/viewer/URLHash.test.js +4 -1
- package/tests/viewer/__snapshots__/Widgets.test.js.snap +8 -8
package/docs/02_Usage.md
CHANGED
|
@@ -291,6 +291,12 @@ Note that all functions of [MapLibre GL JS class Map][16] are also available.
|
|
|
291
291
|
|
|
292
292
|
Destroy any form of life in this component
|
|
293
293
|
|
|
294
|
+
### waitForEnoughMapLoaded
|
|
295
|
+
|
|
296
|
+
Helper to know when enough map background and Panoramax tiles are loaded for a proper display.
|
|
297
|
+
|
|
298
|
+
Returns **[Promise][19]** Resolves when enough is loaded
|
|
299
|
+
|
|
294
300
|
### reloadVectorTiles
|
|
295
301
|
|
|
296
302
|
Force refresh of vector tiles data
|
|
@@ -360,16 +366,16 @@ This is useful after a map theme change.
|
|
|
360
366
|
Photo is the component showing a single picture.
|
|
361
367
|
It uses Photo Sphere Viewer as a basis, and pre-configure dialog with STAC API.
|
|
362
368
|
|
|
363
|
-
Note that all functions of [PhotoSphereViewer Viewer class][
|
|
369
|
+
Note that all functions of [PhotoSphereViewer Viewer class][20] are available as well.
|
|
364
370
|
|
|
365
371
|
### Parameters
|
|
366
372
|
|
|
367
373
|
* `parent` **[CoreView][1]** The parent view
|
|
368
374
|
* `container` **[Element][8]** The DOM element to create into
|
|
369
|
-
* `options` **[object][10]?** The viewer options. Can be any of [Photo Sphere Viewer options][
|
|
375
|
+
* `options` **[object][10]?** The viewer options. Can be any of [Photo Sphere Viewer options][21] (optional, default `{}`)
|
|
370
376
|
|
|
371
377
|
* `options.transitionDuration` **[number][15]?** The number of milliseconds the transition animation should be.
|
|
372
|
-
* `options.shouldGoFast` **[function][
|
|
378
|
+
* `options.shouldGoFast` **[function][22]?** Function returning a boolean to indicate if we may skip loading HD images.
|
|
373
379
|
|
|
374
380
|
### getPictureMetadata
|
|
375
381
|
|
|
@@ -394,7 +400,7 @@ Displays in viewer a picture near to given coordinates
|
|
|
394
400
|
* `lat` **[number][15]** Latitude (WGS84)
|
|
395
401
|
* `lon` **[number][15]** Longitude (WGS84)
|
|
396
402
|
|
|
397
|
-
Returns **[Promise][
|
|
403
|
+
Returns **[Promise][19]** Resolves on picture ID if picture found, otherwise rejects
|
|
398
404
|
|
|
399
405
|
### getXY
|
|
400
406
|
|
|
@@ -676,7 +682,7 @@ Enable or disable JOSM live editing using [Remote][24]
|
|
|
676
682
|
|
|
677
683
|
* `enabled` **[boolean][14]** Set to true to enable JOSM live
|
|
678
684
|
|
|
679
|
-
Returns **[Promise][
|
|
685
|
+
Returns **[Promise][19]** Resolves on JOSM live being enabled or disabled
|
|
680
686
|
|
|
681
687
|
### setFocus
|
|
682
688
|
|
|
@@ -812,13 +818,13 @@ Type: [object][10]
|
|
|
812
818
|
|
|
813
819
|
[18]: https://maplibre.org/maplibre-style-spec/sources/#raster
|
|
814
820
|
|
|
815
|
-
[19]: https://
|
|
821
|
+
[19]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
|
816
822
|
|
|
817
|
-
[20]: https://photo-sphere-viewer.js.org/
|
|
823
|
+
[20]: https://photo-sphere-viewer.js.org/api/classes/core.viewer
|
|
818
824
|
|
|
819
|
-
[21]: https://
|
|
825
|
+
[21]: https://photo-sphere-viewer.js.org/guide/config.html#standard-options
|
|
820
826
|
|
|
821
|
-
[22]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/
|
|
827
|
+
[22]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
|
|
822
828
|
|
|
823
829
|
[23]: #CoreView
|
|
824
830
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panoramax/web-viewer",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.3-develop-557df57a",
|
|
4
4
|
"description": "Panoramax web viewer for geolocated pictures",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"author": "Panoramax team",
|
|
@@ -252,4 +252,4 @@
|
|
|
252
252
|
]
|
|
253
253
|
]
|
|
254
254
|
}
|
|
255
|
-
}
|
|
255
|
+
}
|
package/public/editor.html
CHANGED
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
window.onload = () => {
|
|
34
34
|
editor = new Panoramax.Editor(
|
|
35
35
|
"editor",
|
|
36
|
-
"https://
|
|
36
|
+
"https://panoramax.openstreetmap.fr/api",
|
|
37
37
|
{
|
|
38
|
-
selectedSequence: "
|
|
39
|
-
selectedPicture:
|
|
38
|
+
selectedSequence: "ecfe4b2c-0acd-4d3a-a10d-c3e6818755c8",
|
|
39
|
+
selectedPicture: "329af5c6-4761-4a6d-9c1e-674fd6daa8b6",
|
|
40
40
|
background: "aerial",
|
|
41
41
|
raster: {
|
|
42
42
|
type: "raster",
|
package/src/Editor.js
CHANGED
|
@@ -59,14 +59,11 @@ export default class Editor extends CoreView {
|
|
|
59
59
|
raster: options.raster,
|
|
60
60
|
background: options.background,
|
|
61
61
|
supplementaryStyle: this._createMapStyle(),
|
|
62
|
+
zoom: 15, // Hack to avoid _initMapPosition call
|
|
62
63
|
});
|
|
63
64
|
linkMapAndPhoto(this);
|
|
64
65
|
this._loadSequence();
|
|
65
66
|
this.map.once("load", () => {
|
|
66
|
-
this.map.setPaintProperty("geovisio_editor_sequences", "line-color", this.map._getLayerColorStyle("sequences"));
|
|
67
|
-
this.map.setPaintProperty("geovisio_editor_pictures", "circle-color", this.map._getLayerColorStyle("pictures"));
|
|
68
|
-
this.map.setLayoutProperty("geovisio_editor_sequences", "visibility", "visible");
|
|
69
|
-
this.map.setLayoutProperty("geovisio_editor_pictures", "visibility", "visible");
|
|
70
67
|
if(options.raster) { this._addMapBackgroundWidget(); }
|
|
71
68
|
this._bindPicturesEvents();
|
|
72
69
|
});
|
|
@@ -153,6 +150,15 @@ export default class Editor extends CoreView {
|
|
|
153
150
|
*/
|
|
154
151
|
_loadSequence() {
|
|
155
152
|
return this._api.getSequenceItems(this._selectedSeqId).then(seq => {
|
|
153
|
+
// Hide loader after source load
|
|
154
|
+
this.map.once("sourcedata", () => {
|
|
155
|
+
this.map.setPaintProperty("geovisio_editor_sequences", "line-color", this.map._getLayerColorStyle("sequences"));
|
|
156
|
+
this.map.setPaintProperty("geovisio_editor_pictures", "circle-color", this.map._getLayerColorStyle("pictures"));
|
|
157
|
+
this.map.setLayoutProperty("geovisio_editor_sequences", "visibility", "visible");
|
|
158
|
+
this.map.setLayoutProperty("geovisio_editor_pictures", "visibility", "visible");
|
|
159
|
+
this.map.once("styledata", () => this._loader.dismiss());
|
|
160
|
+
});
|
|
161
|
+
|
|
156
162
|
// Create data source
|
|
157
163
|
this._sequenceData = seq.features;
|
|
158
164
|
this.map.getSource("geovisio_editor_sequences").setData({
|
|
@@ -177,40 +183,34 @@ export default class Editor extends CoreView {
|
|
|
177
183
|
]
|
|
178
184
|
});
|
|
179
185
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
this.map.jumpTo({ center: pic.geometry.coordinates, zoom: 18 });
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
console.log("Picture with ID", pic, "was not found");
|
|
190
|
-
}
|
|
186
|
+
// Select picture if any
|
|
187
|
+
if(this._selectedPicId) {
|
|
188
|
+
const pic = seq.features.find(p => p.id === this._selectedPicId);
|
|
189
|
+
if(pic) {
|
|
190
|
+
this.select(this._selectedSeqId, this._selectedPicId, true);
|
|
191
|
+
this.map.jumpTo({ center: pic.geometry.coordinates, zoom: 18 });
|
|
191
192
|
}
|
|
192
|
-
// Show area of sequence otherwise
|
|
193
193
|
else {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
194
|
+
console.log("Picture with ID", pic, "was not found");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Show area of sequence otherwise
|
|
198
|
+
else {
|
|
199
|
+
const bbox = [
|
|
200
|
+
...seq.features[0].geometry.coordinates,
|
|
201
|
+
...seq.features[0].geometry.coordinates
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
for(let i=1; i < seq.features.length; i++) {
|
|
205
|
+
const c = seq.features[i].geometry.coordinates;
|
|
206
|
+
if(c[0] < bbox[0]) { bbox[0] = c[0]; }
|
|
207
|
+
if(c[1] < bbox[1]) { bbox[1] = c[1]; }
|
|
208
|
+
if(c[0] > bbox[2]) { bbox[2] = c[0]; }
|
|
209
|
+
if(c[1] > bbox[3]) { bbox[3] = c[1]; }
|
|
208
210
|
}
|
|
209
|
-
this._loader.dismiss();
|
|
210
|
-
};
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
this.map.fitBounds(bbox, {animate: false});
|
|
213
|
+
}
|
|
214
214
|
}).catch(e => this._loader.dismiss(e, this._t.gvs.error_api));
|
|
215
215
|
}
|
|
216
216
|
|
package/src/StandaloneMap.js
CHANGED
|
@@ -84,7 +84,7 @@ class StandaloneMap extends CoreView {
|
|
|
84
84
|
|
|
85
85
|
this.map = new MyMap(this, this.mapContainer, this._options);
|
|
86
86
|
this.map.addControl(new NavigationControl({ showCompass: false }));
|
|
87
|
-
this.map.
|
|
87
|
+
this.map.waitForEnoughMapLoaded().then(() => {
|
|
88
88
|
this.map.reloadLayersStyles();
|
|
89
89
|
this._loader.dismiss();
|
|
90
90
|
});
|
package/src/Viewer.js
CHANGED
|
@@ -192,8 +192,8 @@ class Viewer extends CoreView {
|
|
|
192
192
|
const onceStuffReady = () => {
|
|
193
193
|
this._widgets = new Widgets(this, this._options.widgets);
|
|
194
194
|
|
|
195
|
-
// Hide mini component if
|
|
196
|
-
if(this.map && this.
|
|
195
|
+
// Hide mini component if no selected picture
|
|
196
|
+
if(this.map && !this._options.selectedPicture) {
|
|
197
197
|
this.setUnfocusedVisible(false);
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -286,7 +286,9 @@ class Viewer extends CoreView {
|
|
|
286
286
|
delete this._widgets;
|
|
287
287
|
this._hash.destroy();
|
|
288
288
|
delete this._hash;
|
|
289
|
-
this.map
|
|
289
|
+
if (this.map) {
|
|
290
|
+
this.map.destroy();
|
|
291
|
+
}
|
|
290
292
|
delete this.map;
|
|
291
293
|
delete this._mapFilters;
|
|
292
294
|
this.psv.destroy();
|
|
@@ -347,8 +349,11 @@ class Viewer extends CoreView {
|
|
|
347
349
|
this.map._getLayerSortStyle = this._getLayerSortStyle.bind(this);
|
|
348
350
|
this.addEventListener("map:users-changed", resolve, { once: true });
|
|
349
351
|
this.container.classList.add("gvs-has-mini");
|
|
352
|
+
|
|
353
|
+
// Map double-click: unselect if focused, toggle focus if unfocused
|
|
350
354
|
this.map.on("dblclick", () => {
|
|
351
355
|
if(!this.isMapWide()) { this.setFocus("map"); }
|
|
356
|
+
else { this.select(); }
|
|
352
357
|
});
|
|
353
358
|
|
|
354
359
|
if (typeof this._options.map === "object" && this._options.map.startWide) {
|
|
@@ -1003,8 +1008,8 @@ class Viewer extends CoreView {
|
|
|
1003
1008
|
this.dispatchEvent(event);
|
|
1004
1009
|
|
|
1005
1010
|
if(this._josmListener) {
|
|
1006
|
-
this.removeEventListener("picture-loading", this._josmListener);
|
|
1007
|
-
this.removeEventListener("picture-loaded", this._josmListener);
|
|
1011
|
+
this.removeEventListener("psv:picture-loading", this._josmListener);
|
|
1012
|
+
this.removeEventListener("psv:picture-loaded", this._josmListener);
|
|
1008
1013
|
delete this._josmListener;
|
|
1009
1014
|
}
|
|
1010
1015
|
return Promise.resolve();
|
|
@@ -2,7 +2,7 @@ import "./CoreView.css";
|
|
|
2
2
|
import API from "../utils/API";
|
|
3
3
|
import { getTranslations } from "../utils/I18n";
|
|
4
4
|
import { DEFAULT_TILES } from "../utils/Map";
|
|
5
|
-
import { isInIframe, isInternetFast } from "../utils/Utils";
|
|
5
|
+
import { BASE_PANORAMA_ID, isInIframe, isInternetFast } from "../utils/Utils";
|
|
6
6
|
import PACKAGE_JSON from "../../package.json";
|
|
7
7
|
import Loader from "./Loader";
|
|
8
8
|
|
|
@@ -143,6 +143,7 @@ export default class CoreView extends EventTarget {
|
|
|
143
143
|
* @param {boolean} [force=false] Force select even if already selected
|
|
144
144
|
*/
|
|
145
145
|
select(seqId = null, picId = null, force = false) {
|
|
146
|
+
if(picId === BASE_PANORAMA_ID) { picId = null; }
|
|
146
147
|
const prevSeqId = this._selectedSeqId || null;
|
|
147
148
|
const prevPicId = this._selectedPicId || null;
|
|
148
149
|
if(!force && prevPicId == picId && prevSeqId == seqId) { return; } // Avoid running if already selected
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
display: flex;
|
|
23
23
|
flex-direction: column;
|
|
24
24
|
justify-content: center;
|
|
25
|
-
gap:
|
|
25
|
+
gap: 20px;
|
|
26
26
|
align-items: center;
|
|
27
27
|
background: #37474F;
|
|
28
28
|
z-index: 9000;
|
|
@@ -53,4 +53,22 @@
|
|
|
53
53
|
@keyframes rotating {
|
|
54
54
|
from { transform: rotate(0deg); }
|
|
55
55
|
to { transform: rotate(360deg); }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Call to action button */
|
|
59
|
+
.gvs .gvs-loader .gvs-loader-cta {
|
|
60
|
+
border: none;
|
|
61
|
+
border-radius: 7px;
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
font-size: 1.0em;
|
|
64
|
+
color: white;
|
|
65
|
+
background-color: #EF6C00;
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
margin: 10px;
|
|
68
|
+
padding: 5px 30px;
|
|
69
|
+
box-shadow: 2px 2px 2px rgba(0,0,0,0.3);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.gvs .gvs-loader .gvs-loader-cta:hover {
|
|
73
|
+
background-color: #F57C00;
|
|
56
74
|
}
|
package/src/components/Loader.js
CHANGED
|
@@ -83,7 +83,15 @@ export default class Loader {
|
|
|
83
83
|
this.container.children[0].src = LogoDead;
|
|
84
84
|
this.container.children[0].style.width = "200px";
|
|
85
85
|
this.container.children[0].style.animation = "unset";
|
|
86
|
-
|
|
86
|
+
|
|
87
|
+
let errHtml;
|
|
88
|
+
if(next) {
|
|
89
|
+
errHtml = `<button class="gvs-loader-cta">${this._parent._t.gvs.error_click}</button>`;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
errHtml = `<small>${this._parent._t.gvs.error_retry}</small>`;
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
if(errMeaningful) { errHtml = errMeaningful + "<br />" + errHtml; }
|
|
88
96
|
this.container.children[1].innerHTML = `${this._parent._t.gvs.error}<br />${errHtml}`;
|
|
89
97
|
if(next) {
|
package/src/components/Map.js
CHANGED
|
@@ -110,11 +110,16 @@ export default class Map extends maplibregl.Map {
|
|
|
110
110
|
}
|
|
111
111
|
}, 15000);
|
|
112
112
|
|
|
113
|
-
this.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
this.waitForEnoughMapLoaded().then(async () => await this._postLoad());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
async _postLoad() {
|
|
120
|
+
this.resize();
|
|
121
|
+
await this.setVisibleUsers(this._parent._options.users);
|
|
122
|
+
this.reloadLayersStyles();
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
/**
|
|
@@ -132,6 +137,54 @@ export default class Map extends maplibregl.Map {
|
|
|
132
137
|
delete this._userLayers;
|
|
133
138
|
}
|
|
134
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Helper to know when enough map background and Panoramax tiles are loaded for a proper display.
|
|
142
|
+
* @returns {Promise} Resolves when enough is loaded
|
|
143
|
+
*/
|
|
144
|
+
waitForEnoughMapLoaded() {
|
|
145
|
+
return new Promise((resolve) => {
|
|
146
|
+
let nbBgTiles = 0;
|
|
147
|
+
let nbFgTiles = 0;
|
|
148
|
+
let nbLoadedBgTiles = 0;
|
|
149
|
+
let nbLoadedFgTiles = 0;
|
|
150
|
+
|
|
151
|
+
const onSourceDataLoading = e => {
|
|
152
|
+
if(e.dataType === "source" && e.tile) {
|
|
153
|
+
if(e.sourceId.startsWith("geovisio")) {
|
|
154
|
+
nbFgTiles++;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
nbBgTiles++;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const onSourceData = e => {
|
|
162
|
+
if(e.dataType === "source" && e.tile) {
|
|
163
|
+
if(e.sourceId.startsWith("geovisio")) {
|
|
164
|
+
nbLoadedFgTiles++;
|
|
165
|
+
if(e.isSourceLoaded) { nbLoadedFgTiles = nbFgTiles; }
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
nbLoadedBgTiles++;
|
|
169
|
+
if(e.isSourceLoaded) { nbLoadedBgTiles = nbBgTiles; }
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
checkEnoughLoaded();
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const checkEnoughLoaded = () => {
|
|
176
|
+
if(nbLoadedBgTiles / nbBgTiles >= 0.75 && nbLoadedFgTiles / nbFgTiles >= 0.75) {
|
|
177
|
+
this.off("sourcedata", onSourceData);
|
|
178
|
+
this.off("sourcedataloading", onSourceDataLoading);
|
|
179
|
+
resolve();
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
this.on("sourcedataloading", onSourceDataLoading);
|
|
184
|
+
this.on("sourcedata", onSourceData);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
135
188
|
/**
|
|
136
189
|
* Sets map view based on returned API bbox (if no precise option given by user).
|
|
137
190
|
* @private
|
|
@@ -148,7 +201,7 @@ export default class Map extends maplibregl.Map {
|
|
|
148
201
|
try {
|
|
149
202
|
bbox = new maplibregl.LngLatBounds(bbox);
|
|
150
203
|
if(this.loaded()) { this.fitBounds(bbox, { "animate": false }); }
|
|
151
|
-
else { this.
|
|
204
|
+
else { this.waitForEnoughMapLoaded().then(() => this.fitBounds(bbox, { "animate": false })); }
|
|
152
205
|
}
|
|
153
206
|
catch(e) {
|
|
154
207
|
console.warn("Received invalid bbox: "+bbox);
|
|
@@ -344,20 +397,27 @@ export default class Map extends maplibregl.Map {
|
|
|
344
397
|
this._picMarkerPreview.remove();
|
|
345
398
|
|
|
346
399
|
// Show marker corresponding to selection
|
|
347
|
-
|
|
348
|
-
.
|
|
349
|
-
|
|
350
|
-
|
|
400
|
+
if(lon !== undefined && lat !== undefined) {
|
|
401
|
+
this._picMarker
|
|
402
|
+
.setLngLat([lon, lat])
|
|
403
|
+
.setRotation(heading)
|
|
404
|
+
.addTo(this);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
this._picMarker.remove();
|
|
408
|
+
}
|
|
351
409
|
|
|
352
410
|
// Update map style to see selected sequence
|
|
353
411
|
this.reloadLayersStyles();
|
|
354
412
|
|
|
355
413
|
// Move map to picture coordinates
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
414
|
+
if(lon !== undefined && lat !== undefined) {
|
|
415
|
+
this.flyTo({
|
|
416
|
+
center: [lon, lat],
|
|
417
|
+
zoom: this.getZoom() < TILES_PICTURES_ZOOM+2 ? TILES_PICTURES_ZOOM+2 : this.getZoom(),
|
|
418
|
+
maxDuration: 2000
|
|
419
|
+
});
|
|
420
|
+
}
|
|
361
421
|
}
|
|
362
422
|
|
|
363
423
|
/**
|
package/src/components/Photo.js
CHANGED
|
@@ -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
|
-
apiFeatureToPSVNode, getRelativeHeading,
|
|
6
|
+
apiFeatureToPSVNode, getRelativeHeading, BASE_PANORAMA_ID,
|
|
7
7
|
} from "../utils/Utils";
|
|
8
8
|
|
|
9
9
|
// Photo Sphere Viewer imports
|
|
@@ -24,6 +24,17 @@ const BASE_PANORAMA = {
|
|
|
24
24
|
rows: 1,
|
|
25
25
|
tileUrl: () => null,
|
|
26
26
|
};
|
|
27
|
+
const BASE_PANORAMA_NODE = {
|
|
28
|
+
id: BASE_PANORAMA_ID,
|
|
29
|
+
caption: "",
|
|
30
|
+
panorama: BASE_PANORAMA,
|
|
31
|
+
links: [],
|
|
32
|
+
gps: [0,0],
|
|
33
|
+
sequence: {},
|
|
34
|
+
sphereCorrection: {},
|
|
35
|
+
horizontalFov: 360,
|
|
36
|
+
properties: {},
|
|
37
|
+
};
|
|
27
38
|
|
|
28
39
|
export const PSV_DEFAULT_ZOOM = 30;
|
|
29
40
|
export const PSV_ANIM_DURATION = 250;
|
|
@@ -118,7 +129,7 @@ export default class Photo extends PSViewer {
|
|
|
118
129
|
* @returns {Promise} Resolves on PSV node metadata
|
|
119
130
|
*/
|
|
120
131
|
async _getNodeFromAPI(picId) {
|
|
121
|
-
if(!picId) { return; }
|
|
132
|
+
if(!picId || picId === BASE_PANORAMA_ID) { return BASE_PANORAMA_NODE; }
|
|
122
133
|
|
|
123
134
|
const picApiResponse = await fetch(
|
|
124
135
|
this._parent._api.getPictureMetadataUrl(picId, this._picturesSequences[picId]),
|
|
@@ -364,7 +375,7 @@ export default class Photo extends PSViewer {
|
|
|
364
375
|
|
|
365
376
|
/**
|
|
366
377
|
* Event handler for node change in PSV.
|
|
367
|
-
* Allows to send a custom "picture-loaded" event.
|
|
378
|
+
* Allows to send a custom "psv:picture-loaded" event.
|
|
368
379
|
* @private
|
|
369
380
|
*/
|
|
370
381
|
_onNodeChanged(e) {
|
|
@@ -376,7 +387,10 @@ export default class Photo extends PSViewer {
|
|
|
376
387
|
if(e.node.id) {
|
|
377
388
|
this._parent.select(e.node?.sequence?.id, e.node.id);
|
|
378
389
|
const picMeta = this.getPictureMetadata();
|
|
379
|
-
if(!picMeta) {
|
|
390
|
+
if(!picMeta) {
|
|
391
|
+
this._parent.dispatchEvent(new CustomEvent("psv:picture-loaded", {detail: {}}));
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
380
394
|
this._prevSequence = picMeta.sequence.id;
|
|
381
395
|
|
|
382
396
|
/**
|
|
@@ -453,6 +467,7 @@ export default class Photo extends PSViewer {
|
|
|
453
467
|
* @returns {object} Picture metadata
|
|
454
468
|
*/
|
|
455
469
|
getPictureMetadata() {
|
|
470
|
+
if(this._myVTour?.state?.currentNode?.id === BASE_PANORAMA_ID) { return null; }
|
|
456
471
|
return this._myVTour.state.currentNode ? Object.assign({}, this._myVTour.state.currentNode) : null;
|
|
457
472
|
}
|
|
458
473
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/src/translations/da.json
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"sequence_speed": "Afspillerens hastighed",
|
|
42
42
|
"legend_license": "Licens: {l}",
|
|
43
43
|
"legend_title": "Vis detaljer om billedet",
|
|
44
|
-
"error_click": "
|
|
44
|
+
"error_click": "Fortsæt",
|
|
45
45
|
"error": "Vi har et problem…",
|
|
46
46
|
"search_address": "Søg efter en adresse, by…",
|
|
47
47
|
"sequence_pause": "Sæt sekvensen på pause",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"filter_user": "Bruger",
|
|
89
89
|
"filter_user_mypics": "Mine billeder",
|
|
90
90
|
"filter_picture": "Billedtype",
|
|
91
|
-
"filter_zoom_in": "Zoom ind for at
|
|
91
|
+
"filter_zoom_in": "Zoom ind for at se dette filter",
|
|
92
92
|
"picture_flat": "Klassisk",
|
|
93
93
|
"picture_360": "360°",
|
|
94
94
|
"filter_qualityscore_help": "Klik for at aktivere eller deaktivere",
|
package/src/translations/de.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"show_psv": "Bildbetrachter anzeigen",
|
|
43
43
|
"show_map": "Karte anzeigen",
|
|
44
44
|
"search_user": "Benutzernamen suchen…",
|
|
45
|
-
"filter_zoom_in": "Hereinzoomen um Filter
|
|
45
|
+
"filter_zoom_in": "Hereinzoomen um diesen Filter zu sehen",
|
|
46
46
|
"picture_flat": "Klassisch",
|
|
47
47
|
"picture_360": "360°",
|
|
48
48
|
"filter_camera_model": "Nach Kameramodell",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"report": "Foto melden",
|
|
147
147
|
"legend_title": "Zeige Bilderdetails",
|
|
148
148
|
"report_wait": "Bericht senden…",
|
|
149
|
-
"error_click": "
|
|
149
|
+
"error_click": "Weiter",
|
|
150
150
|
"error_retry": "Bitte später erneut versuchen",
|
|
151
151
|
"metadata_camera_resolution": "Auflösung",
|
|
152
152
|
"filter_user_mypics": "Meine Fotos",
|
|
@@ -165,7 +165,8 @@
|
|
|
165
165
|
"qualityscore_doc_link": "Weitere Informationen zur Berechnung des Qualitätsfaktors findest du in unserer Dokumentation.",
|
|
166
166
|
"qualityscore_doc_1": "Panoramax bietet einen Qualitätsfaktor für jedes Bild. Es ermöglicht eine einfache Kartenfilterung und eine umfassende Anzeige der Verfügbarkeit hochwertiger Bilder.",
|
|
167
167
|
"qualityscore_doc_2": "Die Note wird den Benutzern als A/B/C/D/E-Bewertung angezeigt (A ist die beste, E die schlechteste) und anhand dieser Skala grafisch dargestellt:",
|
|
168
|
-
"qualityscore_doc_3": "Die Berechnung erfolgt auf der Grundlage der GPS-Genauigkeit und der Bildauflösung. Ein professionelles System wird mit A bewertet, eine 360-Grad-Action-Kamera mit B und ein Smartphone mit C/D/E."
|
|
168
|
+
"qualityscore_doc_3": "Die Berechnung erfolgt auf der Grundlage der GPS-Genauigkeit und der Bildauflösung. Ein professionelles System wird mit A bewertet, eine 360-Grad-Action-Kamera mit B und ein Smartphone mit C/D/E.",
|
|
169
|
+
"minimize_short": "Verbergen"
|
|
169
170
|
},
|
|
170
171
|
"psv": {
|
|
171
172
|
"twoFingers": "Nutzen sie zwei Finger zum navigieren",
|
package/src/translations/en.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"copy": "Copy",
|
|
43
43
|
"copied": "Copied",
|
|
44
44
|
"error": "We have a problem…",
|
|
45
|
-
"error_click": "
|
|
45
|
+
"error_click": "Continue",
|
|
46
46
|
"error_retry": "Please retry later",
|
|
47
47
|
"sequence_next": "Next picture in sequence",
|
|
48
48
|
"sequence_play": "Play along this sequence",
|
package/src/translations/eo.json
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"copy": "Kopii",
|
|
28
28
|
"copied": "Kopiita",
|
|
29
29
|
"error": "Ni havas problemon…",
|
|
30
|
-
"error_click": "
|
|
30
|
+
"error_click": "Kontinui",
|
|
31
31
|
"error_retry": "Bonvolu reprovi poste",
|
|
32
32
|
"search_address": "Serĉi adreson, urbon…",
|
|
33
33
|
"filters": "Filtriloj",
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"contrast": "Pliigi bildkontraston",
|
|
125
125
|
"metadata_general_picid": "Fotoidentigilo",
|
|
126
126
|
"filter_picture": "Bilda tipo",
|
|
127
|
-
"filter_zoom_in": "Zomu por vidi
|
|
127
|
+
"filter_zoom_in": "Zomu por vidi tiu filtrilo",
|
|
128
128
|
"map_background": "Bazmapo",
|
|
129
129
|
"map_background_aerial": "Aera",
|
|
130
130
|
"map_background_streets": "Stratoj",
|
|
@@ -161,7 +161,13 @@
|
|
|
161
161
|
"report_success": "La raporto estis sukcese sendita. Ĝi estos reviziita baldaŭ.",
|
|
162
162
|
"report_details_placeholder": "Opcie, vi povas aldoni detalojn pri la problemo",
|
|
163
163
|
"report_email_placeholder": "Opcie",
|
|
164
|
-
"report_failure": "Eraro okazis dum kreo de la raporto: {e}. Bonvolu provi denove poste."
|
|
164
|
+
"report_failure": "Eraro okazis dum kreo de la raporto: {e}. Bonvolu provi denove poste.",
|
|
165
|
+
"qualityscore_doc_3": "Ĝi estas kalkulita surbaze de GPS-precizeco kaj bildrezolucio. Profesiaj sistemoj havos A-poentaron, 360°-akcifotilo havos B-poentaron, kaj poŝtelefono havos C/D/E-poentaron.",
|
|
166
|
+
"qualityscore_title": "Pri la kvalita poentaro",
|
|
167
|
+
"qualityscore_doc_1": "Panoramax ofertas Kvalitan Poentaron por ĉiu bildo. Ĝi ebligas facilan mapfiltradon kaj ampleksan vidigon de la havebleco de altkvalitaj bildoj.",
|
|
168
|
+
"qualityscore_doc_link": "Pli da detaloj pri la kalkulo de la Kvalita Poentaro estas disponeblaj en nia dokumentado.",
|
|
169
|
+
"minimize_short": "Maski",
|
|
170
|
+
"qualityscore_doc_2": "La poentaro estas montrita al uzantoj kiel litero A/B/C/D/E (A estas la plej bona, E la plej malbona) kaj grafike prezentita per ĉi tiu skalo:"
|
|
165
171
|
},
|
|
166
172
|
"maplibre": {
|
|
167
173
|
"GeolocateControl.FindMyLocation": "Trovi mian pozicion",
|
package/src/translations/es.json
CHANGED
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"sequence_play": "Reproducir esta secuencia",
|
|
96
96
|
"sequence_pause": "Pausar la secuencia",
|
|
97
97
|
"sequence_prev": "Imagen anterior de la secuencia",
|
|
98
|
-
"error_click": "
|
|
98
|
+
"error_click": "Continuar",
|
|
99
99
|
"error_retry": "Por favor, inténtalo más tarde",
|
|
100
100
|
"error_psv": "El visor de fotos esféricas no se carga correctamente",
|
|
101
101
|
"error_pic": "No se encuentra la imagen que queríamos",
|
package/src/translations/fr.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"copy": "Copier",
|
|
43
43
|
"copied": "Copié",
|
|
44
44
|
"error": "On a un problème…",
|
|
45
|
-
"error_click": "
|
|
45
|
+
"error_click": "Continuer",
|
|
46
46
|
"error_retry": "Merci de réessayer plus tard",
|
|
47
47
|
"sequence_next": "Photo suivante dans la séquence",
|
|
48
48
|
"sequence_play": "Parcourir cette séquence",
|
package/src/translations/it.json
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"copy": "Copia",
|
|
27
27
|
"copied": "Copiato",
|
|
28
28
|
"error": "Abbiamo un problema…",
|
|
29
|
-
"error_click": "
|
|
29
|
+
"error_click": "Continuare",
|
|
30
30
|
"error_retry": "Riprovare più tardi",
|
|
31
31
|
"sequence_play": "Riproduci questa sequenza",
|
|
32
32
|
"sequence_pause": "Pausa la sequenza",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"filter_date_1year": "1 anno",
|
|
77
77
|
"filter_user_mypics": "Le mie foto",
|
|
78
78
|
"filter_picture": "Tipo di foto",
|
|
79
|
-
"filter_zoom_in": "Ingrandisci per
|
|
79
|
+
"filter_zoom_in": "Ingrandisci per vedere questo filtro",
|
|
80
80
|
"picture_flat": "Classica",
|
|
81
81
|
"picture_360": "360°",
|
|
82
82
|
"filter_qualityscore_help": "Clicca per abilitare o disabilitare",
|
|
@@ -156,7 +156,13 @@
|
|
|
156
156
|
"metadata_exif_value": "Valore",
|
|
157
157
|
"report": "Segnala foto",
|
|
158
158
|
"report_details_placeholder": "Facoltativo, puoi aggiungere dei dettagli sul problema e sul perché lo ritieni rilevante",
|
|
159
|
-
"report_success": "La segnalazione è stata inviata correttamente. Non appena possibile verrà esaminata."
|
|
159
|
+
"report_success": "La segnalazione è stata inviata correttamente. Non appena possibile verrà esaminata.",
|
|
160
|
+
"minimize_short": "Nascondi",
|
|
161
|
+
"qualityscore_title": "Informazioni sul punteggio di qualità",
|
|
162
|
+
"qualityscore_doc_1": "Panoramax propone un Punteggio della qualità per ogni foto. Ciò permette di filtrare facilmente la mappa e mostrare le foto di alta qualità disponibili.",
|
|
163
|
+
"qualityscore_doc_2": "Il voto è mostrato agli utenti con un valore tipo A/B/C/D/E (A è il voto migliore, E il peggiore) e graficamente viene mostrato con la seguente scala:",
|
|
164
|
+
"qualityscore_doc_link": "Nella nostra documentazione sono presenti maggiori dettagli sul calcolo del Punteggio della qualità.",
|
|
165
|
+
"qualityscore_doc_3": "Esso è calcolato basandosi sulla precisione del GPS e sulla risoluzione della foto. Un sistema professionale avrà un punteggio A, un action camera a 360° avrà un punteggio B e uno smartphone verrà classificato come C, D o E."
|
|
160
166
|
},
|
|
161
167
|
"psv": {
|
|
162
168
|
"loadError": "Impossibile caricare l’immagine panoramica",
|