@panoramax/web-viewer 3.2.3 → 4.0.0-develop-9f9cf858

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 (255) hide show
  1. package/.gitlab-ci.yml +13 -6
  2. package/CHANGELOG.md +56 -1
  3. package/CODE_OF_CONDUCT.md +1 -1
  4. package/README.md +1 -1
  5. package/build/editor.html +10 -1
  6. package/build/index.css +12 -12
  7. package/build/index.css.map +1 -1
  8. package/build/index.html +1 -1
  9. package/build/index.js +2126 -14
  10. package/build/index.js.map +1 -1
  11. package/build/map.html +1 -1
  12. package/build/photo.html +1 -0
  13. package/build/static/media/atkinson-hyperlegible-next-latin-400-normal..woff +0 -0
  14. package/build/static/media/atkinson-hyperlegible-next-latin-400-normal..woff2 +0 -0
  15. package/build/static/media/atkinson-hyperlegible-next-latin-ext-400-normal..woff +0 -0
  16. package/build/static/media/atkinson-hyperlegible-next-latin-ext-400-normal..woff2 +0 -0
  17. package/build/viewer.html +12 -1
  18. package/build/widgets.html +1 -0
  19. package/config/jest/mocks.js +201 -0
  20. package/config/paths.js +2 -0
  21. package/config/webpack.config.js +52 -0
  22. package/docs/03_URL_settings.md +14 -16
  23. package/docs/05_Compatibility.md +59 -76
  24. package/docs/09_Develop.md +46 -11
  25. package/docs/90_Releases.md +2 -2
  26. package/docs/images/class_diagram.drawio +60 -45
  27. package/docs/images/class_diagram.jpg +0 -0
  28. package/docs/images/screenshot.jpg +0 -0
  29. package/docs/index.md +135 -0
  30. package/docs/reference/components/core/Basic.md +196 -0
  31. package/docs/reference/components/core/CoverageMap.md +210 -0
  32. package/docs/reference/components/core/Editor.md +224 -0
  33. package/docs/reference/components/core/PhotoViewer.md +307 -0
  34. package/docs/reference/components/core/Viewer.md +350 -0
  35. package/docs/reference/components/layout/BottomDrawer.md +35 -0
  36. package/docs/reference/components/layout/CorneredGrid.md +29 -0
  37. package/docs/reference/components/layout/Mini.md +45 -0
  38. package/docs/reference/components/layout/Tabs.md +45 -0
  39. package/docs/reference/components/menus/MapBackground.md +32 -0
  40. package/docs/reference/components/menus/MapFilters.md +15 -0
  41. package/docs/reference/components/menus/MapLayers.md +15 -0
  42. package/docs/reference/components/menus/MapLegend.md +15 -0
  43. package/docs/reference/components/menus/PictureLegend.md +16 -0
  44. package/docs/reference/components/menus/PictureMetadata.md +15 -0
  45. package/docs/reference/components/menus/PlayerOptions.md +15 -0
  46. package/docs/reference/components/menus/QualityScoreDoc.md +15 -0
  47. package/docs/reference/components/menus/ReportForm.md +15 -0
  48. package/docs/reference/components/menus/ShareMenu.md +15 -0
  49. package/docs/reference/components/ui/Button.md +40 -0
  50. package/docs/reference/components/ui/ButtonGroup.md +36 -0
  51. package/docs/reference/components/ui/CopyButton.md +38 -0
  52. package/docs/reference/components/ui/Grade.md +32 -0
  53. package/docs/reference/components/ui/LinkButton.md +45 -0
  54. package/docs/reference/components/ui/ListGroup.md +22 -0
  55. package/docs/reference/components/ui/Loader.md +56 -0
  56. package/docs/reference/components/ui/Map.md +239 -0
  57. package/docs/reference/components/ui/MapMore.md +256 -0
  58. package/docs/reference/components/ui/Photo.md +385 -0
  59. package/docs/reference/components/ui/Popup.md +56 -0
  60. package/docs/reference/components/ui/ProgressBar.md +32 -0
  61. package/docs/reference/components/ui/QualityScore.md +45 -0
  62. package/docs/reference/components/ui/SearchBar.md +63 -0
  63. package/docs/reference/components/ui/TogglableGroup.md +39 -0
  64. package/docs/reference/components/ui/widgets/GeoSearch.md +32 -0
  65. package/docs/reference/components/ui/widgets/Legend.md +49 -0
  66. package/docs/reference/components/ui/widgets/MapFiltersButton.md +33 -0
  67. package/docs/reference/components/ui/widgets/MapLayersButton.md +15 -0
  68. package/docs/reference/components/ui/widgets/OSMEditors.md +15 -0
  69. package/docs/reference/components/ui/widgets/PictureLegendActions.md +32 -0
  70. package/docs/reference/components/ui/widgets/Player.md +33 -0
  71. package/docs/reference/components/ui/widgets/Zoom.md +15 -0
  72. package/docs/reference/utils/API.md +334 -0
  73. package/docs/reference/utils/InitParameters.md +68 -0
  74. package/docs/reference/utils/URLHandler.md +107 -0
  75. package/docs/reference.md +79 -0
  76. package/docs/shortcuts.md +11 -0
  77. package/docs/tutorials/aerial_imagery.md +19 -0
  78. package/docs/tutorials/authentication.md +10 -0
  79. package/docs/tutorials/custom_widgets.md +59 -0
  80. package/docs/tutorials/map_style.md +39 -0
  81. package/docs/tutorials/migrate_v4.md +153 -0
  82. package/docs/tutorials/synced_coverage.md +43 -0
  83. package/mkdocs.yml +66 -5
  84. package/package.json +22 -17
  85. package/public/editor.html +21 -29
  86. package/public/index.html +17 -12
  87. package/public/map.html +19 -18
  88. package/public/photo.html +55 -0
  89. package/public/viewer.html +22 -26
  90. package/public/widgets.html +306 -0
  91. package/scripts/doc.js +79 -0
  92. package/src/components/core/Basic.css +48 -0
  93. package/src/components/core/Basic.js +349 -0
  94. package/src/components/core/CoverageMap.css +9 -0
  95. package/src/components/core/CoverageMap.js +139 -0
  96. package/src/components/core/Editor.css +23 -0
  97. package/src/components/core/Editor.js +390 -0
  98. package/src/components/core/PhotoViewer.css +48 -0
  99. package/src/components/core/PhotoViewer.js +499 -0
  100. package/src/components/core/Viewer.css +98 -0
  101. package/src/components/core/Viewer.js +564 -0
  102. package/src/components/core/index.js +12 -0
  103. package/src/components/index.js +13 -0
  104. package/src/components/layout/BottomDrawer.js +257 -0
  105. package/src/components/layout/CorneredGrid.js +112 -0
  106. package/src/components/layout/Mini.js +117 -0
  107. package/src/components/layout/Tabs.js +133 -0
  108. package/src/components/layout/index.js +9 -0
  109. package/src/components/menus/MapBackground.js +106 -0
  110. package/src/components/menus/MapFilters.js +400 -0
  111. package/src/components/menus/MapLayers.js +143 -0
  112. package/src/components/menus/MapLegend.js +34 -0
  113. package/src/components/menus/PictureLegend.js +257 -0
  114. package/src/components/menus/PictureMetadata.js +317 -0
  115. package/src/components/menus/PlayerOptions.js +95 -0
  116. package/src/components/menus/QualityScoreDoc.js +36 -0
  117. package/src/components/menus/ReportForm.js +133 -0
  118. package/src/components/menus/Share.js +100 -0
  119. package/src/components/menus/index.js +15 -0
  120. package/src/components/styles.js +383 -0
  121. package/src/components/ui/Button.js +77 -0
  122. package/src/components/ui/ButtonGroup.css +57 -0
  123. package/src/components/ui/ButtonGroup.js +68 -0
  124. package/src/components/ui/CopyButton.js +106 -0
  125. package/src/components/ui/Grade.js +54 -0
  126. package/src/components/ui/LinkButton.js +67 -0
  127. package/src/components/ui/ListGroup.js +66 -0
  128. package/src/components/ui/Loader.js +203 -0
  129. package/src/components/{Map.css → ui/Map.css} +5 -17
  130. package/src/components/{Map.js → ui/Map.js} +148 -156
  131. package/src/components/ui/MapMore.js +324 -0
  132. package/src/components/{Photo.css → ui/Photo.css} +6 -6
  133. package/src/components/{Photo.js → ui/Photo.js} +313 -101
  134. package/src/components/ui/Popup.js +145 -0
  135. package/src/components/ui/ProgressBar.js +104 -0
  136. package/src/components/ui/QualityScore.js +147 -0
  137. package/src/components/ui/SearchBar.js +367 -0
  138. package/src/components/ui/TogglableGroup.js +157 -0
  139. package/src/components/ui/index.js +22 -0
  140. package/src/components/ui/widgets/GeoSearch.css +21 -0
  141. package/src/components/ui/widgets/GeoSearch.js +139 -0
  142. package/src/components/ui/widgets/Legend.js +113 -0
  143. package/src/components/ui/widgets/MapFiltersButton.js +104 -0
  144. package/src/components/ui/widgets/MapLayersButton.js +79 -0
  145. package/src/components/ui/widgets/OSMEditors.js +155 -0
  146. package/src/components/ui/widgets/PictureLegendActions.js +117 -0
  147. package/src/components/ui/widgets/Player.css +7 -0
  148. package/src/components/ui/widgets/Player.js +151 -0
  149. package/src/components/ui/widgets/Zoom.js +82 -0
  150. package/src/components/ui/widgets/index.js +13 -0
  151. package/src/img/loader_base.jpg +0 -0
  152. package/src/img/panoramax.svg +13 -0
  153. package/src/img/switch_big.svg +20 -10
  154. package/src/index.js +7 -9
  155. package/src/translations/br.json +1 -0
  156. package/src/translations/da.json +38 -15
  157. package/src/translations/de.json +5 -3
  158. package/src/translations/en.json +35 -15
  159. package/src/translations/eo.json +38 -15
  160. package/src/translations/es.json +1 -1
  161. package/src/translations/fr.json +36 -16
  162. package/src/translations/hu.json +1 -1
  163. package/src/translations/it.json +39 -16
  164. package/src/translations/ja.json +182 -1
  165. package/src/translations/nl.json +106 -6
  166. package/src/translations/pl.json +1 -1
  167. package/src/translations/sv.json +182 -0
  168. package/src/translations/zh_Hant.json +35 -14
  169. package/src/utils/API.js +109 -49
  170. package/src/utils/InitParameters.js +388 -0
  171. package/src/utils/PhotoAdapter.js +1 -0
  172. package/src/utils/URLHandler.js +362 -0
  173. package/src/utils/geocoder.js +152 -0
  174. package/src/utils/{I18n.js → i18n.js} +7 -3
  175. package/src/utils/index.js +11 -0
  176. package/src/utils/{Map.js → map.js} +256 -77
  177. package/src/utils/picture.js +442 -0
  178. package/src/utils/utils.js +324 -0
  179. package/src/utils/widgets.js +55 -0
  180. package/tests/components/core/Basic.test.js +121 -0
  181. package/tests/components/core/BasicMock.js +25 -0
  182. package/tests/components/core/CoverageMap.test.js +20 -0
  183. package/tests/components/core/Editor.test.js +20 -0
  184. package/tests/components/core/PhotoViewer.test.js +57 -0
  185. package/tests/components/core/Viewer.test.js +84 -0
  186. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +73 -0
  187. package/tests/components/core/__snapshots__/Viewer.test.js.snap +145 -0
  188. package/tests/components/ui/CopyButton.test.js +52 -0
  189. package/tests/components/ui/Loader.test.js +55 -0
  190. package/tests/components/{Map.test.js → ui/Map.test.js} +73 -61
  191. package/tests/components/{Photo.test.js → ui/Photo.test.js} +97 -63
  192. package/tests/components/ui/Popup.test.js +26 -0
  193. package/tests/components/ui/QualityScore.test.js +18 -0
  194. package/tests/components/ui/SearchBar.test.js +110 -0
  195. package/tests/components/ui/__snapshots__/CopyButton.test.js.snap +33 -0
  196. package/tests/components/ui/__snapshots__/Loader.test.js.snap +56 -0
  197. package/tests/components/{__snapshots__ → ui/__snapshots__}/Map.test.js.snap +11 -38
  198. package/tests/components/{__snapshots__ → ui/__snapshots__}/Photo.test.js.snap +70 -6
  199. package/tests/components/ui/__snapshots__/Popup.test.js.snap +29 -0
  200. package/tests/components/ui/__snapshots__/QualityScore.test.js.snap +11 -0
  201. package/tests/components/ui/__snapshots__/SearchBar.test.js.snap +65 -0
  202. package/tests/utils/API.test.js +83 -83
  203. package/tests/utils/InitParameters.test.js +499 -0
  204. package/tests/utils/URLHandler.test.js +401 -0
  205. package/tests/utils/__snapshots__/API.test.js.snap +10 -0
  206. package/tests/utils/__snapshots__/URLHandler.test.js.snap +21 -0
  207. package/tests/utils/__snapshots__/{Map.test.js.snap → geocoder.test.js.snap} +1 -1
  208. package/tests/utils/__snapshots__/map.test.js.snap +11 -0
  209. package/tests/utils/__snapshots__/picture.test.js.snap +327 -0
  210. package/tests/utils/__snapshots__/widgets.test.js.snap +19 -0
  211. package/tests/utils/geocoder.test.js +37 -0
  212. package/tests/utils/{I18n.test.js → i18n.test.js} +8 -8
  213. package/tests/utils/map.test.js +126 -0
  214. package/tests/utils/picture.test.js +745 -0
  215. package/tests/utils/utils.test.js +288 -0
  216. package/tests/utils/widgets.test.js +31 -0
  217. package/docs/01_Start.md +0 -149
  218. package/docs/02_Usage.md +0 -831
  219. package/docs/04_Advanced_examples.md +0 -216
  220. package/src/Editor.css +0 -37
  221. package/src/Editor.js +0 -361
  222. package/src/StandaloneMap.js +0 -114
  223. package/src/Viewer.css +0 -203
  224. package/src/Viewer.js +0 -1246
  225. package/src/components/CoreView.css +0 -70
  226. package/src/components/CoreView.js +0 -175
  227. package/src/components/Loader.css +0 -74
  228. package/src/components/Loader.js +0 -120
  229. package/src/img/loader_hd.jpg +0 -0
  230. package/src/utils/Exif.js +0 -193
  231. package/src/utils/Utils.js +0 -631
  232. package/src/utils/Widgets.js +0 -562
  233. package/src/viewer/URLHash.js +0 -469
  234. package/src/viewer/Widgets.css +0 -880
  235. package/src/viewer/Widgets.js +0 -1470
  236. package/tests/Editor.test.js +0 -126
  237. package/tests/StandaloneMap.test.js +0 -45
  238. package/tests/Viewer.test.js +0 -366
  239. package/tests/__snapshots__/Editor.test.js.snap +0 -298
  240. package/tests/__snapshots__/StandaloneMap.test.js.snap +0 -30
  241. package/tests/__snapshots__/Viewer.test.js.snap +0 -195
  242. package/tests/components/CoreView.test.js +0 -92
  243. package/tests/components/Loader.test.js +0 -38
  244. package/tests/components/__snapshots__/Loader.test.js.snap +0 -15
  245. package/tests/utils/Exif.test.js +0 -124
  246. package/tests/utils/Map.test.js +0 -113
  247. package/tests/utils/Utils.test.js +0 -300
  248. package/tests/utils/Widgets.test.js +0 -107
  249. package/tests/utils/__snapshots__/Exif.test.js.snap +0 -43
  250. package/tests/utils/__snapshots__/Utils.test.js.snap +0 -41
  251. package/tests/utils/__snapshots__/Widgets.test.js.snap +0 -44
  252. package/tests/viewer/URLHash.test.js +0 -559
  253. package/tests/viewer/Widgets.test.js +0 -127
  254. package/tests/viewer/__snapshots__/URLHash.test.js.snap +0 -108
  255. package/tests/viewer/__snapshots__/Widgets.test.js.snap +0 -403
@@ -0,0 +1,499 @@
1
+ /* eslint-disable import/no-unused-modules */
2
+ /* eslint-disable no-unused-vars */
3
+
4
+ import "./PhotoViewer.css";
5
+ import { SYSTEM as PSSystem, DEFAULTS as PSDefaults } from "@photo-sphere-viewer/core";
6
+ import URLHandler from "../../utils/URLHandler";
7
+ import Basic from "./Basic";
8
+ import Photo, { PSV_DEFAULT_ZOOM, PSV_ANIM_DURATION } from "../ui/Photo";
9
+ import { createWebComp } from "../../utils/widgets";
10
+ import { isNullId } from "../../utils/utils";
11
+ import { default as InitParameters, alterPSVState, alterMapState, alterPhotoViewerState } from "../../utils/InitParameters";
12
+
13
+
14
+ export const PSV_ZOOM_DELTA = 20;
15
+ const PSV_MOVE_DELTA = Math.PI / 6;
16
+
17
+
18
+ /**
19
+ * Photo Viewer is a component showing pictures (without any 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 with map, checkout [Viewer component](#Panoramax.components.core.Viewer).
24
+ *
25
+ * Make sure to set width/height through CSS for proper display.
26
+ * @class Panoramax.components.core.PhotoViewer
27
+ * @element pnx-photo-viewer
28
+ * @extends Panoramax.components.core.Basic
29
+ * @property {Panoramax.components.ui.Loader} loader The loader screen
30
+ * @property {Panoramax.utils.API} api The API manager
31
+ * @property {Panoramax.components.ui.Photo} psv The Photo Sphere Viewer component itself
32
+ * @property {Panoramax.components.layout.CorneredGrid} grid The grid layout manager
33
+ * @property {Panoramax.components.ui.Popup} popup The popup container
34
+ * @property {Panoramax.utils.URLHandler} urlHandler The URL query parameters manager
35
+ * @fires Panoramax.components.core.Basic#select
36
+ * @fires Panoramax.components.core.Basic#ready
37
+ * @fires Panoramax.components.core.Basic#broken
38
+ * @slot `top-left` The top-left corner
39
+ * @slot `top` The top middle corner
40
+ * @slot `top-right` The top-right corner
41
+ * @slot `bottom-left` The bottom-left corner
42
+ * @slot `bottom` The bottom middle corner
43
+ * @slot `bottom-right` The bottom-right corner
44
+ * @slot `editors` External links to map editors, or any tool that may be helpful. Defaults to OSM tools (iD & JOSM).
45
+ * @example
46
+ * ```html
47
+ * <!-- Basic example -->
48
+ * <pnx-photo-viewer
49
+ * endpoint="https://panoramax.openstreetmap.fr/"
50
+ * style="width: 300px; height: 250px"
51
+ * />
52
+ *
53
+ * <!-- With slotted widgets -->
54
+ * <pnx-photo-viewer
55
+ * endpoint="https://panoramax.openstreetmap.fr/"
56
+ * style="width: 300px; height: 250px"
57
+ * >
58
+ * <p slot="top-right">My custom text</p>
59
+ * <p slot="editors"><a href="https://my.own.tool/">Edit in my own tool</a></p>
60
+ * </pnx-photo-viewer>
61
+ *
62
+ * <!-- With only your custom widgets -->
63
+ * <pnx-photo-viewer
64
+ * endpoint="https://panoramax.openstreetmap.fr/"
65
+ * style="width: 300px; height: 250px"
66
+ * widgets="false"
67
+ * >
68
+ * <p slot="top-right">My custom text</p>
69
+ * </pnx-photo-viewer>
70
+ * ```
71
+ */
72
+ export default class PhotoViewer extends Basic {
73
+ /**
74
+ * Component properties. All of [Basic properties](#Panoramax.components.core.Basic+properties) are available as well.
75
+ * @memberof Panoramax.components.core.PhotoViewer#
76
+ * @mixes Panoramax.components.core.Basic#properties
77
+ * @type {Object}
78
+ * @property {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md))
79
+ * @property {object} [psv] [Any option to pass to Photo component](#Panoramax.components.ui.Photo) as an object.<br />Example: `psv="{'transitionDuration': 500, 'picturesNavigation': 'pic'}"`
80
+ * @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.
81
+ * @property {string} [picture] The picture ID to display
82
+ * @property {string} [sequence] The sequence ID of the picture displayed
83
+ * @property {object} [fetchOptions] 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))
84
+ * @property {string} [lang] To override language used for labels. Defaults to using user's preferred languages.
85
+ * @property {string} [url-parameters=true] Should the component add and update URL query parameters to save viewer state ?
86
+ */
87
+ static properties = {
88
+ psv: {converter: Basic.GetJSONConverter()},
89
+ widgets: {type: String},
90
+ "url-parameters": {type: String},
91
+ ...Basic.properties
92
+ };
93
+
94
+ constructor() {
95
+ super();
96
+
97
+ // Defaults
98
+ this.psv = {};
99
+ this["url-parameters"] = this.getAttribute("url-parameters") || true;
100
+ this.widgets = this.getAttribute("widgets") || "true";
101
+
102
+ // Init DOM containers
103
+ this.grid = createWebComp("pnx-cornered-grid");
104
+ this.psvContainer = document.createElement("div");
105
+ this.psvContainer.setAttribute("slot", "bg");
106
+ this.grid.appendChild(this.psvContainer);
107
+ this.popup = createWebComp("pnx-popup", {_parent: this, onclose: this._onPopupClose.bind(this)});
108
+ }
109
+
110
+ /** @private */
111
+ _createInitParamsHandler() {
112
+ this._initParams = new InitParameters(
113
+ InitParameters.GetComponentProperties(PhotoViewer, this),
114
+ Object.assign({}, this.urlHandler?.currentURLParams(), this.urlHandler?.currentURLParams(true)),
115
+ {},
116
+ );
117
+ }
118
+
119
+ /** @private */
120
+ _initWidgets() {
121
+ if(this._initParams.getParentPostInit().widgets !== "false") {
122
+ this.grid.appendChild(createWebComp("pnx-widget-player", {
123
+ slot: "top",
124
+ _parent: this,
125
+ class: "pnx-only-psv pnx-print-hidden",
126
+ size: this.isHeightSmall() ? "md": "xl",
127
+ }));
128
+
129
+ if(!this.isWidthSmall()) {
130
+ this.legend = createWebComp("pnx-widget-legend", {
131
+ slot: !this.isWidthSmall() ? "top-left" : undefined,
132
+ _parent: this,
133
+ focus: this._initParams.getParentPostInit().focus,
134
+ picture: this._initParams.getParentPostInit().picture,
135
+ });
136
+ this.grid.appendChild(createWebComp("pnx-widget-zoom", {
137
+ slot: "bottom-right",
138
+ class: "pnx-print-hidden",
139
+ _parent: this
140
+ }));
141
+ this.grid.appendChild(this.legend);
142
+ }
143
+ else {
144
+ this.legend = createWebComp("pnx-picture-legend", { _parent: this });
145
+ this.bottomDrawer = createWebComp("pnx-bottom-drawer", {
146
+ slot: "bottom",
147
+ _parent: this,
148
+ class: this._initParams.getParentPostInit().picture ? undefined: "pnx-hidden",
149
+ });
150
+ this.bottomDrawer.appendChild(this.legend);
151
+ this.grid.appendChild(this.bottomDrawer);
152
+ this.addEventListener("select", e => {
153
+ if(isNullId(e.detail.picId)) { this.bottomDrawer.classList.add("pnx-hidden"); }
154
+ else { this.bottomDrawer.classList.remove("pnx-hidden"); }
155
+ });
156
+ }
157
+ }
158
+ }
159
+
160
+ /** @private */
161
+ connectedCallback() {
162
+ super.connectedCallback();
163
+
164
+ if(this["url-parameters"] && this["url-parameters"] !== "false") {
165
+ this.urlHandler = new URLHandler(this);
166
+ this.onceReady().then(() => {
167
+ this.urlHandler.listenToChanges();
168
+ this.urlHandler._onParentChange();
169
+ });
170
+ }
171
+
172
+ this.onceAPIReady().then(this._postAPIInit.bind(this));
173
+ }
174
+
175
+ /** @private */
176
+ firstUpdated() {
177
+ super.firstUpdated();
178
+ this._moveChildToGrid();
179
+ }
180
+
181
+ getClassName() {
182
+ return "PhotoViewer";
183
+ }
184
+
185
+ /**
186
+ * Waits for PhotoViewer to be completely ready (map & PSV loaded, first picture also if one is wanted)
187
+ * @returns {Promise} When viewer is ready
188
+ * @memberof Panoramax.components.core.PhotoViewer#
189
+ */
190
+ onceReady() {
191
+ return this.oncePSVReady().then(() => {
192
+ if(this._initParams.getParentPostInit().picture && !this.psv.getPictureMetadata()) { return this.onceFirstPicLoaded(); }
193
+ else { return Promise.resolve(); }
194
+ });
195
+ }
196
+
197
+ /** @private */
198
+ render() {
199
+ return [this.loader, this.grid, this.popup];
200
+ }
201
+
202
+ getSubComponentsNames() {
203
+ return super.getSubComponentsNames().concat(["psv", "grid", "popup", "urlHandler"]);
204
+ }
205
+
206
+ /**
207
+ * Waiting for Photo Sphere Viewer to be available.
208
+ * @returns {Promise} When PSV is ready to use
209
+ * @memberof Panoramax.components.core.PhotoViewer#
210
+ */
211
+ oncePSVReady() {
212
+ let waiter;
213
+ return new Promise(resolve => {
214
+ waiter = setInterval(() => {
215
+ if(this.psv && typeof this.psv === "object") {
216
+ if(this.psv.container) {
217
+ clearInterval(waiter);
218
+ resolve();
219
+ }
220
+ else if(this.psv.addEventListener) {
221
+ this.psv.addEventListener("ready", () => {
222
+ clearInterval(waiter);
223
+ resolve();
224
+ }, {once: true});
225
+ }
226
+ }
227
+ }, 250);
228
+ });
229
+ }
230
+
231
+ /**
232
+ * Waits for first picture to display on PSV.
233
+ * @returns {Promise}
234
+ * @fulfil {undefined} When picture is shown
235
+ * @memberof Panoramax.components.core.PhotoViewer#
236
+ */
237
+ onceFirstPicLoaded() {
238
+ return this.oncePSVReady().then(() => {
239
+ if(this.psv.getPictureMetadata()) { return Promise.resolve(); }
240
+ else {
241
+ return new Promise(resolve => {
242
+ this.psv.addEventListener("picture-loaded", resolve, {once: true});
243
+ });
244
+ }
245
+ });
246
+ }
247
+
248
+ /** @private */
249
+ async _postAPIInit() {
250
+ this.loader.setAttribute("value", 30);
251
+ this._createInitParamsHandler();
252
+
253
+ const myPostInitParams = this._initParams.getParentPostInit();
254
+
255
+ this._initPSV();
256
+ this._initWidgets();
257
+ alterPhotoViewerState(this, myPostInitParams);
258
+ this._handleKeyboardManagement();
259
+
260
+ if(myPostInitParams.picture) {
261
+ this.psv.addEventListener("picture-loaded", () => this.loader.dismiss(), {once: true});
262
+ }
263
+ else {
264
+ this.loader.dismiss();
265
+ }
266
+ }
267
+
268
+ /** @private */
269
+ _initPSV() {
270
+ try {
271
+ this.psv = new Photo(this, this.psvContainer, {
272
+ shouldGoFast: this._psvShouldGoFast.bind(this),
273
+ keyboard: "always",
274
+ keyboardActions: {
275
+ ...PSDefaults.keyboardActions,
276
+ "8": "ROTATE_UP",
277
+ "2": "ROTATE_DOWN",
278
+ "4": "ROTATE_LEFT",
279
+ "6": "ROTATE_RIGHT",
280
+
281
+ "PageUp": () => this.psv.goToNextPicture(),
282
+ "9": () => this.psv.goToNextPicture(),
283
+
284
+ "PageDown": () => this.psv.goToPrevPicture(),
285
+ "3": () => this.psv.goToPrevPicture(),
286
+
287
+ "5": () => this.moveCenter(),
288
+ "*": () => this.moveCenter(),
289
+
290
+ "Home": () => this._toggleFocus(),
291
+ "7": () => this._toggleFocus(),
292
+
293
+ "End": () => this.mini.toggleAttribute("collapsed"),
294
+ "1": () => this.mini.toggleAttribute("collapsed"),
295
+
296
+ " ": () => this.psv.toggleSequencePlaying(),
297
+ "0": () => this.psv.toggleSequencePlaying(),
298
+ },
299
+ ...this._initParams.getPSVInit()
300
+ });
301
+ this.oncePSVReady().then(() => {
302
+ this.loader.setAttribute("value", 50);
303
+ alterPSVState(this.psv, this._initParams.getPSVPostInit());
304
+ });
305
+ }
306
+ catch(e) {
307
+ let err = !PSSystem.isWebGLSupported ? this._t.pnx.error_webgl : this._t.pnx.error_psv;
308
+ this.loader.dismiss(e, err);
309
+ }
310
+ }
311
+
312
+ /** @private */
313
+ _handleKeyboardManagement() {
314
+ // Switchers
315
+ const keytonone = () => this.psv.stopKeyboardControl();
316
+ const keytopsv = () => this.psv.startKeyboardControl();
317
+
318
+ // Popup
319
+ this.popup.addEventListener("open", () => keytonone());
320
+ this.popup.addEventListener("close", () => keytopsv());
321
+
322
+ // Widgets
323
+ for(let cn of this.grid.childNodes) {
324
+ if(cn.getAttribute("slot") !== "bg") {
325
+ cn.addEventListener("focusin", () => keytonone());
326
+ cn.addEventListener("focusout", () => keytopsv());
327
+ }
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Given context, should tiles be loaded in PSV.
333
+ * @private
334
+ */
335
+ _psvShouldGoFast() {
336
+ return (this.psv._sequencePlaying && this.psv.getTransitionDuration() < 1000);
337
+ }
338
+
339
+ /** @private */
340
+ _moveChildToGrid() {
341
+ const slotContent = Array.from(this.querySelectorAll("[slot]"));
342
+
343
+ slotContent.forEach(n => {
344
+ // Add parent + translation for our components
345
+ if(n.tagName?.toLowerCase().startsWith("pnx-")) {
346
+ n._parent = this;
347
+ n._t = this._t;
348
+ }
349
+
350
+ // Editors slot -> legend
351
+ if(n.getAttribute("slot") === "editors") {
352
+ this.onceReady().then(() => this.legend?.appendChild(n));
353
+ }
354
+ // Add to grid else
355
+ else {
356
+ this.grid.appendChild(n);
357
+ }
358
+ });
359
+ }
360
+
361
+ /**
362
+ * Change full-page popup visibility and content
363
+ * @memberof Panoramax.components.core.PhotoViewer#
364
+ * @param {boolean} visible True to make it appear
365
+ * @param {string|Element[]} [content] The new popup content
366
+ */
367
+ setPopup(visible, content = null) {
368
+ if(visible) { this.popup.setAttribute("visible", ""); }
369
+ else { this.popup.removeAttribute("visible"); }
370
+
371
+ this.popup.innerHTML = "";
372
+ if(typeof content === "string") { this.popup.innerHTML = content; }
373
+ else if(Array.isArray(content)) { content.forEach(c => this.popup.appendChild(c)); }
374
+ }
375
+
376
+ /** @private */
377
+ _onPopupClose() {
378
+ this.dispatchEvent(new CustomEvent("focus-changed", { detail: { focus: this.map && this.isMapWide() ? "map" : "pic" } }));
379
+ }
380
+
381
+ /** @private */
382
+ _showQualityScoreDoc() {
383
+ this.setPopup(true, [createWebComp("pnx-quality-score-doc", {_t: this._t})]);
384
+ }
385
+
386
+ /** @private */
387
+ _showReportForm() {
388
+ if(!this.psv.getPictureMetadata()) { throw new Error("No picture currently selected"); }
389
+ this.setPopup(true, [createWebComp("pnx-report-form", {_parent: this})]);
390
+ }
391
+
392
+ /** @private */
393
+ _showShareOptions() {
394
+ this.setPopup(true, [createWebComp("pnx-share-menu", {_parent: this})]);
395
+ }
396
+
397
+ /**
398
+ * Move the view of main component to its center.
399
+ * For map, center view on selected picture.
400
+ * For picture, center view on image center.
401
+ * @memberof Panoramax.components.core.PhotoViewer#
402
+ */
403
+ moveCenter() {
404
+ const meta = this.psv.getPictureMetadata();
405
+ if(!meta) { return; }
406
+
407
+ this._psvAnimate({
408
+ speed: PSV_ANIM_DURATION,
409
+ yaw: 0,
410
+ pitch: 0,
411
+ zoom: PSV_DEFAULT_ZOOM
412
+ });
413
+ }
414
+
415
+ /**
416
+ * Moves the view of main component slightly to the left.
417
+ * @memberof Panoramax.components.core.PhotoViewer#
418
+ */
419
+ moveLeft() {
420
+ this._moveToDirection("left");
421
+ }
422
+
423
+ /**
424
+ * Moves the view of main component slightly to the right.
425
+ * @memberof Panoramax.components.core.PhotoViewer#
426
+ */
427
+ moveRight() {
428
+ this._moveToDirection("right");
429
+ }
430
+
431
+ /**
432
+ * Moves the view of main component slightly to the top.
433
+ * @memberof Panoramax.components.core.PhotoViewer#
434
+ */
435
+ moveUp() {
436
+ this._moveToDirection("up");
437
+ }
438
+
439
+ /**
440
+ * Moves the view of main component slightly to the bottom.
441
+ * @memberof Panoramax.components.core.PhotoViewer#
442
+ */
443
+ moveDown() {
444
+ this._moveToDirection("down");
445
+ }
446
+
447
+ /**
448
+ * Moves map or picture viewer to given direction.
449
+ * @param {string} dir Direction to move to (up, left, down, right)
450
+ * @private
451
+ */
452
+ _moveToDirection(dir) {
453
+ let pos = this.psv.getPosition();
454
+ switch(dir) {
455
+ case "up":
456
+ pos.pitch += PSV_MOVE_DELTA;
457
+ break;
458
+ case "left":
459
+ pos.yaw -= PSV_MOVE_DELTA;
460
+ break;
461
+ case "down":
462
+ pos.pitch -= PSV_MOVE_DELTA;
463
+ break;
464
+ case "right":
465
+ pos.yaw += PSV_MOVE_DELTA;
466
+ break;
467
+ }
468
+ this._psvAnimate({ speed: PSV_ANIM_DURATION, ...pos });
469
+ }
470
+
471
+ /**
472
+ * Overrided PSV animate function to ensure a single animation plays at once.
473
+ * @param {object} options PSV animate options
474
+ * @private
475
+ */
476
+ _psvAnimate(options) {
477
+ if(this._lastPsvAnim) { this._lastPsvAnim.cancel(); }
478
+ this._lastPsvAnim = this.psv.animate(options);
479
+ }
480
+
481
+ /**
482
+ * Listen to events from this components or one of its sub-components.
483
+ *
484
+ * For example, you can listen to `psv` events using prefix `psv:`.
485
+ *
486
+ * ```js
487
+ * me.addEventListener("psv:picture-loading", doSomething);
488
+ * ```
489
+ * @param {string} type The event type to listen for
490
+ * @param {function} listener The event handler
491
+ * @param {object} [options] [Any original addEventListener available options](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options)
492
+ * @memberof Panoramax.components.core.PhotoViewer#
493
+ */
494
+ addEventListener(type, listener, options) {
495
+ super.addEventListener(type, listener, options);
496
+ }
497
+ }
498
+
499
+ customElements.define("pnx-photo-viewer", PhotoViewer);
@@ -0,0 +1,98 @@
1
+ /* Maximized components */
2
+ pnx-viewer .pnx-map.maplibregl-map,
3
+ pnx-viewer .pnx-psv {
4
+ position: absolute;
5
+ inset: 0;
6
+ z-index: 0;
7
+ }
8
+
9
+ /* No PSV loader */
10
+ pnx-viewer .psv-loader {
11
+ display: none;
12
+ }
13
+
14
+ /* Search bar over other components */
15
+ pnx-widget-geosearch {
16
+ z-index: 129;
17
+ }
18
+
19
+ /* Cornered grid layout */
20
+ pnx-viewer pnx-cornered-grid::part(corner-top-left),
21
+ pnx-viewer pnx-cornered-grid::part(corner-top),
22
+ pnx-viewer pnx-cornered-grid::part(corner-top-right),
23
+ pnx-viewer pnx-cornered-grid::part(corner-bottom-left),
24
+ pnx-viewer pnx-cornered-grid::part(corner-bottom),
25
+ pnx-viewer pnx-cornered-grid::part(corner-bottom-right) {
26
+ gap: 10px;
27
+ padding: 10px;
28
+ }
29
+
30
+ @media screen and (max-width: 576px) {
31
+ pnx-viewer pnx-cornered-grid::part(corner-top-right) {
32
+ flex-direction: column;
33
+ align-items: flex-end;
34
+ justify-content: flex-start;
35
+ }
36
+
37
+ pnx-viewer pnx-cornered-grid::part(corner-top-left) {
38
+ flex-direction: column;
39
+ align-items: flex-start;
40
+ justify-content: flex-start;
41
+ }
42
+ }
43
+
44
+ /* Mini component */
45
+ pnx-viewer pnx-mini {
46
+ box-sizing: border-box;
47
+ aspect-ratio: 1/1;
48
+ min-width: 250px;
49
+ min-height: 250px;
50
+ position: relative;
51
+ display: block;
52
+ z-index: 120;
53
+ }
54
+
55
+ @media screen and ((max-width: 576px)) {
56
+ pnx-viewer pnx-mini {
57
+ min-width: unset;
58
+ min-height: unset;
59
+ margin-bottom: 40px;
60
+ }
61
+ }
62
+
63
+ pnx-viewer pnx-mini .psv-container,
64
+ pnx-viewer pnx-mini .pnx-map {
65
+ border-radius: 10px;
66
+ }
67
+
68
+ /* Hidden elements depending on focus */
69
+ pnx-viewer:not(pnx-viewer[focus="map"]) .pnx-only-map,
70
+ pnx-viewer:not(pnx-viewer[focus="pic"]) .pnx-only-psv {
71
+ display: none;
72
+ }
73
+
74
+ /* Override legend positioning */
75
+ @media screen and (min-width: 576px) {
76
+ pnx-viewer pnx-widget-legend {
77
+ position: absolute;
78
+ left: 10px;
79
+ top: 60px;
80
+ }
81
+
82
+ pnx-viewer[focus="pic"] pnx-widget-legend {
83
+ top: 10px;
84
+ }
85
+ }
86
+
87
+ /* Hide default map legend */
88
+ pnx-viewer .pnx-map .maplibregl-ctrl-attrib {
89
+ display: none;
90
+ }
91
+
92
+ /* Override geosearch sizing */
93
+ @media screen and (max-width: 576px) {
94
+ pnx-widget-geosearch pnx-search-bar:not([reduced])::part(container) {
95
+ width: 250px;
96
+ max-width: 40vw;
97
+ }
98
+ }