@panoramax/web-viewer 5.0.0-develop-d26305dd → 5.0.0-develop-be5ba1a7

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.
Files changed (153) hide show
  1. package/build/cjs/index.js +1 -1
  2. package/build/cjs/index_photoviewer.js +1 -1
  3. package/build/esm/components/core/Basic.js +1 -1
  4. package/build/esm/translations/el.json +92 -1
  5. package/package.json +1 -1
  6. package/build/bundle.cjs +0 -3399
  7. package/build/bundle.cjs.map +0 -1
  8. package/build/bundle_photoviewer.cjs +0 -2510
  9. package/build/bundle_photoviewer.cjs.map +0 -1
  10. package/build/components/core/Basic.css +0 -56
  11. package/build/components/core/Basic.js +0 -378
  12. package/build/components/core/CoverageMap.css +0 -10
  13. package/build/components/core/CoverageMap.js +0 -169
  14. package/build/components/core/Editor.css +0 -33
  15. package/build/components/core/Editor.js +0 -398
  16. package/build/components/core/PhotoViewer.css +0 -70
  17. package/build/components/core/PhotoViewer.js +0 -650
  18. package/build/components/core/Viewer.css +0 -130
  19. package/build/components/core/Viewer.js +0 -711
  20. package/build/components/core/index.js +0 -10
  21. package/build/components/index.js +0 -11
  22. package/build/components/index_photoviewer.js +0 -6
  23. package/build/components/layout/BottomDrawer.js +0 -258
  24. package/build/components/layout/CorneredGrid.js +0 -143
  25. package/build/components/layout/Mini.js +0 -121
  26. package/build/components/layout/Tabs.js +0 -140
  27. package/build/components/layout/index.js +0 -9
  28. package/build/components/menus/LocationPrecisionDoc.js +0 -42
  29. package/build/components/menus/MapBackground.js +0 -110
  30. package/build/components/menus/MapFilters.js +0 -567
  31. package/build/components/menus/MapLayers.js +0 -238
  32. package/build/components/menus/MapLegend.js +0 -68
  33. package/build/components/menus/MiniPictureLegend.js +0 -73
  34. package/build/components/menus/PictureLegend.js +0 -379
  35. package/build/components/menus/PictureMetadata.js +0 -380
  36. package/build/components/menus/PlayerOptions.js +0 -93
  37. package/build/components/menus/QualityScoreDoc.js +0 -42
  38. package/build/components/menus/ReportForm.js +0 -132
  39. package/build/components/menus/SemanticsDoc.js +0 -38
  40. package/build/components/menus/SemanticsDownload.js +0 -33
  41. package/build/components/menus/SemanticsFilters.js +0 -153
  42. package/build/components/menus/SemanticsList.js +0 -413
  43. package/build/components/menus/SemanticsMetadata.js +0 -368
  44. package/build/components/menus/Share.js +0 -105
  45. package/build/components/menus/index.js +0 -22
  46. package/build/components/menus/index_photoviewer.js +0 -11
  47. package/build/components/styles.js +0 -557
  48. package/build/components/ui/AnnotationsSwitch.js +0 -159
  49. package/build/components/ui/Button.js +0 -77
  50. package/build/components/ui/ButtonGroup.css +0 -59
  51. package/build/components/ui/ButtonGroup.js +0 -69
  52. package/build/components/ui/CopyButton.js +0 -110
  53. package/build/components/ui/Grade.js +0 -54
  54. package/build/components/ui/GradeFilter.js +0 -122
  55. package/build/components/ui/IconSwitch.js +0 -193
  56. package/build/components/ui/LinkButton.js +0 -67
  57. package/build/components/ui/ListGroup.js +0 -66
  58. package/build/components/ui/ListItem.js +0 -90
  59. package/build/components/ui/Loader.js +0 -203
  60. package/build/components/ui/Map.css +0 -63
  61. package/build/components/ui/Map.js +0 -853
  62. package/build/components/ui/MapMore.js +0 -175
  63. package/build/components/ui/Photo.css +0 -50
  64. package/build/components/ui/Photo.js +0 -1502
  65. package/build/components/ui/Popup.js +0 -145
  66. package/build/components/ui/ProgressBar.js +0 -104
  67. package/build/components/ui/QualityScore.js +0 -147
  68. package/build/components/ui/SearchBar.js +0 -374
  69. package/build/components/ui/SemanticsEditor.js +0 -191
  70. package/build/components/ui/SemanticsTable.js +0 -88
  71. package/build/components/ui/Switch.js +0 -139
  72. package/build/components/ui/TogglableGroup.js +0 -157
  73. package/build/components/ui/index.js +0 -29
  74. package/build/components/ui/index_photoviewer.js +0 -21
  75. package/build/components/ui/widgets/CopyCoordinates.js +0 -75
  76. package/build/components/ui/widgets/GeoSearch.css +0 -21
  77. package/build/components/ui/widgets/GeoSearch.js +0 -150
  78. package/build/components/ui/widgets/Legend.js +0 -190
  79. package/build/components/ui/widgets/LevelSelect.css +0 -51
  80. package/build/components/ui/widgets/LevelSelect.js +0 -143
  81. package/build/components/ui/widgets/MapFiltersButton.js +0 -114
  82. package/build/components/ui/widgets/MapLayersButton.js +0 -79
  83. package/build/components/ui/widgets/OSMEditors.js +0 -155
  84. package/build/components/ui/widgets/PictureLegendActions.js +0 -99
  85. package/build/components/ui/widgets/Player.css +0 -7
  86. package/build/components/ui/widgets/Player.js +0 -154
  87. package/build/components/ui/widgets/SemanticsFiltersButton.js +0 -65
  88. package/build/components/ui/widgets/Zoom.js +0 -84
  89. package/build/components/ui/widgets/index.js +0 -16
  90. package/build/components/ui/widgets/index_photoviewer.js +0 -7
  91. package/build/img/arrow_360.svg +0 -14
  92. package/build/img/arrow_flat.svg +0 -11
  93. package/build/img/arrow_triangle.svg +0 -9
  94. package/build/img/arrow_turn.svg +0 -8
  95. package/build/img/bg_aerial.jpg +0 -0
  96. package/build/img/bg_streets.jpg +0 -0
  97. package/build/img/loader_base.jpg +0 -0
  98. package/build/img/logo_dead.svg +0 -91
  99. package/build/img/marker.svg +0 -17
  100. package/build/img/marker_blue.svg +0 -20
  101. package/build/img/osm.svg +0 -49
  102. package/build/img/panoramax.svg +0 -13
  103. package/build/img/switch_big.svg +0 -54
  104. package/build/img/switch_mini.svg +0 -48
  105. package/build/img/wd.svg +0 -1
  106. package/build/index_photoviewer.js +0 -4
  107. package/build/package.json +0 -148
  108. package/build/servers.js +0 -14
  109. package/build/translations/ar.json +0 -1
  110. package/build/translations/be.json +0 -257
  111. package/build/translations/br.json +0 -81
  112. package/build/translations/cy.json +0 -117
  113. package/build/translations/da.json +0 -300
  114. package/build/translations/de.json +0 -309
  115. package/build/translations/en.json +0 -294
  116. package/build/translations/eo.json +0 -235
  117. package/build/translations/es.json +0 -292
  118. package/build/translations/fi.json +0 -1
  119. package/build/translations/fr.json +0 -294
  120. package/build/translations/hr.json +0 -294
  121. package/build/translations/hu.json +0 -294
  122. package/build/translations/it.json +0 -306
  123. package/build/translations/ja.json +0 -182
  124. package/build/translations/ko.json +0 -1
  125. package/build/translations/nl.json +0 -305
  126. package/build/translations/nn.json +0 -1
  127. package/build/translations/pl.json +0 -169
  128. package/build/translations/pt.json +0 -296
  129. package/build/translations/pt_BR.json +0 -304
  130. package/build/translations/sv.json +0 -182
  131. package/build/translations/ti.json +0 -9
  132. package/build/translations/tr.json +0 -297
  133. package/build/translations/uk.json +0 -268
  134. package/build/translations/zh_Hant.json +0 -309
  135. package/build/utils/API.js +0 -928
  136. package/build/utils/InitParameters.js +0 -521
  137. package/build/utils/MapStyleComposer.js +0 -889
  138. package/build/utils/PanoraMapProtocol.js +0 -49
  139. package/build/utils/PhotoAdapter.js +0 -49
  140. package/build/utils/PresetsManager.js +0 -148
  141. package/build/utils/SemanticsMapProtocol.js +0 -144
  142. package/build/utils/URLHandler.js +0 -426
  143. package/build/utils/geocoder.js +0 -203
  144. package/build/utils/i18n.js +0 -128
  145. package/build/utils/index.js +0 -17
  146. package/build/utils/index_photoviewer.js +0 -14
  147. package/build/utils/indoor.js +0 -200
  148. package/build/utils/map.js +0 -788
  149. package/build/utils/picture.js +0 -507
  150. package/build/utils/semantics.js +0 -321
  151. package/build/utils/services.js +0 -148
  152. package/build/utils/utils.js +0 -433
  153. package/build/utils/widgets.js +0 -110
@@ -1,711 +0,0 @@
1
- import { getMapParamsFromLocalStorage, linkMapAndPhoto, saveMapParamsToLocalStorage, initMapKeyboardHandler } from "../../utils/map.js";
2
- import PhotoViewer, {KEYBOARD_SKIP_FOCUS_WIDGETS} from "./PhotoViewer.js";
3
- import MapMore from "../ui/MapMore.js";
4
- import { DISABLE_ANNOTATIONS_PARAM, isInIframe, isNullId } from "../../utils/utils.js";
5
- import { createWebComp, fa } from "../../utils/widgets.js";
6
- import { PanoramaxMetaCatalogURL, MapTiles } from "../../utils/services.js";
7
- import { faMap, faPanorama } from "@fortawesome/free-solid-svg-icons";
8
- import { default as InitParameters, alterMapState, alterViewerState } from "../../utils/InitParameters.js";
9
- import MapStyleComposer from "../../utils/MapStyleComposer.js";
10
- import API from "../../utils/API.js";
11
- import ViewerStyles from "./Viewer.css" with { type: "css" };
12
- document.adoptedStyleSheets.push(ViewerStyles);
13
-
14
-
15
- const MAP_MOVE_DELTA = 100;
16
-
17
-
18
- /**
19
- * Viewer is the main component of Panoramax JS library, showing pictures and map.
20
- *
21
- * This component has a [CorneredGrid](#Panoramax.components.layout.CorneredGrid) layout, you can use directly any slot element to pass custom widgets.
22
- *
23
- * If you need a viewer without map, checkout [Photo Viewer component](#Panoramax.components.core.PhotoViewer).
24
- *
25
- * Make sure to set width/height through CSS for proper display.
26
- * @class Panoramax.components.core.Viewer
27
- * @element pnx-viewer
28
- * @extends Panoramax.components.core.PhotoViewer
29
- * @property {Panoramax.components.ui.Loader} loader The loader screen
30
- * @property {Panoramax.utils.API} api The API manager (local instance)
31
- * @property {Panoramax.utils.API} apiMC The API manager for metacatalog
32
- * @property {Panoramax.components.ui.MapMore} map The MapLibre GL map itself
33
- * @property {Panoramax.utils.MapStyleComposer} mapStyleComposer The map style helper
34
- * @property {Panoramax.components.ui.Photo} psv The Photo Sphere Viewer component itself
35
- * @property {Panoramax.components.layout.CorneredGrid} grid The grid layout manager
36
- * @property {Panoramax.components.layout.Mini} mini The reduced/collapsed map/photo component
37
- * @property {Panoramax.components.ui.Popup} popup The popup container
38
- * @property {Panoramax.utils.URLHandler} urlHandler The URL query parameters manager
39
- * @property {Panoramax.utils.PresetsManager} presetsManager The semantics presets manager
40
- * @fires Panoramax.components.core.Basic#select
41
- * @fires Panoramax.components.core.Basic#ready
42
- * @fires Panoramax.components.core.Basic#broken
43
- * @fires Panoramax.components.core.Viewer#focus-changed
44
- * @slot `top-left` The top-left corner
45
- * @slot `top` The top middle corner
46
- * @slot `top-right` The top-right corner
47
- * @slot `bottom-left` The bottom-left corner
48
- * @slot `bottom` The bottom middle corner
49
- * @slot `bottom-right` The bottom-right corner
50
- * @slot `editors` External links to map editors, or any tool that may be helpful. Defaults to OSM tools (iD & JOSM).
51
- * @example
52
- * ```html
53
- * <!-- Basic example (embeds metacatalog) -->
54
- * <pnx-viewer
55
- * endpoint="https://panoramax.openstreetmap.fr/"
56
- * style="width: 300px; height: 250px"
57
- * />
58
- *
59
- * <!-- Basic example (without metacatalog) -->
60
- * <pnx-viewer
61
- * endpoint="https://panoramax.openstreetmap.fr/"
62
- * metacatalog="false"
63
- * style="width: 300px; height: 250px"
64
- * />
65
- *
66
- * <!-- With slotted widgets -->
67
- * <pnx-viewer
68
- * endpoint="https://panoramax.openstreetmap.fr/"
69
- * style="width: 300px; height: 250px"
70
- * >
71
- * <p slot="top-right">My custom text</p>
72
- * <p slot="editors"><a href="https://my.own.tool/">Edit in my own tool</a></p>
73
- * </pnx-viewer>
74
- *
75
- * <!-- With only your custom widgets -->
76
- * <pnx-viewer
77
- * endpoint="https://panoramax.openstreetmap.fr/"
78
- * style="width: 300px; height: 250px"
79
- * widgets="false"
80
- * >
81
- * <p slot="top-right">My custom text</p>
82
- * </pnx-viewer>
83
- *
84
- * <!-- With map options -->
85
- * <pnx-viewer
86
- * endpoint="https://panoramax.openstreetmap.fr/"
87
- * style="width: 300px; height: 250px"
88
- * map-options="{'maxZoom': 15, 'background': 'aerial', 'raster': '...'}"
89
- * />
90
- * ```
91
- */
92
- export default class Viewer extends PhotoViewer {
93
- /**
94
- * Component properties. All of [Basic properties](#Panoramax.components.core.Basic+properties) are available as well.
95
- * @memberof Panoramax.components.core.Viewer#
96
- * @mixes Panoramax.components.core.PhotoViewer#properties
97
- * @type {Object}
98
- * @property {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md))
99
- * @property {object} [map-options] An object with [any map option available in Map or MapMore class](#Panoramax.components.ui.MapMore).<br />Example: `map-options="{'background': 'aerial', 'theme': 'age'}"`
100
- * @property {object} [psv-options] [Any option to pass to Photo component](#Panoramax.components.ui.Photo) as an object.<br />Example: `psv-options="{'transitionDuration': 500, 'picturesNavigation': 'pic'}"`
101
- * @property {string} [url-parameters=true] Should the component add and update URL query parameters to save viewer state ?
102
- * @property {string} [keyboard-shortcuts=true] Should keyboard shortcuts be enabled ? Set to "false" to fully disable any keyboard shortcuts.
103
- * @property {string} [focus=pic] The component showing up as main component (pic, map)
104
- * @property {string} [geocoder=nominatim] The geocoder engine to use (nominatim, ban, or URL to a standard [GeocodeJSON-compliant](https://github.com/geocoders/geocodejson-spec/blob/master/draft/README.md) API)
105
- * @property {string} [widgets=true] Use default set of widgets ? Set to false to avoid any widget to show up, and use slots to populate as you like.
106
- * @property {string} [picture] The picture ID to display
107
- * @property {string} [sequence] The sequence ID of the picture displayed
108
- * @property {object} [fetch-options] Set custom options for fetch calls made against API ([same syntax as fetch options parameter](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters))
109
- * @property {string|object} [map-style] The map's MapLibre style. This can be an a JSON object conforming to the schema described in the [MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/), or a URL string pointing to one. Defaults to OSM vector tiles.
110
- * @property {string} [lang] To override language used for labels. Defaults to using user's preferred languages.
111
- * @property {string} [skip-tags-menu-opening=false] Should the "Tags" menu automatically open when you toggle Annotations switch ? Set true to avoid auto-opening.
112
- * @property {string} [share-base-url] Override the default base URL (current page) for the Share widget. Useful to lead to a public page when viewer is used in a closed tool.
113
- * @property {string} [metacatalog] The URL to access Panoramax federated catalog. Defaults to "https://explore.panoramax.fr". Set to "false" to not display pictures from federated catalog on map.
114
- * @property {string} [endpoint-to-use] Selects the default Panoramax endpoint to use. Either "default" (specific endpoint), "metacatalog" (if defined), any user UUID (available on default endpoint), or user UUID prefixed with "metacatalog_" for a metacatalog user.
115
- */
116
- static properties = {
117
- "map-options": {converter: PhotoViewer.GetJSONConverter()},
118
- "map-style": {type: String},
119
- focus: {type: String, reflect: true},
120
- geocoder: {type: String},
121
- tabindex: {type: Number},
122
- metacatalog: {type: String},
123
- "endpoint-to-use": {type: String},
124
- ...PhotoViewer.properties
125
- };
126
-
127
- constructor() {
128
- super();
129
-
130
- // Defaults
131
- this["map-options"] = true;
132
- this["map-style"] = this.getAttribute("map-style") || MapTiles();
133
- this.geocoder = this.getAttribute("geocoder") || "nominatim";
134
-
135
- // Check if mapstyle is not a unparsed JSON
136
- try {
137
- this["map-style"] = JSON.parse(this["map-style"]);
138
- } catch(e) { /* Empty */ }
139
-
140
- // Init DOM containers
141
- this.mini = createWebComp("pnx-mini", {
142
- slot: "bottom-left",
143
- _parent: this,
144
- onexpand: this._onMiniExpand.bind(this),
145
- collapsed: isNullId(this.picture) ? true : undefined
146
- });
147
- this.mini.addEventListener("expand", this._toggleFocus.bind(this));
148
- this.grid.appendChild(this.mini);
149
- this.mapContainer = document.createElement("div");
150
- this.tabindex = 0;
151
- }
152
-
153
- /** @private */
154
- connectedCallback() {
155
- super.connectedCallback();
156
-
157
- this.metacatalog = this.getAttribute("metacatalog");
158
- if([null, undefined, ""].includes(this.metacatalog)) { this.metacatalog = PanoramaxMetaCatalogURL(); }
159
- this["endpoint-to-use"] = this.getAttribute("endpoint-to-use");
160
-
161
- // Setup map styles and sources
162
- this.mapStyleComposer = new MapStyleComposer(this);
163
- this.mapStyleComposer.addBasemap("streets", this["map-style"], true);
164
- }
165
-
166
- /** @private */
167
- _createInitParamsHandler() {
168
- this._initParams = new InitParameters(
169
- InitParameters.GetComponentProperties(Viewer, this),
170
- Object.assign({}, this.urlHandler?.currentURLParams(), this.urlHandler?.currentURLParams(true)),
171
- {
172
- map: getMapParamsFromLocalStorage(),
173
- disableAnnotations: localStorage.getItem(DISABLE_ANNOTATIONS_PARAM)
174
- },
175
- );
176
- }
177
-
178
- /** @private */
179
- _initWidgets() {
180
- if(this._initParams.getParentPostInit().widgets !== "false") {
181
- this.grid.appendChild(createWebComp("pnx-widget-zoom", {
182
- slot: this.isWidthSmall() ? "top-left" : "bottom-right",
183
- class: this.isWidthSmall() ? "pnx-only-map pnx-print-hidden" : "pnx-print-hidden",
184
- _parent: this
185
- }));
186
-
187
- if(isInIframe()) {
188
- this.legend = createWebComp("pnx-widget-legend", {
189
- slot: "bottom-right",
190
- light: true,
191
- _parent: this,
192
- focus: this._initParams.getParentPostInit().focus,
193
- picture: this._initParams.getParentPostInit().picture,
194
- });
195
- this.grid.appendChild(this.legend);
196
- }
197
- else if(!this.isWidthSmall()) {
198
- this.legend = createWebComp("pnx-widget-legend", {
199
- slot: this.isWidthSmall() ? "top" : "top-left",
200
- _parent: this,
201
- focus: this._initParams.getParentPostInit().focus,
202
- picture: this._initParams.getParentPostInit().picture,
203
- });
204
- this._miniPicLegend = createWebComp("pnx-mini-picture-legend", { _parent: this });
205
- this.grid.appendChild(this.legend);
206
- }
207
- else {
208
- this.legend = createWebComp("pnx-picture-legend", { _parent: this });
209
- this.bottomDrawer = createWebComp("pnx-bottom-drawer", {
210
- slot: "bottom",
211
- _parent: this,
212
- class: this._initParams.getParentPostInit().willLoadPicture ? undefined: "pnx-hidden",
213
- });
214
- this.bottomDrawer.appendChild(this.legend);
215
- this.grid.appendChild(this.bottomDrawer);
216
- this.addEventListener("select", e => {
217
- if(isNullId(e.detail.picId)) { this.bottomDrawer.classList.add("pnx-hidden"); }
218
- else { this.bottomDrawer.classList.remove("pnx-hidden"); }
219
- });
220
- }
221
-
222
- if(!isInIframe()) {
223
- this.grid.appendChild(createWebComp("pnx-widget-player", {
224
- slot: this.isWidthMedium() ? "top-right": "top",
225
- _parent: this,
226
- class: "pnx-only-psv pnx-print-hidden",
227
- size: this.isHeightSmall() || this.isWidthMedium() ? "md": "xl",
228
- }));
229
-
230
- this.grid.appendChild(createWebComp("pnx-annotations-switch", {
231
- slot: this.isWidthMedium() ? "top-right": "top",
232
- _parent: this,
233
- class: "pnx-only-psv pnx-print-hidden",
234
- size: this.isHeightSmall() || this.isWidthMedium() ? "md": "xl",
235
- }));
236
-
237
- this.grid.appendChild(createWebComp("pnx-widget-geosearch", {
238
- slot: this.isWidthSmall() ? "top-right" : "top-left",
239
- _parent: this,
240
- class: "pnx-only-map pnx-print-hidden",
241
- geocoder: this._initParams.getParentPostInit().geocoder,
242
- }));
243
-
244
- this.grid.appendChild(createWebComp("pnx-widget-mapfilters", {
245
- slot: this.isWidthSmall() ? "top-right" : "top-left",
246
- _parent: this,
247
- "user-search": this.api._endpoints.user_search !== null && this.api._endpoints.user_tiles !== null,
248
- "quality-score": this.map?._hasQualityScore?.() || false,
249
- "no-source": !this.hasTwoAPIs(),
250
- class: "pnx-only-map pnx-print-hidden",
251
- }));
252
-
253
- this.grid.appendChild(createWebComp("pnx-widget-semantics-filters", {
254
- slot: this.isWidthSmall() ? "top-right" : "top-left",
255
- _parent: this,
256
- class: "pnx-only-map pnx-print-hidden",
257
- }));
258
-
259
- this.grid.appendChild(createWebComp("pnx-widget-maplayers", { slot: "top-right", _parent: this, class: "pnx-only-map pnx-print-hidden" }));
260
- }
261
- }
262
- }
263
-
264
- /** @private */
265
- disconnectedCallback() {
266
- super.disconnectedCallback();
267
- this.map?.destroy();
268
- }
269
-
270
- // eslint-disable-next-line class-methods-use-this
271
- getClassName() {
272
- return "Viewer";
273
- }
274
-
275
- getSubComponentsNames() {
276
- return super.getSubComponentsNames().concat(["mini", "map", "mapStyleComposer"]);
277
- }
278
-
279
- /**
280
- * Waits for Viewer to be completely ready (map & PSV loaded, first picture also if one is wanted)
281
- * @returns {Promise} When viewer is ready
282
- * @memberof Panoramax.components.core.Viewer#
283
- */
284
- onceReady() {
285
- return Promise.all([this.oncePSVReady(), this.onceMapReady()])
286
- .then(() => {
287
- if(this._initParams.getParentPostInit().willLoadPicture && !this.psv.getPictureMetadata()) { return this.onceFirstPicLoaded(); }
288
- else { return Promise.resolve(); }
289
- });
290
- }
291
-
292
- /**
293
- * Waits for initial API setup.
294
- * @memberof Panoramax.components.core.Basic#
295
- * @returns {Promise}
296
- * @fulfil {null} When API is ready.
297
- * @reject {string} Error message
298
- */
299
- onceAPIReady() {
300
- if(this.api) {
301
- return this.api.onceReady();
302
- }
303
- else {
304
- return new Promise(resolve => setTimeout(resolve, 250)).then(this.onceAPIReady.bind(this));
305
- }
306
- }
307
-
308
- /**
309
- * Waits for all APIs setup.
310
- * This is useful for two-APIs setup.
311
- * @memberof Panoramax.components.core.Viewer#
312
- * @returns {Promise}
313
- * @fulfil {null} When two APIs are ready.
314
- * @reject {string} Error message
315
- */
316
- onceAllAPIsReady() {
317
- if(this.getAPI()) {
318
- return this.getAPI().onceReady();
319
- }
320
- else {
321
- return new Promise(resolve => setTimeout(resolve, 250)).then(this.onceAllAPIsReady.bind(this));
322
- }
323
- }
324
-
325
- /** @private */
326
- attributeChangedCallback(name, old, value) {
327
- super.attributeChangedCallback(name, old, value);
328
-
329
- if(name === "picture") {
330
- this.legend?.setAttribute?.("picture", value);
331
-
332
- // First pic load : show map in mini component
333
- if(isNullId(old) && !isNullId(value)) {
334
- this.mini.removeAttribute("collapsed");
335
- }
336
-
337
- // Unselect -> show map wide instead
338
- if(isNullId(value)) {
339
- if(this.map && this.isMapWide()) { this.mini.classList.add("pnx-hidden"); }
340
- else if(this.map && !this.isMapWide()) { this._setFocus("map"); }
341
- }
342
- // Check if it's not first load from seq=* URL parameter
343
- else if(
344
- isNullId(old)
345
- // eslint-disable-next-line eqeqeq
346
- && this.sequence == this._initParams.getParentPostInit().sequence
347
- && !this._initParams.getParentPostInit().picture
348
- ) {
349
- this.mini.classList.remove("pnx-hidden");
350
- this.mini.removeAttribute("collapsed");
351
- if(this.bottomDrawer?.getAttribute?.("openness") === "closed") {
352
- this.bottomDrawer.setAttribute("openness", "half-opened");
353
- }
354
- }
355
- // Select after none selected -> show pic wide
356
- else {
357
- this.mini.classList.remove("pnx-hidden");
358
- if(isNullId(old)) {
359
- this._setFocus("pic");
360
- if(this.bottomDrawer?.getAttribute?.("openness") === "closed") {
361
- this.bottomDrawer.setAttribute("openness", "half-opened");
362
- }
363
- }
364
- }
365
- }
366
-
367
- if(name === "focus") {
368
- this._setFocus(value);
369
- }
370
- }
371
-
372
- /**
373
- * Waiting for map to be available.
374
- * @returns {Promise} When map is ready to use
375
- * @memberof Panoramax.components.core.Viewer#
376
- */
377
- onceMapReady() {
378
- if(!this["map-options"]) { return Promise.resolve(); }
379
-
380
- let waiter;
381
- return new Promise(resolve => {
382
- waiter = setInterval(() => {
383
- if(typeof this.map === "object") {
384
- if(this.map?.loaded?.()) {
385
- clearInterval(waiter);
386
- resolve();
387
- }
388
- else if(this.map?.once) {
389
- this.map.once("render", () => {
390
- clearInterval(waiter);
391
- resolve();
392
- });
393
- }
394
- }
395
- }, 250);
396
- });
397
- }
398
-
399
- /**
400
- * Inits MapLibre GL component
401
- *
402
- * @private
403
- * @returns {Promise} Resolves when map is ready
404
- */
405
- async _initMap() {
406
- await new Promise(resolve => {
407
- const mapInitOpts = this._initParams.getMapInit();
408
- if(mapInitOpts.raster) { this.mapStyleComposer._createRasterBasemap(mapInitOpts.raster); }
409
- this.map = new MapMore(this, this.mapContainer, mapInitOpts);
410
- saveMapParamsToLocalStorage(this.map);
411
- this.map.waitForEnoughMapLoaded().then(() => {
412
- this.loader.setAttribute("value", Math.max(75, parseInt(this.loader.getAttribute("value"))));
413
- });
414
- resolve();
415
- });
416
-
417
- await alterMapState(this.map, this._initParams.getMapPostInit());
418
- initMapKeyboardHandler(this);
419
- linkMapAndPhoto(this);
420
- }
421
-
422
- /**
423
- * Is the viewer using both metacatalog and local API ?
424
- * @returns {boolean} True if using two APIs
425
- * @memberof Panoramax.components.core.Viewer#
426
- */
427
- hasTwoAPIs() {
428
- // eslint-disable-next-line eqeqeq
429
- return (this.apiMC != undefined && this.api != undefined) || this.metacatalog !== "false";
430
- }
431
-
432
- /**
433
- * Returns the API manager, from current Panoramax endpoint.
434
- * @returns {API} The API manager
435
- * @memberof Panoramax.components.core.Viewer#
436
- */
437
- getAPI() {
438
- let apiToUse = this.mapStyleComposer.panoramax || this._initParams.getParentPostInit().users || (this.hasTwoAPIs() ? "metacatalog" : "default");
439
- if(apiToUse === "metacatalog" && this.metacatalog === "false") { apiToUse = "default"; }
440
- return apiToUse?.startsWith("metacatalog") ? this.apiMC : this.api;
441
- }
442
-
443
- /** @private */
444
- async _postAPIInit() {
445
- this.loader.setAttribute("value", 30);
446
- this._createInitParamsHandler();
447
-
448
- const myPostInitParams = this._initParams.getParentPostInit();
449
-
450
- // Load Panoramax endpoints in map style
451
- const loadDefault = [null, undefined, "", "default"].includes(myPostInitParams.users);
452
- await this._lookForMetacatalog(!loadDefault);
453
- this.mapStyleComposer._createPanoramaxEndpointFromAPI("default", this.api, loadDefault);
454
-
455
- this._initPSV();
456
- await this._initMap();
457
- this._initWidgets();
458
-
459
- // Re-launch slot move (for those depending on widgets)
460
- this._moveChildToGrid();
461
-
462
- alterViewerState(this, myPostInitParams);
463
-
464
- if(myPostInitParams.keyboardShortcuts) {
465
- this._handleKeyboardManagement();
466
- }
467
-
468
- if(myPostInitParams.willLoadPicture) {
469
- this.psv.addEventListener("picture-loaded", () => {
470
- alterViewerState(this, myPostInitParams); // Do it again for forcing focus
471
- this.loader.dismiss();
472
- }, {once: true});
473
- }
474
- else {
475
- this.map.waitForEnoughMapLoaded().then(() => {
476
- this.loader.dismiss();
477
- });
478
- }
479
- }
480
-
481
- /** @private */
482
- async _lookForMetacatalog(switchOn) {
483
- if(this.hasTwoAPIs()) {
484
- this.apiMC = new API(this.metacatalog+"/api");
485
- await this.apiMC.onceReady();
486
- this.mapStyleComposer._createPanoramaxEndpointFromAPI("metacatalog", this.apiMC, switchOn);
487
- }
488
- }
489
-
490
- /** @private */
491
- _enableKeyboard() {
492
- if(this.map && this.isMapWide()) { this._enableKeyboardMap(); }
493
- else { this._enableKeyboardPSV(); }
494
- }
495
-
496
- /** @private */
497
- _enableKeyboardMap() {
498
- this.psv.stopKeyboardControl();
499
- this.map.keyboard.enable();
500
- }
501
-
502
- /** @private */
503
- _enableKeyboardPSV() {
504
- this.psv.startKeyboardControl();
505
- this.map.keyboard.disable();
506
- }
507
-
508
- /** @private */
509
- _disableKeyboard() {
510
- this.psv.stopKeyboardControl();
511
- this.map.keyboard.disable();
512
- }
513
-
514
- /** @private */
515
- _handleKeyboardManagement() {
516
- // General
517
- window.addEventListener("click", e => this._toggleKeyboardBasedOnFocus(e));
518
- window.addEventListener("keypress", this._toggleKeyboardBasedOnFocus.bind(this));
519
- this.addEventListener("focus-changed", e => {
520
- if(this.popup.getAttribute("visible")) { this._disableKeyboard(); }
521
- else if(e.detail.focus === "map") { this._enableKeyboardMap(); }
522
- else { this._enableKeyboardPSV(); }
523
- });
524
-
525
- // Popup
526
- this.popup.addEventListener("open", this._disableKeyboard.bind(this));
527
- this.popup.addEventListener("close", this._enableKeyboard.bind(this));
528
- this.psv.addEventListener("click", this._enableKeyboardPSV.bind(this));
529
-
530
- // Widgets
531
- for(let cn of this.grid.childNodes) {
532
- if(
533
- cn.getAttribute("slot") !== "bg"
534
- && !KEYBOARD_SKIP_FOCUS_WIDGETS.includes(cn.tagName.toLowerCase())
535
- ) {
536
- cn.addEventListener("focusin", this._disableKeyboard.bind(this));
537
- cn.addEventListener("focusout", () => {
538
- if(this.popup.getAttribute("visible") === null) {
539
- this._enableKeyboard();
540
- }
541
- });
542
- }
543
- }
544
- }
545
-
546
- /**
547
- * Move the view of main component to its center.
548
- * For map, center view on selected picture.
549
- * For picture, center view on image center.
550
- * @memberof Panoramax.components.core.Viewer#
551
- */
552
- moveCenter() {
553
- const meta = this.psv.getPictureMetadata();
554
- if(!meta) { return; }
555
-
556
- if(this.map && this.isMapWide()) {
557
- this.map.flyTo({ center: meta.gps, zoom: 20 });
558
- }
559
- else {
560
- super.moveCenter();
561
- }
562
- }
563
-
564
- /**
565
- * Moves map or picture viewer to given direction.
566
- * @param {string} dir Direction to move to (up, left, down, right)
567
- * @private
568
- */
569
- _moveToDirection(dir) {
570
- if(this.map && this.isMapWide()) {
571
- let pan;
572
- switch(dir) {
573
- case "up":
574
- pan = [0, -MAP_MOVE_DELTA];
575
- break;
576
- case "left":
577
- pan = [-MAP_MOVE_DELTA, 0];
578
- break;
579
- case "down":
580
- pan = [0, MAP_MOVE_DELTA];
581
- break;
582
- case "right":
583
- pan = [MAP_MOVE_DELTA, 0];
584
- break;
585
- }
586
- this.map.panBy(pan);
587
- }
588
- else {
589
- super._moveToDirection(dir);
590
- }
591
- }
592
-
593
- /**
594
- * Is the map shown as main element instead of viewer (wide map mode) ?
595
- * @memberof Panoramax.components.core.Viewer#
596
- * @returns {boolean} True if map is wider than viewer
597
- */
598
- isMapWide() {
599
- return this.mapContainer.parentNode === this.grid;
600
- }
601
-
602
- /**
603
- * Change the viewer focus (either on picture or map)
604
- * @memberof Panoramax.components.core.Viewer#
605
- * @param {string} focus The object to focus on (map, pic)
606
- * @param {boolean} [skipEvent=false] True to not send focus-changed event
607
- * @param {boolean} [skipDupCheck=false] True to avoid duplicate calls check
608
- * @private
609
- */
610
- _setFocus(focus, skipEvent = false, skipDupCheck = false) {
611
- if(focus === "map" && !this.map) { throw new Error("Map is not enabled"); }
612
- if(!["map", "pic"].includes(focus)) { throw new Error("Invalid focus value (should be pic or map)"); }
613
-
614
- this.focus = focus;
615
-
616
- if(!skipDupCheck && (
617
- (focus === "map" && this.map && this.isMapWide())
618
- || (focus === "pic" && (!this.map || !this.isMapWide()))
619
- )) { return; }
620
-
621
- if(focus === "map") {
622
- // Remove PSV from grid
623
- if(this.psvContainer.parentNode === this.grid) {
624
- this.grid.removeChild(this.psvContainer);
625
- this.psvContainer.removeAttribute("slot");
626
- }
627
-
628
- // Remove map from mini
629
- if(this.mapContainer.parentNode === this.mini) {
630
- this.mini.removeChild(this.mapContainer);
631
- }
632
-
633
- // Add map to grid
634
- this.mapContainer.setAttribute("slot", "bg");
635
- this.grid.appendChild(this.mapContainer);
636
-
637
- // Add PSV to mini
638
- this.mini.appendChild(this.psvContainer);
639
- this.mini.icon = fa(faPanorama);
640
- if(this._miniPicLegend) { this.mini.appendChild(this._miniPicLegend); }
641
-
642
- // Hide mini icon if no picture selected
643
- if(isNullId(this.picture)) { this.mini.classList.add("pnx-hidden"); }
644
- else { this.mini.classList.remove("pnx-hidden"); }
645
-
646
- this.map.getCanvas().focus();
647
- }
648
- else {
649
- // Remove map from grid
650
- if(this.mapContainer.parentNode === this.grid) {
651
- this.grid.removeChild(this.mapContainer);
652
- this.mapContainer.removeAttribute("slot");
653
- }
654
-
655
- // Remove PSV from mini
656
- if(this.psvContainer.parentNode === this.mini) {
657
- this.mini.removeChild(this.psvContainer);
658
- if(this._miniPicLegend) { this.mini.removeChild(this._miniPicLegend); }
659
- }
660
-
661
- // Add PSV to grid
662
- this.psvContainer.setAttribute("slot", "bg");
663
- this.grid.appendChild(this.psvContainer);
664
-
665
- // Add map to mini
666
- this.mini.classList.remove("pnx-hidden");
667
- this.mini.appendChild(this.mapContainer);
668
- this.mini.icon = fa(faMap);
669
-
670
- this.psvContainer.focus();
671
- }
672
-
673
- this?.map?.resize?.();
674
- this.psv.autoSize();
675
- this.psv.forceRefresh();
676
- this.legend?.setAttribute?.("focus", this.focus);
677
-
678
- if(!skipEvent) {
679
- /**
680
- * Event for focus change (either map or picture is shown wide)
681
- * @event Panoramax.components.core.Viewer#focus-changed
682
- * @type {CustomEvent}
683
- * @property {string} detail.focus Component now focused on (map, pic)
684
- */
685
- const event = new CustomEvent("focus-changed", { detail: { focus } });
686
- this.dispatchEvent(event);
687
- }
688
- }
689
-
690
- /**
691
- * Toggle the viewer focus (either on picture or map)
692
- * @memberof Panoramax.components.core.Viewer#
693
- * @private
694
- */
695
- _toggleFocus() {
696
- this._setFocus(this.isMapWide() ? "pic" : "map");
697
- }
698
-
699
- /** @private */
700
- _onMiniExpand() {
701
- this.map.resize();
702
- this.psv.autoSize();
703
- }
704
-
705
- /** @private */
706
- _showLocationPrecisionDoc() {
707
- this.setPopup(true, [createWebComp("pnx-location-precision-doc", {_t: this._t})]);
708
- }
709
- }
710
-
711
- customElements.define("pnx-viewer", Viewer);