@panoramax/web-viewer 3.2.3 → 4.0.0-develop-39167b4d

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 +53 -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
@@ -1,10 +1,11 @@
1
1
  import "./Photo.css";
2
- import LoaderImgBase from "../img/loader_base.jpg";
3
- import LogoDead from "../img/logo_dead.svg";
2
+ import LoaderImgBase from "../../img/loader_base.jpg";
3
+ import LogoDead from "../../img/logo_dead.svg";
4
4
  import {
5
5
  getDistance, positionToXYZ, xyzToPosition,
6
- apiFeatureToPSVNode, getRelativeHeading, BASE_PANORAMA_ID,
7
- } from "../utils/Utils";
6
+ getRelativeHeading, BASE_PANORAMA_ID, isNullId,
7
+ } from "../../utils/utils";
8
+ import { apiFeatureToPSVNode } from "../../utils/picture";
8
9
 
9
10
  // Photo Sphere Viewer imports
10
11
  import "@photo-sphere-viewer/core/index.css";
@@ -13,7 +14,7 @@ import "@photo-sphere-viewer/gallery-plugin/index.css";
13
14
  import "@photo-sphere-viewer/markers-plugin/index.css";
14
15
  import { Viewer as PSViewer } from "@photo-sphere-viewer/core";
15
16
  import { VirtualTourPlugin } from "@photo-sphere-viewer/virtual-tour-plugin";
16
- import PhotoAdapter from "../utils/PhotoAdapter";
17
+ import PhotoAdapter from "../../utils/PhotoAdapter";
17
18
 
18
19
 
19
20
  // Default panorama (logo)
@@ -36,23 +37,48 @@ const BASE_PANORAMA_NODE = {
36
37
  properties: {},
37
38
  };
38
39
 
39
- export const PSV_DEFAULT_ZOOM = 30;
40
+ export const PSV_DEFAULT_ZOOM = 30; // eslint-disable-line import/no-unused-modules
40
41
  export const PSV_ANIM_DURATION = 250;
41
42
  export const PIC_MAX_STAY_DURATION = 3000;
42
43
 
43
44
  PSViewer.useNewAnglesOrder = true;
44
45
 
46
+ /**
47
+ * Triggered once when the panorama image has been loaded and the viewer is ready to perform the first render.
48
+ * @see {@link https://photo-sphere-viewer.js.org/guide/events.html#ready|Photo Sphere Viewer documentation}
49
+ * @event Panoramax.components.ui.Photo#ready
50
+ * @memberof Panoramax.components.ui.Photo
51
+ * @type {Event}
52
+ */
53
+
45
54
  /**
46
55
  * Photo is the component showing a single picture.
47
56
  * It uses Photo Sphere Viewer as a basis, and pre-configure dialog with STAC API.
48
57
  *
49
58
  * Note that all functions of [PhotoSphereViewer Viewer class](https://photo-sphere-viewer.js.org/api/classes/core.viewer) are available as well.
50
59
  *
51
- * @param {CoreView} parent The parent view
60
+ * @class Panoramax.components.ui.Photo
61
+ * @extends [photo-sphere-viewer.core.Viewer](https://photo-sphere-viewer.js.org/api/classes/Core.Viewer.html)
62
+ * @param {Panoramax.components.core.basic} parent The parent view
52
63
  * @param {Element} container The DOM element to create into
53
64
  * @param {object} [options] The viewer options. Can be any of [Photo Sphere Viewer options](https://photo-sphere-viewer.js.org/guide/config.html#standard-options)
54
65
  * @param {number} [options.transitionDuration] The number of milliseconds the transition animation should be.
66
+ * @param {number[]} [options.position] Initial geographical coordinates (as [latitude, longitude]) to find picture nearby. Only used if no picture ID is set.
55
67
  * @param {function} [options.shouldGoFast] Function returning a boolean to indicate if we may skip loading HD images.
68
+ * @param {string} [options.picturesNavigation=any] The allowed pictures navigation ("any": no restriction, "seq": only pictures in same sequence, "pic": only selected picture)
69
+ * @fires Panoramax.components.ui.Photo#picture-loading
70
+ * @fires Panoramax.components.ui.Photo#picture-preview-started
71
+ * @fires Panoramax.components.ui.Photo#picture-preview-stopped
72
+ * @fires Panoramax.components.ui.Photo#view-rotated
73
+ * @fires Panoramax.components.ui.Photo#picture-loaded
74
+ * @fires Panoramax.components.ui.Photo#picture-tiles-loaded
75
+ * @fires Panoramax.components.ui.Photo#transition-duration-changed
76
+ * @fires Panoramax.components.ui.Photo#sequence-playing
77
+ * @fires Panoramax.components.ui.Photo#sequence-stopped
78
+ * @fires Panoramax.components.ui.Photo#pictures-navigation-changed
79
+ * @fires Panoramax.components.ui.Photo#ready
80
+ * @example
81
+ * const psv = new Panoramax.components.ui.Photo(viewer, psvNode, {transitionDuration: 500})
56
82
  */
57
83
  export default class Photo extends PSViewer {
58
84
  constructor(parent, container, options = {}) {
@@ -64,8 +90,8 @@ export default class Photo extends PSViewer {
64
90
  resolution: parent.isWidthSmall() ? 32 : 64,
65
91
  shouldGoFast: options.shouldGoFast,
66
92
  }],
67
- withCredentials: parent._options?.fetchOptions?.credentials == "include",
68
- requestHeaders: parent._options?.fetchOptions?.headers,
93
+ withCredentials: parent?.fetchOptions?.credentials == "include",
94
+ requestHeaders: parent?.fetchOptions?.headers,
69
95
  panorama: BASE_PANORAMA,
70
96
  lang: parent._t.psv,
71
97
  minFov: 5,
@@ -91,7 +117,8 @@ export default class Photo extends PSViewer {
91
117
  });
92
118
 
93
119
  this._parent = parent;
94
- container.classList.add("gvs-psv");
120
+ this._options = options;
121
+ container.classList.add("pnx-psv");
95
122
  this._shouldGoFast = options?.shouldGoFast || (() => false);
96
123
  this._transitionDuration = options?.transitionDuration || PSV_ANIM_DURATION;
97
124
  this._myVTour = this.getPlugin(VirtualTourPlugin);
@@ -99,6 +126,8 @@ export default class Photo extends PSViewer {
99
126
  this._myVTour.config.transitionOptions = this._psvNodeTransition.bind(this);
100
127
  this._clearArrows = this._myVTour.arrowsRenderer.clear.bind(this._myVTour.arrowsRenderer);
101
128
  this._myVTour.arrowsRenderer.clear = () => {};
129
+ this._sequencePlaying = false;
130
+ this._picturesNavigation = this._options.picturesNavigation || "any";
102
131
 
103
132
  // Cache to find sequence ID for a single picture
104
133
  this._picturesSequences = {};
@@ -119,6 +148,11 @@ export default class Photo extends PSViewer {
119
148
  this.loader.thickness = 10;
120
149
  this.loader.canvas.setAttribute("viewBox", "0 0 150 150");
121
150
  this.loader.__updateContent();
151
+
152
+ // Handle initial parameters
153
+ if(this._options.position && !this._parent.picture) {
154
+ this.goToPosition(...this._options.position);
155
+ }
122
156
  }
123
157
 
124
158
  /**
@@ -127,20 +161,21 @@ export default class Photo extends PSViewer {
127
161
  * @private
128
162
  * @param {string} picId The picture UUID
129
163
  * @returns {Promise} Resolves on PSV node metadata
164
+ * @memberof Panoramax.components.ui.Photo#
130
165
  */
131
166
  async _getNodeFromAPI(picId) {
132
- if(!picId || picId === BASE_PANORAMA_ID) { return BASE_PANORAMA_NODE; }
167
+ if(isNullId(picId)) { return BASE_PANORAMA_NODE; }
133
168
 
134
169
  const picApiResponse = await fetch(
135
- this._parent._api.getPictureMetadataUrl(picId, this._picturesSequences[picId]),
136
- this._parent._api._getFetchOptions()
170
+ this._parent.api.getPictureMetadataUrl(picId, this._picturesSequences[picId]),
171
+ this._parent.api._getFetchOptions()
137
172
  );
138
173
  let metadata = await picApiResponse.json();
139
174
 
140
175
  if(metadata.features) { metadata = metadata.features.pop(); }
141
176
  if(!metadata || Object.keys(metadata).length === 0 || !picApiResponse.ok) {
142
- if(this._parent._loader) {
143
- this._parent._loader.dismiss(true, this._parent._t.gvs.error_pic);
177
+ if(this._parent.loader) {
178
+ this._parent.loader.dismiss(true, this._parent._t.pnx.error_pic);
144
179
  }
145
180
  throw new Error("Picture with ID " + picId + " was not found");
146
181
  }
@@ -150,7 +185,7 @@ export default class Photo extends PSViewer {
150
185
  metadata,
151
186
  this._parent._t,
152
187
  this._parent._isInternetFast,
153
- this._parent._picturesNavFilter?.bind(this._parent)
188
+ this._picturesNavFilter.bind(this)
154
189
  );
155
190
  if(node?.sequence?.prevPic) { this._picturesSequences[node?.sequence?.prevPic] = metadata.collection; }
156
191
  if(node?.sequence?.nextPic) { this._picturesSequences[node?.sequence?.nextPic] = metadata.collection; }
@@ -164,6 +199,7 @@ export default class Photo extends PSViewer {
164
199
  * @param {*} [fromNode] Currently shown node (previous)
165
200
  * @param {*} [fromLink] Link clicked by user to go from current to next node
166
201
  * @private
202
+ * @memberof Panoramax.components.ui.Photo#
167
203
  */
168
204
  _psvNodeTransition(toNode, fromNode, fromLink) {
169
205
  let nodeTransition = {};
@@ -174,14 +210,16 @@ export default class Photo extends PSViewer {
174
210
  const sameSequence = fromNode && toNode.sequence.id === fromNode.sequence.id;
175
211
  const fromNodeHeading = (fromNode?.properties?.["view:azimuth"] || 0) * (Math.PI / 180);
176
212
  const toNodeHeading = (toNode?.properties?.["view:azimuth"] || 0) * (Math.PI / 180);
213
+ const toNodeRelHeading = getRelativeHeading(toNode) * (Math.PI / 180);
177
214
 
178
215
  this.setOption("maxFov", Math.min(toNode.horizontalFov * 3/4, 90));
179
216
 
180
- const centerNoAnim = {
217
+ const forwardNoAnim = {
218
+ showLoader: false,
219
+ effect: "none",
181
220
  speed: 0,
182
- fadeIn: false,
183
221
  rotation: false,
184
- rotateTo: { pitch: 0, yaw: 0 },
222
+ rotateTo: { pitch: 0, yaw: -toNodeRelHeading },
185
223
  zoomTo: PSV_DEFAULT_ZOOM
186
224
  };
187
225
 
@@ -189,19 +227,19 @@ export default class Photo extends PSViewer {
189
227
  if(toNode.horizontalFov == 360) {
190
228
  // No previous sequence -> Point to center + no animation
191
229
  if(!fromNode) {
192
- nodeTransition = centerNoAnim;
230
+ nodeTransition = forwardNoAnim;
193
231
  }
194
232
  // Has a previous sequence
195
233
  else {
196
234
  // Far away sequences -> Point to center + no animation
197
235
  if(getDistance(fromNode.gps, toNode.gps) >= 0.001) {
198
- nodeTransition = centerNoAnim;
236
+ nodeTransition = forwardNoAnim;
199
237
  }
200
238
  // Nearby sequences -> Keep orientation
201
239
  else {
202
240
  nodeTransition = {
203
241
  speed: animationDuration,
204
- fadeIn: following && animated,
242
+ effect: following && animated ? "fade" : "none",
205
243
  rotation: following && sameSequence && animated,
206
244
  rotateTo: this.getPosition()
207
245
  };
@@ -220,7 +258,7 @@ export default class Photo extends PSViewer {
220
258
  const notTooMuchRotation = Math.abs(fromNodeHeading - toNodeHeading) <= Math.PI / 4;
221
259
  nodeTransition = {
222
260
  speed: animationDuration,
223
- fadeIn: following && notTooMuchRotation && animated,
261
+ effect: following && notTooMuchRotation && animated ? "fade" : "none",
224
262
  rotation: following && notTooMuchRotation && animated,
225
263
  rotateTo: keepZoomPos ? this.getPosition() : { pitch: 0, yaw: 0 },
226
264
  zoomTo: keepZoomPos ? this.getZoomLevel() : PSV_DEFAULT_ZOOM,
@@ -228,11 +266,11 @@ export default class Photo extends PSViewer {
228
266
  }
229
267
  // Different sequence -> Point to center + no animation
230
268
  else {
231
- nodeTransition = centerNoAnim;
269
+ nodeTransition = forwardNoAnim;
232
270
  }
233
271
  }
234
272
 
235
- if(nodeTransition.fadeIn && nodeTransition.speed >= 150) {
273
+ if(nodeTransition.effect === "fade" && nodeTransition.speed >= 150) {
236
274
  setTimeout(this._clearArrows, nodeTransition.speed-100);
237
275
  }
238
276
  else {
@@ -243,18 +281,17 @@ export default class Photo extends PSViewer {
243
281
  /**
244
282
  * Event for picture starting to load
245
283
  *
246
- * @event psv:picture-loading
247
- * @memberof CoreView
248
- * @type {object}
249
- * @property {object} detail Event information
284
+ * @event Panoramax.components.ui.Photo#picture-loading
285
+ * @type {CustomEvent}
250
286
  * @property {string} detail.picId The picture unique identifier
251
287
  * @property {number} detail.lon Longitude (WGS84)
252
288
  * @property {number} detail.lat Latitude (WGS84)
253
289
  * @property {number} detail.x New x position (in degrees, 0-360), corresponds to heading (0° = North, 90° = East, 180° = South, 270° = West)
254
290
  * @property {number} detail.y New y position (in degrees)
255
291
  * @property {number} detail.z New z position (0-100)
292
+ * @property {boolean} detail.first True if first picture loaded
256
293
  */
257
- const event = new CustomEvent("psv:picture-loading", {
294
+ const event = new CustomEvent("picture-loading", {
258
295
  detail: {
259
296
  ...Object.assign({},
260
297
  this.getXYZ(),
@@ -263,10 +300,11 @@ export default class Photo extends PSViewer {
263
300
  ),
264
301
  picId: toNode.id,
265
302
  lon: toNode.gps[0],
266
- lat: toNode.gps[1]
303
+ lat: toNode.gps[1],
304
+ first: this._parent._initParams?.getParentPostInit().picture == toNode.id,
267
305
  }
268
306
  });
269
- this._parent.dispatchEvent(event);
307
+ this.dispatchEvent(event);
270
308
 
271
309
  return nodeTransition;
272
310
  }
@@ -276,6 +314,7 @@ export default class Photo extends PSViewer {
276
314
  * It creates a custom event "picture-preview-started"
277
315
  * @private
278
316
  * @param {object} e The event data
317
+ * @memberof Panoramax.components.ui.Photo#
279
318
  */
280
319
  _onEnterArrow(e) {
281
320
  const fromLink = e.link;
@@ -295,20 +334,18 @@ export default class Photo extends PSViewer {
295
334
  /**
296
335
  * Event for picture preview
297
336
  *
298
- * @event psv:picture-preview-started
299
- * @memberof CoreView
300
- * @type {object}
301
- * @property {object} detail Event information
337
+ * @event Panoramax.components.ui.Photo#picture-preview-started
338
+ * @type {CustomEvent}
302
339
  * @property {string} detail.picId The picture ID
303
340
  * @property {number[]} detail.coordinates [x,y] coordinates
304
341
  * @property {number} detail.direction The theorical picture orientation
305
342
  */
306
- const event = new CustomEvent("psv:picture-preview-started", { detail: {
343
+ const event = new CustomEvent("picture-preview-started", { detail: {
307
344
  picId: fromLink.nodeId,
308
345
  coordinates: fromLink.gps,
309
346
  direction,
310
347
  }});
311
- this._parent.dispatchEvent(event);
348
+ this.dispatchEvent(event);
312
349
  }
313
350
 
314
351
  /**
@@ -316,47 +353,44 @@ export default class Photo extends PSViewer {
316
353
  * It creates a custom event "picture-preview-stopped"
317
354
  * @private
318
355
  * @param {object} e The event data
356
+ * @memberof Panoramax.components.ui.Photo#
319
357
  */
320
358
  _onLeaveArrow(e) {
321
359
  const fromLink = e.link;
322
360
 
323
361
  /**
324
362
  * Event for end of picture preview
325
- *
326
- * @event psv:picture-preview-stopped
327
- * @memberof CoreView
328
- * @type {object}
329
- * @property {object} detail Event information
363
+ * @event Panoramax.components.ui.Photo#picture-preview-stopped
364
+ * @type {CustomEvent}
330
365
  * @property {string} detail.picId The picture ID
331
366
  */
332
- const event = new CustomEvent("psv:picture-preview-stopped", { detail: {
367
+ const event = new CustomEvent("picture-preview-stopped", { detail: {
333
368
  picId: fromLink.nodeId,
334
369
  }});
335
- this._parent.dispatchEvent(event);
370
+ this.dispatchEvent(event);
336
371
  }
337
372
 
338
373
  /**
339
374
  * Event handler for position update in PSV.
340
375
  * Allows to send a custom "view-rotated" event.
341
376
  * @private
377
+ * @memberof Panoramax.components.ui.Photo#
342
378
  */
343
379
  _onPositionUpdated({position}) {
344
380
  const pos = positionToXYZ(position, this.getZoomLevel());
345
381
  pos.x += this.getPictureOriginalHeading();
346
382
  pos.x = pos.x % 360;
383
+
347
384
  /**
348
385
  * Event for viewer rotation
349
- *
350
- * @event psv:view-rotated
351
- * @memberof CoreView
352
- * @type {object}
353
- * @property {object} detail Event information
386
+ * @event Panoramax.components.ui.Photo#view-rotated
387
+ * @type {CustomEvent}
354
388
  * @property {number} detail.x New x position (in degrees, 0-360), corresponds to heading (0° = North, 90° = East, 180° = South, 270° = West)
355
389
  * @property {number} detail.y New y position (in degrees)
356
390
  * @property {number} detail.z New Z position (between 0 and 100)
357
391
  */
358
- const event = new CustomEvent("psv:view-rotated", { detail: pos });
359
- this._parent.dispatchEvent(event);
392
+ const event = new CustomEvent("view-rotated", { detail: pos });
393
+ this.dispatchEvent(event);
360
394
 
361
395
  this._onTilesStartLoading();
362
396
  }
@@ -365,57 +399,59 @@ export default class Photo extends PSViewer {
365
399
  * Event handler for zoom updates in PSV.
366
400
  * Allows to send a custom "view-rotated" event.
367
401
  * @private
402
+ * @memberof Panoramax.components.ui.Photo#
368
403
  */
369
404
  _onZoomUpdated({zoomLevel}) {
370
- const event = new CustomEvent("psv:view-rotated", { detail: { ...this.getXY(), z: zoomLevel} });
371
- this._parent.dispatchEvent(event);
405
+ const event = new CustomEvent("view-rotated", { detail: { ...this.getXY(), z: zoomLevel} });
406
+ this.dispatchEvent(event);
372
407
 
373
408
  this._onTilesStartLoading();
374
409
  }
375
410
 
376
411
  /**
377
412
  * Event handler for node change in PSV.
378
- * Allows to send a custom "psv:picture-loaded" event.
413
+ * Allows to send a custom "picture-loaded" event.
379
414
  * @private
415
+ * @memberof Panoramax.components.ui.Photo#
380
416
  */
381
417
  _onNodeChanged(e) {
382
418
  // Clean up clicked arrows
383
- for(let d of document.getElementsByClassName("gvs-psv-tour-arrows")) {
384
- d.classList.remove("gvs-clicked");
419
+ for(let d of document.getElementsByClassName("pnx-psv-tour-arrows")) {
420
+ d.classList.remove("pnx-clicked");
385
421
  }
386
422
 
387
423
  if(e.node.id) {
424
+ const isFirst = this._parent._initParams?.getParentPostInit().picture == e.node.id;
388
425
  this._parent.select(e.node?.sequence?.id, e.node.id);
389
426
  const picMeta = this.getPictureMetadata();
390
427
  if(!picMeta) {
391
- this._parent.dispatchEvent(new CustomEvent("psv:picture-loaded", {detail: {}}));
428
+ this.dispatchEvent(new CustomEvent("picture-loaded", {detail: {}}));
392
429
  return;
393
430
  }
394
431
  this._prevSequence = picMeta.sequence.id;
395
432
 
396
433
  /**
397
434
  * Event for picture load (low-resolution image is loaded)
398
- *
399
- * @event psv:picture-loaded
400
- * @memberof CoreView
401
- * @type {object}
402
- * @property {object} detail Event information
435
+ * @event Panoramax.components.ui.Photo#picture-loaded
436
+ * @type {CustomEvent}
403
437
  * @property {string} detail.picId The picture unique identifier
404
438
  * @property {number} detail.lon Longitude (WGS84)
405
439
  * @property {number} detail.lat Latitude (WGS84)
406
440
  * @property {number} detail.x New x position (in degrees, 0-360), corresponds to heading (0° = North, 90° = East, 180° = South, 270° = West)
407
441
  * @property {number} detail.y New y position (in degrees)
408
442
  * @property {number} detail.z New z position (0-100)
443
+ * @property {boolean} detail.first True if first picture loaded
409
444
  */
410
- const event = new CustomEvent("psv:picture-loaded", {
445
+ const event = new CustomEvent("picture-loaded", {
411
446
  detail: {
412
447
  ...this.getXYZ(),
413
448
  picId: e.node.id,
414
449
  lon: picMeta.gps[0],
415
- lat: picMeta.gps[1]
416
- }
450
+ lat: picMeta.gps[1],
451
+ first: isFirst
452
+ },
417
453
  });
418
- this._parent.dispatchEvent(event);
454
+ this.dispatchEvent(event);
419
455
 
420
456
  // Change download URL
421
457
  if(picMeta.panorama.hdUrl) {
@@ -432,7 +468,7 @@ export default class Photo extends PSViewer {
432
468
 
433
469
  /**
434
470
  * Event handler for loading a new range of tiles
435
- *
471
+ * @memberof Panoramax.components.ui.Photo#
436
472
  * @private
437
473
  */
438
474
  _onTilesStartLoading() {
@@ -445,15 +481,12 @@ export default class Photo extends PSViewer {
445
481
  if(this._myVTour.state.currentNode) {
446
482
  /**
447
483
  * Event launched when all visible tiles of a picture are loaded
448
- *
449
- * @event psv:picture-tiles-loaded
450
- * @memberof CoreView
451
- * @type {object}
452
- * @property {object} detail Event information
484
+ * @event Panoramax.components.ui.Photo#picture-tiles-loaded
485
+ * @type {CustomEvent}
453
486
  * @property {string} detail.picId The picture unique identifier
454
487
  */
455
- const event = new Event("psv:picture-tiles-loaded", { picId: this._myVTour.state.currentNode.id });
456
- this._parent.dispatchEvent(event);
488
+ const event = new CustomEvent("picture-tiles-loaded", { detail: { picId: this._myVTour.state.currentNode.id }});
489
+ this.dispatchEvent(event);
457
490
  }
458
491
  clearInterval(this._tilesQueueTimer);
459
492
  delete this._tilesQueueTimer;
@@ -463,17 +496,28 @@ export default class Photo extends PSViewer {
463
496
 
464
497
  /**
465
498
  * Access currently shown picture metadata
466
- *
499
+ * @memberof Panoramax.components.ui.Photo#
467
500
  * @returns {object} Picture metadata
468
501
  */
469
502
  getPictureMetadata() {
470
- if(this._myVTour?.state?.currentNode?.id === BASE_PANORAMA_ID) { return null; }
503
+ if(isNullId(this._myVTour?.state?.currentNode?.id)) { return null; }
471
504
  return this._myVTour.state.currentNode ? Object.assign({}, this._myVTour.state.currentNode) : null;
472
505
  }
473
506
 
507
+ /**
508
+ * Get current picture ID, or loading picture ID if any.
509
+ * @memberof Panoramax.components.ui.Photo#
510
+ * @returns {string|null} Picture ID (current or loading), or null if none is selected.
511
+ */
512
+ getPictureId() {
513
+ const id = this._myVTour?.state?.loadingNode || this._myVTour?.state?.currentNode?.id;
514
+ return isNullId(id) ? null : id;
515
+ }
516
+
474
517
  /**
475
518
  * Handler for select event.
476
519
  * @private
520
+ * @memberof Panoramax.components.ui.Photo#
477
521
  */
478
522
  _onSelect(e) {
479
523
  if(e.detail.seqId) {
@@ -483,13 +527,15 @@ export default class Photo extends PSViewer {
483
527
  if(this._myVTour.getCurrentNode()?.id !== e.detail.picId) {
484
528
  this.loader.show();
485
529
  this._myVTour.setCurrentNode(e.detail.picId).catch(e => {
486
- this.showErrorOverlay(e, this._parent._t.gvs.error_pic, true);
530
+ this.showErrorOverlay(e, this._parent._t.pnx.error_pic, true);
487
531
  });
488
532
  }
489
533
  }
490
534
 
491
535
  /**
492
536
  * Displays next picture in current sequence (if any)
537
+ * @memberof Panoramax.components.ui.Photo#
538
+ * @throws {Error} If no picture is selected, or no next picture available
493
539
  */
494
540
  goToNextPicture() {
495
541
  if(!this.getPictureMetadata()) {
@@ -507,6 +553,8 @@ export default class Photo extends PSViewer {
507
553
 
508
554
  /**
509
555
  * Displays previous picture in current sequence (if any)
556
+ * @memberof Panoramax.components.ui.Photo#
557
+ * @throws {Error} If no picture is selected, or no previous picture available
510
558
  */
511
559
  goToPrevPicture() {
512
560
  if(!this.getPictureMetadata()) {
@@ -524,13 +572,15 @@ export default class Photo extends PSViewer {
524
572
 
525
573
  /**
526
574
  * Displays in viewer a picture near to given coordinates
527
- *
575
+ * @memberof Panoramax.components.ui.Photo#
528
576
  * @param {number} lat Latitude (WGS84)
529
577
  * @param {number} lon Longitude (WGS84)
530
- * @returns {Promise} Resolves on picture ID if picture found, otherwise rejects
578
+ * @returns {Promise}
579
+ * @fulfil {string} Picture ID if picture found
580
+ * @reject {Error} If no picture found
531
581
  */
532
582
  async goToPosition(lat, lon) {
533
- return this._parent._api.getPicturesAroundCoordinates(lat, lon)
583
+ return this._parent.api.getPicturesAroundCoordinates(lat, lon)
534
584
  .then(res => {
535
585
  if(res.features.length > 0) {
536
586
  const f = res.features.pop();
@@ -548,7 +598,7 @@ export default class Photo extends PSViewer {
548
598
 
549
599
  /**
550
600
  * Get 2D position of sphere currently shown to user
551
- *
601
+ * @memberof Panoramax.components.ui.Photo#
552
602
  * @returns {object} Position in format { x: heading in degrees (0° = North, 90° = East, 180° = South, 270° = West), y: top/bottom position in degrees (-90° = bottom, 0° = front, 90° = top) }
553
603
  */
554
604
  getXY() {
@@ -559,7 +609,7 @@ export default class Photo extends PSViewer {
559
609
 
560
610
  /**
561
611
  * Get 3D position of sphere currently shown to user
562
- *
612
+ * @memberof Panoramax.components.ui.Photo#
563
613
  * @returns {object} Position in format { x: heading in degrees (0° = North, 90° = East, 180° = South, 270° = West), y: top/bottom position in degrees (-90° = bottom, 0° = front, 90° = top), z: zoom (0 = wide, 100 = zoomed in) }
564
614
  */
565
615
  getXYZ() {
@@ -570,7 +620,8 @@ export default class Photo extends PSViewer {
570
620
 
571
621
  /**
572
622
  * Get capture orientation of current picture, based on its GPS.
573
- * @returns Picture original heading in degrees (0 to 360°)
623
+ * @returns {number} Picture original heading in degrees (0 to 360°)
624
+ * @memberof Panoramax.components.ui.Photo#
574
625
  */
575
626
  getPictureOriginalHeading() {
576
627
  return this.getPictureMetadata()?.properties?.["view:azimuth"] || 0;
@@ -579,8 +630,8 @@ export default class Photo extends PSViewer {
579
630
  /**
580
631
  * Computes the relative heading of currently selected picture.
581
632
  * This gives the angle of capture compared to sequence path (vehicle movement).
582
- *
583
- * @returns Relative heading in degrees (-180 to 180)
633
+ * @memberof Panoramax.components.ui.Photo#
634
+ * @returns {number} Relative heading in degrees (-180 to 180)
584
635
  */
585
636
  getPictureRelativeHeading() {
586
637
  return getRelativeHeading(this.getPictureMetadata());
@@ -589,6 +640,7 @@ export default class Photo extends PSViewer {
589
640
  /**
590
641
  * Clears the Photo Sphere Viewer metadata cache.
591
642
  * It is useful when current picture or sequence has changed server-side after first load.
643
+ * @memberof Panoramax.components.ui.Photo#
592
644
  */
593
645
  clearPictureMetadataCache() {
594
646
  const oldPicId = this.getPictureMetadata()?.id;
@@ -609,7 +661,7 @@ export default class Photo extends PSViewer {
609
661
 
610
662
  /**
611
663
  * Change the shown position in picture
612
- *
664
+ * @memberof Panoramax.components.ui.Photo#
613
665
  * @param {number} x X position (in degrees)
614
666
  * @param {number} y Y position (in degrees)
615
667
  * @param {number} z Z position (0-100)
@@ -623,6 +675,7 @@ export default class Photo extends PSViewer {
623
675
  /**
624
676
  * Enable or disable higher contrast on picture
625
677
  * @param {boolean} enable True to enable higher contrast
678
+ * @memberof Panoramax.components.ui.Photo#
626
679
  */
627
680
  setHigherContrast(enable) {
628
681
  this.renderer.renderer.toneMapping = enable ? 3 : 0;
@@ -633,6 +686,7 @@ export default class Photo extends PSViewer {
633
686
  /**
634
687
  * Get the duration of stay on a picture during a sequence play.
635
688
  * @returns {number} The duration (in milliseconds)
689
+ * @memberof Panoramax.components.ui.Photo#
636
690
  */
637
691
  getTransitionDuration() {
638
692
  return this._transitionDuration;
@@ -640,7 +694,7 @@ export default class Photo extends PSViewer {
640
694
 
641
695
  /**
642
696
  * Changes the duration of stay on a picture during a sequence play.
643
- *
697
+ * @memberof Panoramax.components.ui.Photo#
644
698
  * @param {number} value The new duration (in milliseconds, between 100 and 3000)
645
699
  */
646
700
  setTransitionDuration(value) {
@@ -652,19 +706,17 @@ export default class Photo extends PSViewer {
652
706
 
653
707
  /**
654
708
  * Event for transition duration change
655
- *
656
- * @event psv:transition-duration-changed
657
- * @memberof CoreView
658
- * @type {object}
659
- * @property {object} detail Event information
709
+ * @event Panoramax.components.ui.Photo#transition-duration-changed
710
+ * @type {CustomEvent}
660
711
  * @property {string} detail.duration New duration (in milliseconds)
661
712
  */
662
- const event = new CustomEvent("psv:transition-duration-changed", { detail: { value } });
663
- this._parent.dispatchEvent(event);
713
+ const event = new CustomEvent("transition-duration-changed", { detail: { value } });
714
+ this.dispatchEvent(event);
664
715
  }
665
716
 
717
+ /** @private */
666
718
  setPanorama(path, options) {
667
- const onFailure = e => this.showErrorOverlay(e, this._parent._t.gvs.error_pic, true);
719
+ const onFailure = e => this.showErrorOverlay(e, this._parent?._t.pnx.error_pic, true);
668
720
  try {
669
721
  return super.setPanorama(path, options).catch(onFailure);
670
722
  }
@@ -678,14 +730,15 @@ export default class Photo extends PSViewer {
678
730
  * @param {object} e The initial error
679
731
  * @param {str} label The main error label to display
680
732
  * @param {boolean} dissmisable Is error dissmisable
733
+ * @memberof Panoramax.components.ui.Photo#
681
734
  */
682
735
  showErrorOverlay(e, label, dissmisable) {
683
- if(this._parent._loader.isVisible() || !this.overlay.isVisible()) {
684
- this._parent._loader.dismiss(
736
+ if(this._parent?.loader.isVisible() || !this.overlay.isVisible()) {
737
+ this._parent?.loader.dismiss(
685
738
  e,
686
739
  label,
687
740
  dissmisable ? () => {
688
- this._parent._loader.dismiss();
741
+ this._parent?.loader.dismiss();
689
742
  this.overlay.hide();
690
743
  } : undefined
691
744
  );
@@ -694,10 +747,169 @@ export default class Photo extends PSViewer {
694
747
  console.error(e);
695
748
  this.overlay.show({
696
749
  image: `<img style="width: 200px" src="${LogoDead}" alt="" />`,
697
- title: this._parent._t.gvs.error,
698
- text: label + "<br />" + this._parent._t.gvs.error_click,
750
+ title: this._parent?._t.pnx.error,
751
+ text: label + "<br />" + this._parent?._t.pnx.error_click,
699
752
  dissmisable,
700
753
  });
701
754
  }
702
755
  }
756
+
757
+ /**
758
+ * Goes continuously to next picture in sequence as long as possible
759
+ * @memberof Panoramax.components.ui.Photo#
760
+ */
761
+ playSequence() {
762
+ this._sequencePlaying = true;
763
+
764
+ /**
765
+ * Event for sequence starting to play
766
+ * @event Panoramax.components.ui.Photo#sequence-playing
767
+ * @type {CustomEvent}
768
+ */
769
+ const event = new Event("sequence-playing", {bubbles: true, composed: true});
770
+ this.dispatchEvent(event);
771
+
772
+ const nextPicturePlay = () => {
773
+ if(this._sequencePlaying) {
774
+ this.addEventListener("picture-loaded", () => {
775
+ this._playTimer = setTimeout(() => {
776
+ nextPicturePlay();
777
+ }, this.getTransitionDuration());
778
+ }, { once: true });
779
+
780
+ try {
781
+ this.goToNextPicture();
782
+ }
783
+ catch(e) {
784
+ this.stopSequence();
785
+ }
786
+ }
787
+ };
788
+
789
+ // Stop playing if user clicks on image
790
+ this.addEventListener("click", () => this.stopSequence());
791
+
792
+ nextPicturePlay();
793
+ }
794
+
795
+ /**
796
+ * Stops playing current sequence
797
+ * @memberof Panoramax.components.ui.Photo#
798
+ */
799
+ stopSequence() {
800
+ this._sequencePlaying = false;
801
+
802
+ // Next picture timer is pending
803
+ if(this._playTimer) {
804
+ clearTimeout(this._playTimer);
805
+ delete this._playTimer;
806
+ }
807
+
808
+ // Force refresh of PSV to eventually load tiles
809
+ this.forceRefresh();
810
+
811
+ /**
812
+ * Event for sequence stopped playing
813
+ * @event Panoramax.components.ui.Photo#sequence-stopped
814
+ * @type {CustomEvent}
815
+ */
816
+ const event = new Event("sequence-stopped", {bubbles: true, composed: true});
817
+ this.dispatchEvent(event);
818
+ }
819
+
820
+ /**
821
+ * Is there any sequence being played right now ?
822
+ * @memberof Panoramax.components.ui.Photo#
823
+ * @returns {boolean} True if sequence is playing
824
+ */
825
+ isSequencePlaying() {
826
+ return this._sequencePlaying;
827
+ }
828
+
829
+ /**
830
+ * Starts/stops the reading of pictures in a sequence
831
+ * @memberof Panoramax.components.ui.Photo#
832
+ */
833
+ toggleSequencePlaying() {
834
+ if(this.isSequencePlaying()) {
835
+ this.stopSequence();
836
+ }
837
+ else {
838
+ this.playSequence();
839
+ }
840
+ }
841
+
842
+ /**
843
+ * Get current pictures navigation mode.
844
+ * @returns {string} The picture navigation mode ("any": no restriction, "seq": only pictures in same sequence, "pic": only selected picture)
845
+ * @memberof Panoramax.components.ui.Photo#
846
+ */
847
+ getPicturesNavigation() {
848
+ return this._picturesNavigation;
849
+ }
850
+
851
+ /**
852
+ * Switch the allowed navigation between pictures.
853
+ * @param {string} pn The picture navigation mode ("any": no restriction, "seq": only pictures in same sequence, "pic": only selected picture)
854
+ * @memberof Panoramax.components.ui.Photo#
855
+ */
856
+ setPicturesNavigation(pn) {
857
+ if(pn === "none") { pn = "pic"; }
858
+ this._picturesNavigation = pn;
859
+
860
+ /**
861
+ * Event for pictures navigation mode change
862
+ * @event Panoramax.components.ui.Photo#pictures-navigation-changed
863
+ * @type {CustomEvent}
864
+ * @property {string} detail.value New mode (any, pic, seq)
865
+ */
866
+ const event = new CustomEvent("pictures-navigation-changed", { detail: { value: pn } });
867
+ this.dispatchEvent(event);
868
+ }
869
+
870
+ /**
871
+ * Filter function
872
+ * @param {object} link A STAC next/prev/related link definition
873
+ * @returns {boolean} True if link should be kept
874
+ * @private
875
+ */
876
+ _picturesNavFilter(link) {
877
+ switch(this._picturesNavigation) {
878
+ case "seq":
879
+ return ["next", "prev"].includes(link.rel);
880
+ case "pic":
881
+ case "none":
882
+ return false;
883
+ case "any":
884
+ default:
885
+ return true;
886
+ }
887
+ }
888
+
889
+ /**
890
+ * Force reload of texture and tiles.
891
+ * @memberof Panoramax.components.ui.Photo#
892
+ */
893
+ forceRefresh() {
894
+ const cn = this._myVTour.getCurrentNode();
895
+
896
+ // Refresh mode for flat pictures
897
+ if(cn && cn.panorama.baseUrl !== cn?.panorama?.origBaseUrl) {
898
+ const prevZoom = this.getZoomLevel();
899
+ const prevPos = this.getPosition();
900
+ this._myVTour.state.currentNode = null;
901
+ this._myVTour.setCurrentNode(cn.id, {
902
+ zoomTo: prevZoom,
903
+ rotateTo: prevPos,
904
+ fadeIn: false,
905
+ speed: 0,
906
+ rotation: false,
907
+ });
908
+ }
909
+
910
+ // Refresh mode for 360 pictures
911
+ if(cn && cn.panorama.rows > 1) {
912
+ this.adapter.__refresh();
913
+ }
914
+ }
703
915
  }