@panoramax/web-viewer 4.0.3 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -1
- package/build/index.css +9 -9
- package/build/index.css.map +1 -1
- package/build/index.js +640 -456
- package/build/index.js.map +1 -1
- package/build/photo.html +1 -1
- package/build/viewer.html +3 -3
- package/build/widgets.html +1 -1
- package/config/jest/mocks.js +9 -1
- package/docs/03_URL_settings.md +21 -0
- package/docs/09_Develop.md +6 -0
- package/docs/images/comparative_3drender.jpg +0 -0
- package/docs/index.md +13 -0
- package/docs/reference/components/core/Editor.md +18 -0
- package/docs/reference/components/core/PhotoViewer.md +1 -0
- package/docs/reference/components/core/Viewer.md +1 -0
- package/docs/reference/components/menus/MapLegend.md +17 -0
- package/docs/reference/components/menus/MiniPictureLegend.md +15 -0
- package/docs/reference/components/menus/PictureLegend.md +17 -0
- package/docs/reference/components/ui/AnnotationsSwitch.md +15 -0
- package/docs/reference/components/ui/Button.md +1 -1
- package/docs/reference/components/ui/CopyButton.md +1 -1
- package/docs/reference/components/ui/LinkButton.md +1 -1
- package/docs/reference/components/ui/Map.md +18 -2
- package/docs/reference/components/ui/MapMore.md +6 -2
- package/docs/reference/components/ui/SemanticsEditor.md +87 -0
- package/docs/reference/components/ui/widgets/Legend.md +5 -4
- package/docs/reference/utils/URLHandler.md +7 -0
- package/docs/reference.md +3 -1
- package/docs/tutorials/aerial_imagery.md +13 -11
- package/mkdocs.yml +3 -1
- package/package.json +7 -7
- package/public/photo.html +1 -1
- package/public/viewer.html +3 -3
- package/public/widgets.html +32 -0
- package/src/components/core/Basic.css +2 -0
- package/src/components/core/Basic.js +3 -1
- package/src/components/core/CoverageMap.js +6 -0
- package/src/components/core/Editor.css +1 -0
- package/src/components/core/Editor.js +58 -7
- package/src/components/core/PhotoViewer.css +5 -10
- package/src/components/core/PhotoViewer.js +55 -20
- package/src/components/core/Viewer.css +9 -2
- package/src/components/core/Viewer.js +62 -33
- package/src/components/layout/BottomDrawer.js +2 -1
- package/src/components/layout/Tabs.js +4 -0
- package/src/components/menus/AnnotationsList.js +13 -9
- package/src/components/menus/MapBackground.js +8 -3
- package/src/components/menus/MapFilters.js +11 -2
- package/src/components/menus/MapLayers.js +3 -2
- package/src/components/menus/MapLegend.js +28 -4
- package/src/components/menus/MiniPictureLegend.js +74 -0
- package/src/components/menus/PictureLegend.js +88 -33
- package/src/components/menus/PictureMetadata.js +49 -17
- package/src/components/menus/PlayerOptions.js +3 -3
- package/src/components/menus/Share.js +3 -3
- package/src/components/menus/index.js +5 -4
- package/src/components/styles.js +11 -0
- package/src/components/ui/AnnotationsSwitch.js +169 -0
- package/src/components/ui/Button.js +1 -1
- package/src/components/ui/CopyButton.js +1 -1
- package/src/components/ui/LinkButton.js +1 -1
- package/src/components/ui/Map.css +4 -0
- package/src/components/ui/Map.js +17 -5
- package/src/components/ui/MapMore.js +61 -25
- package/src/components/ui/Photo.css +11 -2
- package/src/components/ui/Photo.js +6 -3
- package/src/components/ui/SemanticsEditor.js +157 -0
- package/src/components/ui/index.js +2 -1
- package/src/components/ui/widgets/GeoSearch.js +3 -2
- package/src/components/ui/widgets/Legend.js +69 -14
- package/src/components/ui/widgets/MapFiltersButton.js +3 -3
- package/src/components/ui/widgets/MapLayersButton.js +3 -3
- package/src/components/ui/widgets/OSMEditors.js +2 -2
- package/src/components/ui/widgets/PictureLegendActions.js +24 -42
- package/src/components/ui/widgets/Player.js +3 -3
- package/src/components/ui/widgets/Zoom.js +4 -2
- package/src/translations/ar.json +1 -0
- package/src/translations/da.json +3 -2
- package/src/translations/de.json +64 -13
- package/src/translations/en.json +5 -1
- package/src/translations/eo.json +32 -2
- package/src/translations/fr.json +7 -1
- package/src/translations/it.json +33 -2
- package/src/translations/nl.json +53 -11
- package/src/translations/zh_Hant.json +29 -2
- package/src/utils/API.js +17 -1
- package/src/utils/InitParameters.js +46 -4
- package/src/utils/URLHandler.js +9 -1
- package/src/utils/map.js +24 -1
- package/src/utils/semantics.js +53 -1
- package/src/utils/services.js +16 -0
- package/src/utils/widgets.js +20 -0
- package/tests/components/core/Editor.test.js +1 -1
- package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +18 -6
- package/tests/components/core/__snapshots__/Viewer.test.js.snap +15 -3
- package/tests/components/ui/Photo.test.js +1 -0
- package/tests/components/ui/__snapshots__/Map.test.js.snap +164 -0
- package/tests/utils/InitParameters.test.js +27 -0
- package/tests/utils/map.test.js +12 -0
- package/tests/utils/semantics.test.js +34 -5
- package/docs/reference/components/ui/HashTags.md +0 -15
- package/src/components/ui/HashTags.js +0 -98
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LitElement, nothing, css } from "lit";
|
|
2
2
|
import { html, unsafeStatic } from "lit/static-html.js";
|
|
3
|
-
import { fa } from "../../utils/widgets";
|
|
3
|
+
import { fa, onceParentAvailable } from "../../utils/widgets";
|
|
4
4
|
import { faLocationDot } from "@fortawesome/free-solid-svg-icons/faLocationDot";
|
|
5
5
|
import { faMedal } from "@fortawesome/free-solid-svg-icons/faMedal";
|
|
6
6
|
import { faCamera } from "@fortawesome/free-solid-svg-icons/faCamera";
|
|
@@ -14,7 +14,8 @@ import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
|
|
|
14
14
|
import { faTags } from "@fortawesome/free-solid-svg-icons/faTags";
|
|
15
15
|
import { faSvg, titles, textarea, hidden } from "../styles";
|
|
16
16
|
import { createWebComp } from "../../utils/widgets";
|
|
17
|
-
import { getGPSPrecision } from "../../utils/picture";
|
|
17
|
+
import { getGPSPrecision, getHashTags } from "../../utils/picture";
|
|
18
|
+
import { PanoramaxMetaCatalogURL } from "../../utils/services";
|
|
18
19
|
import {
|
|
19
20
|
getGrade, QUALITYSCORE_GPS_VALUES, QUALITYSCORE_RES_360_VALUES,
|
|
20
21
|
QUALITYSCORE_RES_FLAT_VALUES, QUALITYSCORE_POND_GPS, QUALITYSCORE_POND_RES
|
|
@@ -81,14 +82,16 @@ export default class PictureMetadata extends LitElement {
|
|
|
81
82
|
connectedCallback() {
|
|
82
83
|
super.connectedCallback();
|
|
83
84
|
|
|
84
|
-
this.
|
|
85
|
-
|
|
86
|
-
this._parent.
|
|
87
|
-
this.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
onceParentAvailable(this).then(() => {
|
|
86
|
+
this._meta = this._parent?.psv?.getPictureMetadata();
|
|
87
|
+
this._parent?.oncePSVReady?.().then(() => {
|
|
88
|
+
this._parent.psv.addEventListener("picture-loaded", () => {
|
|
89
|
+
this._meta = this._parent.psv.getPictureMetadata();
|
|
90
|
+
});
|
|
91
|
+
this._parent.psv.addEventListener("annotation-click", () => {
|
|
92
|
+
const tabs = this.shadowRoot.querySelector("pnx-tabs");
|
|
93
|
+
if(tabs) { tabs.setAttribute("activeTabIndex", 4); }
|
|
94
|
+
});
|
|
92
95
|
});
|
|
93
96
|
});
|
|
94
97
|
}
|
|
@@ -101,6 +104,14 @@ export default class PictureMetadata extends LitElement {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
|
|
107
|
+
/** @private */
|
|
108
|
+
_onCaptureDateClick() {
|
|
109
|
+
const qsTab = this.shadowRoot.querySelector("pnx-tabs");
|
|
110
|
+
if(qsTab) {
|
|
111
|
+
qsTab.setAttribute("activeTabIndex", 1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
104
115
|
/** @private */
|
|
105
116
|
_toTab(title, data) {
|
|
106
117
|
return html`
|
|
@@ -108,7 +119,7 @@ export default class PictureMetadata extends LitElement {
|
|
|
108
119
|
<div slot="content" class="data-blocks">
|
|
109
120
|
${data.filter(b => b).map(b => html`<div class="data-block" style=${b.style}>
|
|
110
121
|
<h5>${b.title}</h5>
|
|
111
|
-
<div style=${b.content_style}>${b.content}</div>
|
|
122
|
+
<div style=${b.content_style} @click=${b.click}>${b.content}</div>
|
|
112
123
|
</div>`)}
|
|
113
124
|
</div>
|
|
114
125
|
`;
|
|
@@ -234,6 +245,16 @@ export default class PictureMetadata extends LitElement {
|
|
|
234
245
|
);
|
|
235
246
|
let semanticsData = [];
|
|
236
247
|
if(hasSemantics) {
|
|
248
|
+
// Hashtags
|
|
249
|
+
const hashtags = getHashTags(this._meta);
|
|
250
|
+
if(hashtags.length > 0) {
|
|
251
|
+
semanticsData.push({
|
|
252
|
+
title: this._parent?._t.pnx.semantics_hashtags,
|
|
253
|
+
style: "width: 100%",
|
|
254
|
+
content: hashtags.join(" ")
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
237
258
|
// Full list of picture tags
|
|
238
259
|
semanticsData.push({
|
|
239
260
|
title: this._parent?._t.pnx.semantics_tags_picture,
|
|
@@ -284,7 +305,7 @@ export default class PictureMetadata extends LitElement {
|
|
|
284
305
|
}
|
|
285
306
|
return {
|
|
286
307
|
title: key,
|
|
287
|
-
content: value.length > 30 ? html`<textarea readonly
|
|
308
|
+
content: value.length > 30 ? html`<textarea readonly .value=${value}></textarea>`: value,
|
|
288
309
|
style: value.length > 30 ? "width: 100%" : undefined
|
|
289
310
|
};
|
|
290
311
|
});
|
|
@@ -313,9 +334,11 @@ export default class PictureMetadata extends LitElement {
|
|
|
313
334
|
// Capture date
|
|
314
335
|
this._meta?.caption?.date && {
|
|
315
336
|
title: this._parent?._t.pnx.metadata_general_date,
|
|
337
|
+
click: this._onCaptureDateClick,
|
|
338
|
+
content_style: "cursor: pointer",
|
|
316
339
|
content: html`
|
|
317
340
|
<strong>${new Intl.DateTimeFormat(lang, {timeZone: this._meta.caption.tz, dateStyle: "long"}).format(this._meta.caption.date)}</strong>
|
|
318
|
-
<br />${new Intl.DateTimeFormat(lang, {timeZone: this._meta.caption.tz, hour: "numeric",minute:"numeric"}).format(this._meta.caption.date)}
|
|
341
|
+
<br />${new Intl.DateTimeFormat(lang, {timeZone: this._meta.caption.tz, hour: "numeric",minute:"numeric", second: "numeric"}).format(this._meta.caption.date)}
|
|
319
342
|
`
|
|
320
343
|
},
|
|
321
344
|
// Camera
|
|
@@ -334,10 +357,10 @@ export default class PictureMetadata extends LitElement {
|
|
|
334
357
|
// Quality score
|
|
335
358
|
hasQualityScore && {
|
|
336
359
|
title: this._parent?._t.pnx.metadata_quality,
|
|
360
|
+
click: this._onQualityScoreClick,
|
|
337
361
|
content: html`<pnx-quality-score
|
|
338
362
|
grade=${generalGrade}
|
|
339
363
|
style="font-size: 14px; cursor: pointer"
|
|
340
|
-
@click=${this._onQualityScoreClick}
|
|
341
364
|
/>`
|
|
342
365
|
},
|
|
343
366
|
// Copy ID
|
|
@@ -367,9 +390,18 @@ export default class PictureMetadata extends LitElement {
|
|
|
367
390
|
},
|
|
368
391
|
this._meta?.origInstance && {
|
|
369
392
|
title: this._parent?._t.pnx.metadata_general_instance,
|
|
370
|
-
content: html`<strong
|
|
371
|
-
|
|
372
|
-
|
|
393
|
+
content: html`<strong>
|
|
394
|
+
<a href=${this._meta.origInstance.href+window.location.search} target="_blank" style="text-decoration: none">
|
|
395
|
+
<img
|
|
396
|
+
src=${PanoramaxMetaCatalogURL()+"/api/instances/"+this._meta.origInstance.instance_name+"/logo"}
|
|
397
|
+
style="height: 30px; max-width: 150px; vertical-align: middle"
|
|
398
|
+
alt=""
|
|
399
|
+
/>
|
|
400
|
+
<span style="text-decoration: underline">
|
|
401
|
+
${this._meta.origInstance.instance_name || this._meta.origInstance.href.replace(/^http.?:\/\//, "")}
|
|
402
|
+
</span>
|
|
403
|
+
</a>
|
|
404
|
+
</strong>`
|
|
373
405
|
}
|
|
374
406
|
];
|
|
375
407
|
|
|
@@ -4,7 +4,7 @@ import { faRocket } from "@fortawesome/free-solid-svg-icons/faRocket";
|
|
|
4
4
|
import { faLightbulb } from "@fortawesome/free-solid-svg-icons/faLightbulb";
|
|
5
5
|
import { faPersonBiking } from "@fortawesome/free-solid-svg-icons/faPersonBiking";
|
|
6
6
|
import { PIC_MAX_STAY_DURATION } from "../ui/Photo";
|
|
7
|
-
import { fa } from "../../utils/widgets";
|
|
7
|
+
import { fa, onceParentAvailable } from "../../utils/widgets";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Player Options menu displays player speed and contrast settings.
|
|
@@ -40,9 +40,9 @@ export default class PlayerOptions extends LitElement {
|
|
|
40
40
|
/** @private */
|
|
41
41
|
connectedCallback() {
|
|
42
42
|
super.connectedCallback();
|
|
43
|
-
this._parent?.psv?.addEventListener("transition-duration-changed", e => {
|
|
43
|
+
onceParentAvailable(this).then(() => this._parent?.psv?.addEventListener("transition-duration-changed", e => {
|
|
44
44
|
this.renderRoot.querySelector("#pnx-player-speed").value = PIC_MAX_STAY_DURATION - e.detail.value;
|
|
45
|
-
});
|
|
45
|
+
}));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/** @private */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LitElement, css, html } from "lit";
|
|
2
|
-
import { fa } from "../../utils/widgets";
|
|
2
|
+
import { fa, onceParentAvailable } from "../../utils/widgets";
|
|
3
3
|
import { faSvg, textarea, titles, input } from "../styles";
|
|
4
4
|
import { faMap } from "@fortawesome/free-solid-svg-icons/faMap";
|
|
5
5
|
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons/faCircleInfo";
|
|
@@ -47,7 +47,7 @@ export default class ShareMenu extends LitElement {
|
|
|
47
47
|
/** @private */
|
|
48
48
|
connectedCallback() {
|
|
49
49
|
super.connectedCallback();
|
|
50
|
-
this._parent
|
|
50
|
+
onceParentAvailable(this).then(() => this._parent.onceReady()).then(() => {
|
|
51
51
|
this._onUrlChange();
|
|
52
52
|
this._parent.urlHandler.addEventListener("url-changed", this._onUrlChange.bind(this));
|
|
53
53
|
});
|
|
@@ -85,7 +85,7 @@ export default class ShareMenu extends LitElement {
|
|
|
85
85
|
>
|
|
86
86
|
${fa(faCircleInfo)} ${this._parent?._t.pnx.share_embed_docs}
|
|
87
87
|
</pnx-link-button>
|
|
88
|
-
<textarea readonly
|
|
88
|
+
<textarea readonly .value=${iframe}></textarea>
|
|
89
89
|
<pnx-copy-button
|
|
90
90
|
._t=${this._parent?._t}
|
|
91
91
|
text=${iframe}
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export {default as AnnotationsList} from "./AnnotationsList";
|
|
7
|
+
export {default as MapBackground} from "./MapBackground";
|
|
7
8
|
export {default as MapFilters} from "./MapFilters";
|
|
8
9
|
export {default as MapLayers} from "./MapLayers";
|
|
9
|
-
export {default as
|
|
10
|
+
export {default as MapLegend} from "./MapLegend";
|
|
11
|
+
export {default as MiniPictureLegend} from "./MiniPictureLegend";
|
|
12
|
+
export {default as PictureLegend} from "./PictureLegend";
|
|
13
|
+
export {default as PictureMetadata} from "./PictureMetadata";
|
|
10
14
|
export {default as PlayerOptions} from "./PlayerOptions";
|
|
11
15
|
export {default as QualityScoreDoc} from "./QualityScoreDoc";
|
|
12
16
|
export {default as ReportForm} from "./ReportForm";
|
|
13
17
|
export {default as Share} from "./Share";
|
|
14
|
-
export {default as PictureLegend} from "./PictureLegend";
|
|
15
|
-
export {default as MapLegend} from "./MapLegend";
|
|
16
|
-
export {default as PictureMetadata} from "./PictureMetadata";
|
package/src/components/styles.js
CHANGED
|
@@ -212,6 +212,17 @@ export const btn = css`
|
|
|
212
212
|
background-color: var(--widget-bg-primary-hover);
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
/* Fully-filled warning style */
|
|
216
|
+
.pnx-btn-fullwarn {
|
|
217
|
+
background-color: var(--widget-bg-warn);
|
|
218
|
+
color: var(--widget-font-warn);
|
|
219
|
+
border: none;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.pnx-btn-fullwarn:not(:disabled):hover {
|
|
223
|
+
background-color: var(--widget-bg-warn);
|
|
224
|
+
}
|
|
225
|
+
|
|
215
226
|
/* Outline style */
|
|
216
227
|
.pnx-btn-outline {
|
|
217
228
|
border: 1px solid var(--widget-border-btn);
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { LitElement, html, css, nothing } from "lit";
|
|
2
|
+
import { fa } from "../../utils/widgets";
|
|
3
|
+
import { faTags } from "@fortawesome/free-solid-svg-icons/faTags";
|
|
4
|
+
import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons/faTriangleExclamation";
|
|
5
|
+
import { hasAnnotations } from "../../utils/picture";
|
|
6
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
7
|
+
import { panel } from "../styles";
|
|
8
|
+
|
|
9
|
+
const DISABLE_ANNOTATIONS_PARAM = "pnx-disable-annotations";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* AnnotationsSwitch component allows to switch on/off pictures annotations.
|
|
13
|
+
* @class Panoramax.components.ui.AnnotationsSwitch
|
|
14
|
+
* @element pnx-annotations-switch
|
|
15
|
+
* @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
|
|
16
|
+
* @example
|
|
17
|
+
* ```html
|
|
18
|
+
* <pnx-annotations-switch ._parent=${viewer} />
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export default class AnnotationsSwitch extends LitElement {
|
|
22
|
+
/** @private */
|
|
23
|
+
static styles = [ panel, css`
|
|
24
|
+
.pnx-panel {
|
|
25
|
+
padding: 5px;
|
|
26
|
+
margin-top: 5px;
|
|
27
|
+
width: max-content;
|
|
28
|
+
min-width: unset;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Custom button look */
|
|
32
|
+
pnx-button::part(btn) {
|
|
33
|
+
border-radius: 8px;
|
|
34
|
+
height: 26px;
|
|
35
|
+
width: 26px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pnx-button[size="xl"]::part(btn) {
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
height: 38px;
|
|
41
|
+
width: 38px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pnx-button[active]::part(btn),
|
|
45
|
+
pnx-button[active]:hover::part(btn) {
|
|
46
|
+
background-color: var(--widget-bg-active) !important;
|
|
47
|
+
border-color: var(--widget-bg-active) !important;
|
|
48
|
+
color: var(--widget-font-active) !important;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* No-annotations badge */
|
|
52
|
+
.pnx-annotations-switch-empty {
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 1px;
|
|
55
|
+
right: 1px;
|
|
56
|
+
color: var(--orange);
|
|
57
|
+
height: 8px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pnx-button[size="xl"] .pnx-annotations-switch-empty {
|
|
61
|
+
top: 2px;
|
|
62
|
+
right: 2px;
|
|
63
|
+
height: 12px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pnx-button[active] .pnx-annotations-switch-empty {
|
|
67
|
+
color: var(--yellow);
|
|
68
|
+
}
|
|
69
|
+
`];
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Component properties.
|
|
73
|
+
* @memberof Panoramax.components.ui.AnnotationsSwitch#
|
|
74
|
+
* @type {Object}
|
|
75
|
+
* @property {string} [size=xl] Button size (md, xl)
|
|
76
|
+
*/
|
|
77
|
+
/** @private */
|
|
78
|
+
static properties = {
|
|
79
|
+
size: {type: String},
|
|
80
|
+
_annotationsToggled: {state: true},
|
|
81
|
+
_warnNoAnnot: {state: true},
|
|
82
|
+
_warnNoAnnotTooltip: {state: true},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
constructor() {
|
|
86
|
+
super();
|
|
87
|
+
this._annotationsToggled = false;
|
|
88
|
+
this._warnNoAnnot = false;
|
|
89
|
+
this._warnNoAnnotTooltip = false;
|
|
90
|
+
this.size = "xl";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** @private */
|
|
94
|
+
connectedCallback() {
|
|
95
|
+
super.connectedCallback();
|
|
96
|
+
|
|
97
|
+
// Check if annotations have been explicitly disabled
|
|
98
|
+
const annotsDisabled = localStorage.getItem(DISABLE_ANNOTATIONS_PARAM) === "true";
|
|
99
|
+
|
|
100
|
+
this._parent.onceReady().then(() => {
|
|
101
|
+
this._parent.psv.addEventListener("annotations-toggled", e => {
|
|
102
|
+
this._annotationsToggled = e.detail.visible;
|
|
103
|
+
this._persistAnnotationsLocalStorage(this._annotationsToggled);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
this._warnNoAnnot = !hasAnnotations(this._parent.psv.getPictureMetadata());
|
|
107
|
+
this._parent.psv.addEventListener("picture-loaded", () => {
|
|
108
|
+
this._warnNoAnnot = !hasAnnotations(this._parent.psv.getPictureMetadata());
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
this._parent.onceFirstPicLoaded().then(() => {
|
|
113
|
+
this._annotationsToggled = this._parent.psv.areAnnotationsVisible() || false;
|
|
114
|
+
|
|
115
|
+
if(!this._annotationsToggled && !annotsDisabled) {
|
|
116
|
+
this._parent.psv.toggleAllAnnotations(true);
|
|
117
|
+
this._annotationsToggled = true;
|
|
118
|
+
}
|
|
119
|
+
this._persistAnnotationsLocalStorage(this._annotationsToggled);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** @private */
|
|
124
|
+
_persistAnnotationsLocalStorage(isAnnotToggled) {
|
|
125
|
+
localStorage.setItem(DISABLE_ANNOTATIONS_PARAM, isAnnotToggled ? "false": "true");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** @private */
|
|
129
|
+
_onClick() {
|
|
130
|
+
if(!this._annotationsToggled && this._warnNoAnnot) {
|
|
131
|
+
this._warnNoAnnotTooltip = true;
|
|
132
|
+
setTimeout(() => this._warnNoAnnotTooltip = false, 2000);
|
|
133
|
+
}
|
|
134
|
+
this._persistAnnotationsLocalStorage(!this._annotationsToggled);
|
|
135
|
+
this._parent.psv.toggleAllAnnotations(!this._annotationsToggled);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** @private */
|
|
139
|
+
render() {
|
|
140
|
+
/* eslint-disable indent */
|
|
141
|
+
const panelClasses = {
|
|
142
|
+
"pnx-panel": true,
|
|
143
|
+
"pnx-hidden": !this._warnNoAnnotTooltip,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return html`
|
|
147
|
+
<pnx-button
|
|
148
|
+
kind="superflat"
|
|
149
|
+
size=${this.size}
|
|
150
|
+
style="vertical-align: middle"
|
|
151
|
+
class="pnx-print-hidden"
|
|
152
|
+
title=${this._annotationsToggled ? this._parent._t?.pnx.semantics_hide_annotations : this._parent._t?.pnx.semantics_show_annotations}
|
|
153
|
+
active=${this._annotationsToggled ? "" : nothing}
|
|
154
|
+
@click=${this._onClick}
|
|
155
|
+
>
|
|
156
|
+
${fa(faTags, { styles: { "height": "20px" }})}
|
|
157
|
+
${this._warnNoAnnot ? fa(faTriangleExclamation, { classes: "pnx-annotations-switch-empty" }) : nothing}
|
|
158
|
+
</pnx-button>
|
|
159
|
+
<div
|
|
160
|
+
class=${classMap(panelClasses)}
|
|
161
|
+
@click=${() => this._warnNoAnnotTooltip = false}
|
|
162
|
+
>
|
|
163
|
+
${this._parent._t?.pnx.semantics_zero_annotations}
|
|
164
|
+
</div>
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
customElements.define("pnx-annotations-switch", AnnotationsSwitch);
|
|
@@ -23,7 +23,7 @@ export default class Button extends LitElement {
|
|
|
23
23
|
* @memberof Panoramax.components.ui.Button#
|
|
24
24
|
* @type {Object}
|
|
25
25
|
* @property {boolean} [active=false] Whether the button is in an active state.
|
|
26
|
-
* @property {string} [kind=full] The style variation of the button (full, outline, flat, superflat, inline, superinline)
|
|
26
|
+
* @property {string} [kind=full] The style variation of the button (full, fullwarn, outline, flat, superflat, inline, superinline)
|
|
27
27
|
* @property {string} [size=md] The size of the button (sm, md, l, xl, xxl)
|
|
28
28
|
* @property {boolean} [disabled=false] Whether the button is disabled.
|
|
29
29
|
* @property {string} [type] The button type (e.g., 'submit').
|
|
@@ -38,7 +38,7 @@ export default class CopyButton extends LitElement {
|
|
|
38
38
|
* @type {Object}
|
|
39
39
|
* @property {string} [text] Text to copy in clipboard on click (use either this parameter or input, not both)
|
|
40
40
|
* @property {input} [input] ID of a HTML input field to copy content from in clipboard (use either this parameter or text, not both)
|
|
41
|
-
* @property {string} [kind=full] The style variation of the button (full, outline, flat, superflat, inline, superinline)
|
|
41
|
+
* @property {string} [kind=full] The style variation of the button (full, fullwarn, outline, flat, superflat, inline, superinline)
|
|
42
42
|
* @property {string} [size=md] The size of the button (sm, md, l, xl, xxl)
|
|
43
43
|
* @property {boolean} [unstyled=false] Disable all styling (for list group integration)
|
|
44
44
|
* @property {string} [title] Tooltip text displayed when hovering over the button
|
|
@@ -31,7 +31,7 @@ export default class LinkButton extends LitElement {
|
|
|
31
31
|
* @property {string} [title] Tooltip text displayed when hovering over the button
|
|
32
32
|
* @property {string} [download] Indicates if the linked resource should be downloaded
|
|
33
33
|
* @property {string} [class] Custom CSS class for additional styling
|
|
34
|
-
* @property {string} [kind=full] The style variation of the button (full, outline, flat, superflat)
|
|
34
|
+
* @property {string} [kind=full] The style variation of the button (full, fullwarn, outline, flat, superflat)
|
|
35
35
|
* @property {string} [size=md] The size of the button (sm, md, l, xl, xxl)
|
|
36
36
|
*/
|
|
37
37
|
static properties = {
|
package/src/components/ui/Map.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./Map.css";
|
|
2
2
|
import {
|
|
3
3
|
VECTOR_STYLES, TILES_PICTURES_ZOOM, getThumbGif, RASTER_LAYER_ID, combineStyles,
|
|
4
|
-
getMissingLayerStyles, isLabelLayer, getUserLayerId, getUserSourceId,
|
|
4
|
+
getMissingLayerStyles, isLabelLayer, getUserLayerId, getUserSourceId, isNullCoordinates,
|
|
5
5
|
} from "../../utils/map";
|
|
6
6
|
import { COLORS } from "../../utils/utils";
|
|
7
7
|
import MarkerBaseSVG from "../../img/marker.svg";
|
|
@@ -37,6 +37,7 @@ maplibregl.addProtocol("pmtiles", new pmtiles.Protocol().tile);
|
|
|
37
37
|
* @param {object} [options.raster] The MapLibre raster source for aerial background. This must be a JSON object following [MapLibre raster source definition](https://maplibre.org/maplibre-style-spec/sources/#raster).
|
|
38
38
|
* @param {string} [options.background=streets] Choose default map background to display (streets or aerial, if raster aerial background available). Defaults to street.
|
|
39
39
|
* @param {string} [options.attributionControl.customAttribution] To override default map attribution.
|
|
40
|
+
* @param {boolean} [options.picMarkerDraggable] To make the picture marker draggable, default to false.
|
|
40
41
|
* @fires Panoramax.components.ui.Map#background-changed
|
|
41
42
|
* @fires Panoramax.components.ui.Map#users-changed
|
|
42
43
|
* @fires Panoramax.components.ui.Map#sequence-hover
|
|
@@ -205,7 +206,7 @@ export default class Map extends maplibregl.Map {
|
|
|
205
206
|
*/
|
|
206
207
|
_initMapPosition() {
|
|
207
208
|
if(
|
|
208
|
-
(
|
|
209
|
+
isNullCoordinates(this._options.center)
|
|
209
210
|
&& (!this._options.zoom || this._options.zoom === 0)
|
|
210
211
|
&& (!this._options.hash)
|
|
211
212
|
) {
|
|
@@ -379,6 +380,9 @@ export default class Map extends maplibregl.Map {
|
|
|
379
380
|
});
|
|
380
381
|
});
|
|
381
382
|
|
|
383
|
+
// Force style reload
|
|
384
|
+
this.reloadLayersStyles();
|
|
385
|
+
|
|
382
386
|
/**
|
|
383
387
|
* Event for visible users changes
|
|
384
388
|
*
|
|
@@ -413,13 +417,16 @@ export default class Map extends maplibregl.Map {
|
|
|
413
417
|
|
|
414
418
|
/**
|
|
415
419
|
* Shows on map a picture position and heading.
|
|
420
|
+
*
|
|
421
|
+
* If no longitude & latitude are set, marker is removed from map.
|
|
416
422
|
* @memberof Panoramax.components.ui.Map#
|
|
417
423
|
* @param {number} lon The longitude
|
|
418
424
|
* @param {number} lat The latitude
|
|
419
425
|
* @param {number} heading The heading
|
|
420
426
|
* @param {boolean} [skipCenter=false] Set to true to avoid map centering on marker
|
|
427
|
+
* @param {string} [picId=null] The picture Id
|
|
421
428
|
*/
|
|
422
|
-
displayPictureMarker(lon, lat, heading, skipCenter = false) {
|
|
429
|
+
displayPictureMarker(lon, lat, heading, skipCenter = false, picId = null) {
|
|
423
430
|
this._picMarkerPreview.remove();
|
|
424
431
|
|
|
425
432
|
// Show marker corresponding to selection
|
|
@@ -428,6 +435,7 @@ export default class Map extends maplibregl.Map {
|
|
|
428
435
|
.setLngLat([lon, lat])
|
|
429
436
|
.setRotation(heading)
|
|
430
437
|
.addTo(this);
|
|
438
|
+
this._picMarker.picId = picId ;
|
|
431
439
|
}
|
|
432
440
|
else {
|
|
433
441
|
this._picMarker.remove();
|
|
@@ -877,8 +885,12 @@ export default class Map extends maplibregl.Map {
|
|
|
877
885
|
img.src = selected ? MarkerSelectedSVG : MarkerBaseSVG;
|
|
878
886
|
img.alt = "";
|
|
879
887
|
return new maplibregl.Marker({
|
|
880
|
-
element: img
|
|
881
|
-
|
|
888
|
+
element: img,
|
|
889
|
+
picId: null
|
|
890
|
+
})
|
|
891
|
+
// only picMarker could be draggable, don't for picMarkerPreview.
|
|
892
|
+
.setDraggable(selected && this._options.picMarkerDraggable)
|
|
893
|
+
;
|
|
882
894
|
}
|
|
883
895
|
|
|
884
896
|
/**
|
|
@@ -198,32 +198,21 @@ export default class MapMore extends Map {
|
|
|
198
198
|
return s;
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
/**
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
* @param {string} [filters.minDate] Start date for pictures (format YYYY-MM-DD)
|
|
205
|
-
* @param {string} [filters.maxDate] End date for pictures (format YYYY-MM-DD)
|
|
206
|
-
* @param {string} [filters.pic_type] Type of picture to keep (flat, equirectangular)
|
|
207
|
-
* @param {string} [filters.camera] Camera make and model to keep
|
|
208
|
-
* @param {string} [filters.theme] Map theme to use
|
|
209
|
-
* @param {number[]} [filters.qualityscore] QualityScore values, as a list of 1 to 5 grades
|
|
210
|
-
* @param {boolean} [skipZoomIn=false] If true, doesn't force zoom in to map level >= 7
|
|
211
|
-
* @memberof Panoramax.components.core.MapMore#
|
|
212
|
-
*/
|
|
213
|
-
setFilters(filters, skipZoomIn = false) {
|
|
201
|
+
/** @private */
|
|
202
|
+
_mapFiltersToLayersFilters(filters) {
|
|
203
|
+
let mapFilters = {};
|
|
214
204
|
let mapSeqFilters = [];
|
|
215
205
|
let mapPicFilters = [];
|
|
216
206
|
let reloadMapStyle = false;
|
|
217
|
-
this._mapFilters = {};
|
|
218
207
|
|
|
219
208
|
if(filters.minDate && filters.minDate !== "") {
|
|
220
|
-
|
|
209
|
+
mapFilters.minDate = filters.minDate;
|
|
221
210
|
mapSeqFilters.push([">=", ["get", "date"], filters.minDate]);
|
|
222
211
|
mapPicFilters.push([">=", ["get", "ts"], filters.minDate]);
|
|
223
212
|
}
|
|
224
213
|
|
|
225
214
|
if(filters.maxDate && filters.maxDate !== "") {
|
|
226
|
-
|
|
215
|
+
mapFilters.maxDate = filters.maxDate;
|
|
227
216
|
mapSeqFilters.push(["<=", ["get", "date"], filters.maxDate]);
|
|
228
217
|
|
|
229
218
|
// Get tomorrow date for pictures filtering
|
|
@@ -235,16 +224,16 @@ export default class MapMore extends Map {
|
|
|
235
224
|
}
|
|
236
225
|
|
|
237
226
|
if(filters.pic_type && filters.pic_type !== "") {
|
|
238
|
-
|
|
239
|
-
mapSeqFilters.push(["==", ["get", "type"],
|
|
240
|
-
mapPicFilters.push(["==", ["get", "type"],
|
|
227
|
+
mapFilters.pic_type = filters.pic_type === "flat" ? "flat" : "equirectangular";
|
|
228
|
+
mapSeqFilters.push(["==", ["get", "type"], mapFilters.pic_type]);
|
|
229
|
+
mapPicFilters.push(["==", ["get", "type"], mapFilters.pic_type]);
|
|
241
230
|
}
|
|
242
231
|
if(this._hasGridStats()) {
|
|
243
232
|
reloadMapStyle = true;
|
|
244
233
|
}
|
|
245
234
|
|
|
246
235
|
if(filters.camera && filters.camera !== "") {
|
|
247
|
-
|
|
236
|
+
mapFilters.camera = filters.camera;
|
|
248
237
|
// low/high model hack : to enable fuzzy filtering of camera make and model
|
|
249
238
|
const lowModel = filters.camera.toLowerCase().trim() + " ";
|
|
250
239
|
const highModel = filters.camera.toLowerCase().trim() + "zzzzzzzzzzzzzzzzzzzz";
|
|
@@ -256,13 +245,13 @@ export default class MapMore extends Map {
|
|
|
256
245
|
}
|
|
257
246
|
|
|
258
247
|
if(filters.qualityscore && filters.qualityscore.length > 0) {
|
|
259
|
-
|
|
260
|
-
mapSeqFilters.push(["in", MAP_EXPR_QUALITYSCORE, ["literal",
|
|
261
|
-
mapPicFilters.push(["in", MAP_EXPR_QUALITYSCORE, ["literal",
|
|
248
|
+
mapFilters.qualityscore = filters.qualityscore;
|
|
249
|
+
mapSeqFilters.push(["in", MAP_EXPR_QUALITYSCORE, ["literal", mapFilters.qualityscore]]);
|
|
250
|
+
mapPicFilters.push(["in", MAP_EXPR_QUALITYSCORE, ["literal", mapFilters.qualityscore]]);
|
|
262
251
|
}
|
|
263
252
|
|
|
264
253
|
if(filters.theme && Object.values(MAP_THEMES).includes(filters.theme)) {
|
|
265
|
-
|
|
254
|
+
mapFilters.theme = filters.theme;
|
|
266
255
|
reloadMapStyle = true;
|
|
267
256
|
}
|
|
268
257
|
|
|
@@ -280,6 +269,25 @@ export default class MapMore extends Map {
|
|
|
280
269
|
];
|
|
281
270
|
}
|
|
282
271
|
|
|
272
|
+
return { mapFilters, mapSeqFilters, mapPicFilters, reloadMapStyle };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Change the map filters
|
|
277
|
+
* @param {object} filters Filtering values
|
|
278
|
+
* @param {string} [filters.minDate] Start date for pictures (format YYYY-MM-DD)
|
|
279
|
+
* @param {string} [filters.maxDate] End date for pictures (format YYYY-MM-DD)
|
|
280
|
+
* @param {string} [filters.pic_type] Type of picture to keep (flat, equirectangular)
|
|
281
|
+
* @param {string} [filters.camera] Camera make and model to keep
|
|
282
|
+
* @param {string} [filters.theme] Map theme to use
|
|
283
|
+
* @param {number[]} [filters.qualityscore] QualityScore values, as a list of 1 to 5 grades
|
|
284
|
+
* @param {boolean} [skipZoomIn=false] If true, doesn't force zoom in to map level >= 7
|
|
285
|
+
* @memberof Panoramax.components.core.MapMore#
|
|
286
|
+
*/
|
|
287
|
+
setFilters(filters, skipZoomIn = false) {
|
|
288
|
+
let { mapFilters, mapSeqFilters, mapPicFilters, reloadMapStyle } = this._mapFiltersToLayersFilters(filters);
|
|
289
|
+
|
|
290
|
+
this._mapFilters = mapFilters;
|
|
283
291
|
if(reloadMapStyle) {
|
|
284
292
|
this.reloadLayersStyles();
|
|
285
293
|
}
|
|
@@ -291,9 +299,10 @@ export default class MapMore extends Map {
|
|
|
291
299
|
7, mapSeqFilters
|
|
292
300
|
];
|
|
293
301
|
}
|
|
294
|
-
|
|
302
|
+
|
|
295
303
|
this.filterUserLayersContent("sequences", mapSeqFilters);
|
|
296
304
|
this.filterUserLayersContent("pictures", mapPicFilters);
|
|
305
|
+
|
|
297
306
|
if(
|
|
298
307
|
!skipZoomIn
|
|
299
308
|
&& (
|
|
@@ -321,4 +330,31 @@ export default class MapMore extends Map {
|
|
|
321
330
|
*/
|
|
322
331
|
this.fire("filters-changed", Object.assign({}, this._mapFilters));
|
|
323
332
|
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Make given user layers visible on map, and hide all others (if any)
|
|
336
|
+
* @memberof Panoramax.components.ui.Map#
|
|
337
|
+
* @param {string|string[]} visibleIds The user layers IDs to display
|
|
338
|
+
*/
|
|
339
|
+
async setVisibleUsers(visibleIds = []) {
|
|
340
|
+
await super.setVisibleUsers(visibleIds);
|
|
341
|
+
|
|
342
|
+
// Force reload of styles & filters
|
|
343
|
+
let { mapSeqFilters, mapPicFilters, reloadMapStyle } = this._mapFiltersToLayersFilters(this._mapFilters);
|
|
344
|
+
|
|
345
|
+
if(reloadMapStyle) {
|
|
346
|
+
this.reloadLayersStyles();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const allUsers = visibleIds.includes("geovisio");
|
|
350
|
+
if(mapSeqFilters && allUsers) {
|
|
351
|
+
mapSeqFilters = ["step", ["zoom"],
|
|
352
|
+
true,
|
|
353
|
+
7, mapSeqFilters
|
|
354
|
+
];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
this.filterUserLayersContent("sequences", mapSeqFilters);
|
|
358
|
+
this.filterUserLayersContent("pictures", mapPicFilters);
|
|
359
|
+
}
|
|
324
360
|
}
|
|
@@ -35,7 +35,16 @@
|
|
|
35
35
|
height: auto;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
.pnx-psv-tour-arrows svg:hover {
|
|
39
|
+
filter: drop-shadow(0 0 15px var(--blue));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.pnx-psv-playing .pnx-psv-tour-arrows {
|
|
43
|
+
display: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* No virtual tour arrows or annotations if photo is reduced */
|
|
47
|
+
pnx-mini .psv-virtual-tour-arrows,
|
|
48
|
+
pnx-mini .pnx-psv-annotation {
|
|
40
49
|
display: none;
|
|
41
50
|
}
|