@panoramax/web-viewer 3.2.3-develop-f219e404 → 3.2.3-develop-6257391e

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 (221) hide show
  1. package/.gitlab-ci.yml +3 -0
  2. package/CHANGELOG.md +19 -0
  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 +2 -2
  7. package/build/index.css.map +1 -1
  8. package/build/index.html +1 -1
  9. package/build/index.js +1682 -5
  10. package/build/index.js.map +1 -1
  11. package/build/map.html +1 -1
  12. package/build/viewer.html +10 -1
  13. package/build/widgets.html +1 -0
  14. package/config/jest/mocks.js +172 -0
  15. package/config/paths.js +1 -0
  16. package/config/webpack.config.js +26 -0
  17. package/docs/03_URL_settings.md +3 -11
  18. package/docs/05_Compatibility.md +59 -76
  19. package/docs/09_Develop.md +30 -11
  20. package/docs/90_Releases.md +2 -2
  21. package/docs/images/class_diagram.drawio +28 -28
  22. package/docs/images/class_diagram.jpg +0 -0
  23. package/docs/index.md +112 -0
  24. package/docs/reference/components/core/Basic.md +153 -0
  25. package/docs/reference/components/core/CoverageMap.md +160 -0
  26. package/docs/reference/components/core/Editor.md +172 -0
  27. package/docs/reference/components/core/Viewer.md +288 -0
  28. package/docs/reference/components/layout/CorneredGrid.md +29 -0
  29. package/docs/reference/components/layout/Mini.md +45 -0
  30. package/docs/reference/components/menus/MapBackground.md +32 -0
  31. package/docs/reference/components/menus/MapFilters.md +15 -0
  32. package/docs/reference/components/menus/MapLayers.md +15 -0
  33. package/docs/reference/components/menus/MapLegend.md +15 -0
  34. package/docs/reference/components/menus/PictureLegend.md +15 -0
  35. package/docs/reference/components/menus/PictureMetadata.md +15 -0
  36. package/docs/reference/components/menus/PlayerOptions.md +15 -0
  37. package/docs/reference/components/menus/QualityScoreDoc.md +15 -0
  38. package/docs/reference/components/menus/ReportForm.md +15 -0
  39. package/docs/reference/components/menus/ShareMenu.md +15 -0
  40. package/docs/reference/components/ui/Button.md +39 -0
  41. package/docs/reference/components/ui/ButtonGroup.md +36 -0
  42. package/docs/reference/components/ui/CopyButton.md +35 -0
  43. package/docs/reference/components/ui/Grade.md +32 -0
  44. package/docs/reference/components/ui/LinkButton.md +44 -0
  45. package/docs/reference/components/ui/Loader.md +54 -0
  46. package/docs/reference/components/ui/Map.md +214 -0
  47. package/docs/reference/components/ui/MapMore.md +233 -0
  48. package/docs/reference/components/ui/Photo.md +369 -0
  49. package/docs/reference/components/ui/Popup.md +56 -0
  50. package/docs/reference/components/ui/QualityScore.md +45 -0
  51. package/docs/reference/components/ui/SearchBar.md +63 -0
  52. package/docs/reference/components/ui/TogglableGroup.md +39 -0
  53. package/docs/reference/components/ui/widgets/GeoSearch.md +32 -0
  54. package/docs/reference/components/ui/widgets/Legend.md +32 -0
  55. package/docs/reference/components/ui/widgets/MapFiltersButton.md +33 -0
  56. package/docs/reference/components/ui/widgets/MapLayersButton.md +15 -0
  57. package/docs/reference/components/ui/widgets/Player.md +32 -0
  58. package/docs/reference/components/ui/widgets/Share.md +15 -0
  59. package/docs/reference/components/ui/widgets/Zoom.md +15 -0
  60. package/docs/reference/utils/API.md +311 -0
  61. package/docs/reference/utils/InitParameters.md +67 -0
  62. package/docs/reference/utils/URLHandler.md +102 -0
  63. package/docs/reference.md +73 -0
  64. package/docs/shortcuts.md +11 -0
  65. package/docs/tutorials/aerial_imagery.md +19 -0
  66. package/docs/tutorials/authentication.md +10 -0
  67. package/docs/tutorials/custom_widgets.md +64 -0
  68. package/docs/tutorials/map_style.md +27 -0
  69. package/docs/tutorials/migrate_v4.md +122 -0
  70. package/docs/tutorials/synced_coverage.md +42 -0
  71. package/mkdocs.yml +60 -5
  72. package/package.json +10 -7
  73. package/public/editor.html +21 -29
  74. package/public/index.html +3 -3
  75. package/public/map.html +19 -18
  76. package/public/viewer.html +18 -24
  77. package/public/widgets.html +265 -0
  78. package/scripts/doc.js +77 -0
  79. package/src/components/core/Basic.css +44 -0
  80. package/src/components/core/Basic.js +258 -0
  81. package/src/components/core/CoverageMap.css +9 -0
  82. package/src/components/core/CoverageMap.js +105 -0
  83. package/src/components/core/Editor.css +23 -0
  84. package/src/components/core/Editor.js +354 -0
  85. package/src/components/core/Viewer.css +109 -0
  86. package/src/components/core/Viewer.js +707 -0
  87. package/src/components/core/index.js +11 -0
  88. package/src/components/index.js +13 -0
  89. package/src/components/layout/CorneredGrid.js +109 -0
  90. package/src/components/layout/Mini.js +117 -0
  91. package/src/components/layout/index.js +7 -0
  92. package/src/components/menus/MapBackground.js +106 -0
  93. package/src/components/menus/MapFilters.js +386 -0
  94. package/src/components/menus/MapLayers.js +143 -0
  95. package/src/components/menus/MapLegend.js +54 -0
  96. package/src/components/menus/PictureLegend.js +103 -0
  97. package/src/components/menus/PictureMetadata.js +188 -0
  98. package/src/components/menus/PlayerOptions.js +96 -0
  99. package/src/components/menus/QualityScoreDoc.js +36 -0
  100. package/src/components/menus/ReportForm.js +133 -0
  101. package/src/components/menus/Share.js +228 -0
  102. package/src/components/menus/index.js +15 -0
  103. package/src/components/styles.js +365 -0
  104. package/src/components/ui/Button.js +75 -0
  105. package/src/components/ui/ButtonGroup.css +49 -0
  106. package/src/components/ui/ButtonGroup.js +68 -0
  107. package/src/components/ui/CopyButton.js +71 -0
  108. package/src/components/ui/Grade.js +54 -0
  109. package/src/components/ui/LinkButton.js +68 -0
  110. package/src/components/ui/Loader.js +188 -0
  111. package/src/components/{Map.css → ui/Map.css} +5 -17
  112. package/src/components/{Map.js → ui/Map.js} +114 -138
  113. package/src/components/ui/MapMore.js +324 -0
  114. package/src/components/{Photo.css → ui/Photo.css} +6 -6
  115. package/src/components/{Photo.js → ui/Photo.js} +279 -90
  116. package/src/components/ui/Popup.js +145 -0
  117. package/src/components/ui/QualityScore.js +152 -0
  118. package/src/components/ui/SearchBar.js +363 -0
  119. package/src/components/ui/TogglableGroup.js +162 -0
  120. package/src/components/ui/index.js +20 -0
  121. package/src/components/ui/widgets/GeoSearch.css +21 -0
  122. package/src/components/ui/widgets/GeoSearch.js +139 -0
  123. package/src/components/ui/widgets/Legend.js +51 -0
  124. package/src/components/ui/widgets/MapFiltersButton.js +104 -0
  125. package/src/components/ui/widgets/MapLayersButton.js +79 -0
  126. package/src/components/ui/widgets/Player.css +7 -0
  127. package/src/components/ui/widgets/Player.js +148 -0
  128. package/src/components/ui/widgets/Share.js +30 -0
  129. package/src/components/ui/widgets/Zoom.js +82 -0
  130. package/src/components/ui/widgets/index.js +12 -0
  131. package/src/img/panoramax.svg +13 -0
  132. package/src/img/switch_big.svg +20 -10
  133. package/src/index.js +6 -9
  134. package/src/translations/da.json +1 -1
  135. package/src/translations/de.json +1 -1
  136. package/src/translations/en.json +5 -3
  137. package/src/translations/eo.json +1 -1
  138. package/src/translations/es.json +1 -1
  139. package/src/translations/fr.json +5 -3
  140. package/src/translations/hu.json +1 -1
  141. package/src/translations/it.json +1 -1
  142. package/src/translations/ja.json +1 -1
  143. package/src/translations/nl.json +1 -1
  144. package/src/translations/pl.json +1 -1
  145. package/src/translations/sv.json +33 -3
  146. package/src/translations/zh_Hant.json +1 -1
  147. package/src/utils/API.js +74 -42
  148. package/src/utils/InitParameters.js +354 -0
  149. package/src/utils/URLHandler.js +364 -0
  150. package/src/utils/geocoder.js +116 -0
  151. package/src/utils/{I18n.js → i18n.js} +3 -1
  152. package/src/utils/index.js +11 -0
  153. package/src/utils/{Map.js → map.js} +216 -80
  154. package/src/utils/picture.js +433 -0
  155. package/src/utils/utils.js +315 -0
  156. package/src/utils/widgets.js +93 -0
  157. package/tests/components/ui/CopyButton.test.js +52 -0
  158. package/tests/components/ui/Loader.test.js +54 -0
  159. package/tests/components/{Map.test.js → ui/Map.test.js} +19 -61
  160. package/tests/components/{Photo.test.js → ui/Photo.test.js} +89 -57
  161. package/tests/components/ui/Popup.test.js +24 -0
  162. package/tests/components/ui/QualityScore.test.js +17 -0
  163. package/tests/components/ui/SearchBar.test.js +107 -0
  164. package/tests/components/ui/__snapshots__/CopyButton.test.js.snap +34 -0
  165. package/tests/components/ui/__snapshots__/Loader.test.js.snap +56 -0
  166. package/tests/components/{__snapshots__ → ui/__snapshots__}/Map.test.js.snap +11 -38
  167. package/tests/components/{__snapshots__ → ui/__snapshots__}/Photo.test.js.snap +57 -4
  168. package/tests/components/ui/__snapshots__/Popup.test.js.snap +29 -0
  169. package/tests/components/ui/__snapshots__/QualityScore.test.js.snap +11 -0
  170. package/tests/components/ui/__snapshots__/SearchBar.test.js.snap +65 -0
  171. package/tests/utils/API.test.js +1 -14
  172. package/tests/utils/InitParameters.test.js +485 -0
  173. package/tests/utils/URLHandler.test.js +350 -0
  174. package/tests/utils/__snapshots__/URLHandler.test.js.snap +21 -0
  175. package/tests/utils/__snapshots__/picture.test.js.snap +315 -0
  176. package/tests/utils/__snapshots__/widgets.test.js.snap +19 -0
  177. package/tests/utils/geocoder.test.js +37 -0
  178. package/tests/utils/{I18n.test.js → i18n.test.js} +1 -1
  179. package/tests/utils/map.test.js +67 -0
  180. package/tests/utils/picture.test.js +745 -0
  181. package/tests/utils/utils.test.js +288 -0
  182. package/tests/utils/widgets.test.js +90 -0
  183. package/docs/01_Start.md +0 -149
  184. package/docs/02_Usage.md +0 -831
  185. package/docs/04_Advanced_examples.md +0 -216
  186. package/src/Editor.css +0 -37
  187. package/src/Editor.js +0 -361
  188. package/src/StandaloneMap.js +0 -114
  189. package/src/Viewer.css +0 -203
  190. package/src/Viewer.js +0 -1246
  191. package/src/components/CoreView.css +0 -70
  192. package/src/components/CoreView.js +0 -175
  193. package/src/components/Loader.css +0 -74
  194. package/src/components/Loader.js +0 -120
  195. package/src/utils/Exif.js +0 -193
  196. package/src/utils/Utils.js +0 -631
  197. package/src/utils/Widgets.js +0 -562
  198. package/src/viewer/URLHash.js +0 -469
  199. package/src/viewer/Widgets.css +0 -880
  200. package/src/viewer/Widgets.js +0 -1470
  201. package/tests/Editor.test.js +0 -126
  202. package/tests/StandaloneMap.test.js +0 -45
  203. package/tests/Viewer.test.js +0 -366
  204. package/tests/__snapshots__/Editor.test.js.snap +0 -298
  205. package/tests/__snapshots__/StandaloneMap.test.js.snap +0 -30
  206. package/tests/__snapshots__/Viewer.test.js.snap +0 -195
  207. package/tests/components/CoreView.test.js +0 -92
  208. package/tests/components/Loader.test.js +0 -38
  209. package/tests/components/__snapshots__/Loader.test.js.snap +0 -15
  210. package/tests/utils/Exif.test.js +0 -124
  211. package/tests/utils/Map.test.js +0 -113
  212. package/tests/utils/Utils.test.js +0 -300
  213. package/tests/utils/Widgets.test.js +0 -107
  214. package/tests/utils/__snapshots__/Exif.test.js.snap +0 -43
  215. package/tests/utils/__snapshots__/Utils.test.js.snap +0 -41
  216. package/tests/utils/__snapshots__/Widgets.test.js.snap +0 -44
  217. package/tests/viewer/URLHash.test.js +0 -559
  218. package/tests/viewer/Widgets.test.js +0 -127
  219. package/tests/viewer/__snapshots__/URLHash.test.js.snap +0 -108
  220. package/tests/viewer/__snapshots__/Widgets.test.js.snap +0 -403
  221. /package/tests/utils/__snapshots__/{Map.test.js.snap → geocoder.test.js.snap} +0 -0
@@ -1,469 +0,0 @@
1
- const MAP_FILTERS_JS2URL = {
2
- "minDate": "date_from",
3
- "maxDate": "date_to",
4
- "type": "pic_type",
5
- "camera": "camera",
6
- "theme": "theme",
7
- "qualityscore": "pic_score",
8
- };
9
- const MAP_FILTERS_URL2JS = Object.fromEntries(Object.entries(MAP_FILTERS_JS2URL).map(v => [v[1], v[0]]));
10
- const UPDATE_HASH_EVENTS = [
11
- "psv:view-rotated", "psv:picture-loaded", "focus-changed",
12
- "filters-changed", "psv:transition-duration-changed",
13
- "map:background-changed", "map:users-changed", "pictures-navigation-changed",
14
- ];
15
-
16
- /**
17
- * Updates the URL hash with various viewer information.
18
- * This doesn't handle the "map" parameter, which is managed by MapLibre GL JS
19
- *
20
- * Based on https://github.com/maplibre/maplibre-gl-js/blob/main/src/ui/hash.ts
21
- *
22
- * @returns {URLHash} `this`
23
- *
24
- * @private
25
- */
26
- export default class URLHash extends EventTarget {
27
- constructor(viewer) {
28
- super();
29
- this._viewer = viewer;
30
- this._delay = null;
31
- this._hashChangeHandler = this._onHashChange.bind(this);
32
-
33
- // Only start changing after first initial load
34
- // to avoid generating broken URL during load
35
- viewer.addEventListener("ready", () => {
36
- window.addEventListener("hashchange", this._hashChangeHandler, false);
37
- UPDATE_HASH_EVENTS.forEach(e => this._viewer.addEventListener(e, this._updateHash.bind(this)));
38
- }, { once: true });
39
- }
40
-
41
- /**
42
- * Ends all form of life in this object.
43
- */
44
- destroy() {
45
- window.removeEventListener("hashchange", this._hashChangeHandler);
46
- delete this._hashChangeHandler;
47
- this._viewer?.map?.off("moveend", this._updateHash);
48
- UPDATE_HASH_EVENTS.forEach(e => this._viewer.removeEventListener(e, this._updateHash));
49
- delete this._viewer;
50
- this._updateHash();
51
- }
52
-
53
- /**
54
- * Start listening to map movend event
55
- */
56
- bindMapEvents() {
57
- this._viewer.map.on("moveend", this._updateHash.bind(this));
58
- }
59
-
60
- /**
61
- * Compute next hash parts
62
- * @returns {object} Hash parameters
63
- * @private
64
- */
65
- _getHashParts() {
66
- let hashParts = {};
67
-
68
- if(typeof this._viewer.psv.getTransitionDuration() == "number") {
69
- hashParts.speed = this._viewer.psv.getTransitionDuration();
70
- }
71
-
72
- if(![null, "any"].includes(this._viewer.getPicturesNavigation())) {
73
- hashParts.nav = this._viewer.getPicturesNavigation();
74
- }
75
-
76
- const picMeta = this._viewer.psv.getPictureMetadata();
77
- if (picMeta) {
78
- hashParts.pic = picMeta.id;
79
- hashParts.xyz = this._getXyzHashString();
80
- }
81
-
82
- if(this._viewer.map) {
83
- hashParts.map = this._getMapHashString();
84
- hashParts.focus = "pic";
85
- if(this._viewer.isMapWide()) { hashParts.focus = "map"; }
86
- if(!this._viewer.popupContainer.classList.contains("gvs-hidden")) { hashParts.focus = "meta"; }
87
- if(this._viewer.map.hasTwoBackgrounds() && this._viewer.map.getBackground()) {
88
- hashParts.background = this._viewer.map.getBackground();
89
- }
90
-
91
- const vu = this._viewer.map.getVisibleUsers();
92
- if(vu.length > 1 || !vu.includes("geovisio")) {
93
- hashParts.users = vu.join(",");
94
- }
95
-
96
- if(this._viewer._mapFilters) {
97
- for(let k in MAP_FILTERS_JS2URL) {
98
- if(this._viewer._mapFilters[k]) {
99
- hashParts[MAP_FILTERS_JS2URL[k]] = this._viewer._mapFilters[k];
100
- }
101
- }
102
- if(hashParts.pic_score) {
103
- const mapping = [null, "E", "D", "C", "B", "A"];
104
- hashParts.pic_score = hashParts.pic_score.map(v => mapping[v]).join("");
105
- }
106
- }
107
- }
108
- else {
109
- hashParts.map = "none";
110
- }
111
- return hashParts;
112
- }
113
-
114
- /**
115
- * Get the hash string with current map/psv parameters
116
- * @return {string} The hash, starting with #
117
- */
118
- getHashString() {
119
- let hash = "";
120
-
121
- Object.entries(this._getHashParts())
122
- .sort((a,b) => a[0].localeCompare(b[0]))
123
- .forEach(entry => {
124
- let [ hashName, value ] = entry;
125
- let found = false;
126
- const parts = hash.split("&").map(part => {
127
- const key = part.split("=")[0];
128
- if (key === hashName) {
129
- found = true;
130
- return `${key}=${value}`;
131
- }
132
- return part;
133
- }).filter(a => a);
134
- if (!found) {
135
- parts.push(`${hashName}=${value}`);
136
- }
137
- hash = `${parts.join("&")}`;
138
- });
139
-
140
- return `#${hash}`.replace(/^#+/, "#");
141
- }
142
-
143
- /**
144
- * Transforms window.location.hash into key->value object
145
- * @return {object} Key-value read from hash
146
- * @private
147
- */
148
- _getCurrentHash() {
149
- // Get the current hash from location, stripped from its number sign
150
- const hash = window.location.hash.replace("#", "");
151
-
152
- // Split the parameter-styled hash into parts and find the value we need
153
- let keyvals = {};
154
- hash.split("&").map(
155
- part => part.split("=")
156
- )
157
- .filter(part => part[0] !== undefined && part[0].length > 0)
158
- .forEach(part => {
159
- keyvals[part[0]] = part[1];
160
- });
161
-
162
- // If hash is compressed
163
- if(keyvals.s) {
164
- const shortVals = Object.fromEntries(
165
- keyvals.s
166
- .split(";")
167
- .map(kv => [kv[0], kv.substring(1)])
168
- );
169
-
170
- keyvals = {};
171
-
172
- // Used letters: b c d e f k m n p q s t u v
173
- // Focus
174
- if(shortVals.f === "m") { keyvals.focus = "map"; }
175
- else if(shortVals.f === "p") { keyvals.focus = "pic"; }
176
- else if(shortVals.f === "t") { keyvals.focus = "meta"; }
177
-
178
- // Speed
179
- if(shortVals.s !== "") { keyvals.speed = parseFloat(shortVals.s) * 100; }
180
-
181
- // Nav
182
- if(shortVals.n === "a") { keyvals.nav = "any"; }
183
- else if(shortVals.n === "s") { keyvals.nav = "seq"; }
184
- if(shortVals.n === "n") { keyvals.nav = "none"; }
185
-
186
- // Pic
187
- if(shortVals.p !== "") { keyvals.pic = shortVals.p; }
188
-
189
- // XYZ
190
- if(shortVals.c !== "") { keyvals.xyz = shortVals.c; }
191
-
192
- // Map
193
- if(shortVals.m !== "") { keyvals.map = shortVals.m; }
194
-
195
- // Date
196
- if(shortVals.d !== "") { keyvals.date_from = shortVals.d; }
197
- if(shortVals.e !== "") { keyvals.date_to = shortVals.e; }
198
-
199
- // Pic type
200
- if(shortVals.t === "f") { keyvals.pic_type = "flat"; }
201
- else if(shortVals.t === "e") { keyvals.pic_type = "equirectangular"; }
202
-
203
- // Camera
204
- if(shortVals.k !== "") { keyvals.camera = shortVals.k; }
205
-
206
- // Theme
207
- if(shortVals.v === "d") { keyvals.theme = "default"; }
208
- else if(shortVals.v === "a") { keyvals.theme = "age"; }
209
- else if(shortVals.v === "t") { keyvals.theme = "type"; }
210
- else if(shortVals.v === "s") { keyvals.theme = "score"; }
211
-
212
- // Background
213
- if(shortVals.b === "s") { keyvals.background = "streets"; }
214
- else if(shortVals.b === "a") { keyvals.background = "aerial"; }
215
-
216
- // Users
217
- if(shortVals.u !== "") { keyvals.users = shortVals.u; }
218
-
219
- // Photoscore
220
- if(shortVals.q !== "") { keyvals.pic_score = shortVals.q; }
221
- }
222
-
223
- return keyvals;
224
- }
225
-
226
- /**
227
- * Get string representation of map position
228
- * @returns {string} zoom/lat/lon or zoom/lat/lon/bearing/pitch
229
- * @private
230
- */
231
- _getMapHashString() {
232
- const center = this._viewer.map.getCenter(),
233
- zoom = Math.round(this._viewer.map.getZoom() * 100) / 100,
234
- // derived from equation: 512px * 2^z / 360 / 10^d < 0.5px
235
- precision = Math.ceil((zoom * Math.LN2 + Math.log(512 / 360 / 0.5)) / Math.LN10),
236
- m = Math.pow(10, precision),
237
- lng = Math.round(center.lng * m) / m,
238
- lat = Math.round(center.lat * m) / m,
239
- bearing = this._viewer.map.getBearing(),
240
- pitch = this._viewer.map.getPitch();
241
- let hash = `${zoom}/${lat}/${lng}`;
242
-
243
- if (bearing || pitch) hash += (`/${Math.round(bearing * 10) / 10}`);
244
- if (pitch) hash += (`/${Math.round(pitch)}`);
245
-
246
- return hash;
247
- }
248
-
249
- /**
250
- * Get PSV view position as string
251
- * @returns {string} x/y/z
252
- * @private
253
- */
254
- _getXyzHashString() {
255
- const xyz = this._viewer.psv.getXYZ();
256
- const x = xyz.x.toFixed(2),
257
- y = xyz.y.toFixed(2),
258
- z = Math.round(xyz.z || 0);
259
- return `${x}/${y}/${z}`;
260
- }
261
-
262
- /**
263
- * Updates map and PSV according to current hash values
264
- * @private
265
- */
266
- _onHashChange() {
267
- let vals = this._getCurrentHash();
268
-
269
- // Restore selected picture
270
- if(vals.pic) {
271
- const picIds = vals.pic.split(";"); // Handle multiple IDs coming from OSM
272
- if(picIds.length > 1) {
273
- console.warn("Multiple picture IDs passed in URL, only first one kept");
274
- }
275
- this._viewer.select(null, picIds[0]);
276
- }
277
- else {
278
- this._viewer.select();
279
- }
280
-
281
- // Change focus
282
- if(vals.focus && ["map", "pic"].includes(vals.focus)) {
283
- this._viewer.setPopup(false);
284
- this._viewer.setFocus(vals.focus);
285
- }
286
- if(vals.focus && vals.focus == "meta") {
287
- this._viewer._widgets._showPictureMetadataPopup();
288
- }
289
-
290
- // Change speed
291
- if(vals.speed !== undefined) {
292
- this._viewer.psv.setTransitionDuration(vals.speed);
293
- }
294
-
295
- // Change map position & users
296
- if(vals.map && this._viewer.map) {
297
- const mapOpts = this.getMapOptionsFromHashString(vals.map);
298
- if(mapOpts) {
299
- this._viewer.map.jumpTo(mapOpts);
300
- }
301
-
302
- let vu = (vals.users || "").split(",");
303
- if(vu.length === 0 || (vu.length === 1 && vu[0].trim() === "")) { vu = ["geovisio"]; }
304
- this._viewer.map.setVisibleUsers(vu);
305
- }
306
-
307
- // Change xyz position
308
- if(vals.xyz) {
309
- const coords = this.getXyzOptionsFromHashString(vals.xyz);
310
- this._viewer.psv.setXYZ(coords.x, coords.y, coords.z);
311
- }
312
-
313
- // Change map filters
314
- this._viewer.setFilters(this.getMapFiltersFromHashVals(vals));
315
-
316
- // Change map background
317
- if(["aerial", "streets"].includes(vals.background)) {
318
- this._viewer.map.setBackground(vals.background);
319
- }
320
-
321
- // Change pictures navigation mode
322
- if(["pic", "any", "seq"].includes(vals.nav)) {
323
- this._viewer.setPicturesNavigation(vals.nav);
324
- }
325
- }
326
-
327
- /**
328
- * Get short link URL (hash replaced by Base64)
329
- * @returns {str} The short link URL
330
- */
331
- getShortLink(baseUrl) {
332
- const url = new URL(baseUrl);
333
- const hashParts = this._getHashParts();
334
- const shortVals = {
335
- f: (hashParts.focus || "").substring(0, 1),
336
- s: !isNaN(parseInt(hashParts.speed)) ? Math.floor(parseInt(hashParts.speed)/100) : undefined,
337
- n: (hashParts.nav || "").substring(0, 1),
338
- p: hashParts.pic,
339
- c: hashParts.xyz,
340
- m: hashParts.map,
341
- d: hashParts.date_from,
342
- e: hashParts.date_to,
343
- t: (hashParts.pic_type || "").substring(0, 1),
344
- k: hashParts.camera,
345
- v: (hashParts.theme || "").substring(0, 1),
346
- b: (hashParts.background || "").substring(0, 1),
347
- u: hashParts.users,
348
- q: hashParts.pic_score,
349
- };
350
- const short = Object.entries(shortVals)
351
- .filter(([,v]) => v != undefined && v != "")
352
- .map(([k,v]) => `${k}${v}`)
353
- .join(";");
354
- url.hash = `s=${short}`;
355
- return url;
356
- }
357
-
358
- /**
359
- * Extracts from hash parsed keys all map filters values
360
- * @param {*} vals Hash keys
361
- * @returns {object} Map filters
362
- */
363
- getMapFiltersFromHashVals(vals) {
364
- const newMapFilters = {};
365
- for(let k in MAP_FILTERS_URL2JS) {
366
- if(vals[k]) {
367
- newMapFilters[MAP_FILTERS_URL2JS[k]] = vals[k];
368
- }
369
- }
370
- if(newMapFilters.qualityscore) {
371
- let values = newMapFilters.qualityscore.split("");
372
- const mapping = {"A": 5, "B": 4, "C": 3, "D": 2, "E": 1};
373
- newMapFilters.qualityscore = values.map(v => mapping[v]);
374
- }
375
- return newMapFilters;
376
- }
377
-
378
- /**
379
- * Extracts from string map position
380
- * @param {string} str The map position as hash string
381
- * @returns {object} { center, zoom, pitch, bearing }
382
- */
383
- getMapOptionsFromHashString(str) {
384
- const loc = str.split("/");
385
- if (loc.length >= 3 && !loc.some(v => isNaN(v))) {
386
- const res = {
387
- center: [+loc[2], +loc[1]],
388
- zoom: +loc[0],
389
- pitch: +(loc[4] || 0)
390
- };
391
-
392
- if(this._viewer.map) {
393
- res.bearing = this._viewer.map.dragRotate.isEnabled() && this._viewer.map.touchZoomRotate.isEnabled() ? +(loc[3] || 0) : this._viewer.map.getBearing();
394
- }
395
-
396
- return res;
397
- }
398
- else { return null; }
399
- }
400
-
401
- /**
402
- * Extracts from string xyz position
403
- * @param {string} str The xyz position as hash string
404
- * @returns {object} { x, y, z }
405
- */
406
- getXyzOptionsFromHashString(str) {
407
- const loc = str.split("/");
408
- if (loc.length === 3 && !loc.some(v => isNaN(v))) {
409
- const res = {
410
- x: +loc[0],
411
- y: +loc[1],
412
- z: +loc[2]
413
- };
414
-
415
- return res;
416
- }
417
- else { return null; }
418
- }
419
-
420
- /**
421
- * Changes the URL hash using current viewer parameters
422
- * @private
423
- */
424
- _updateHash() {
425
- if(this._delay) {
426
- clearTimeout(this._delay);
427
- this._delay = null;
428
- }
429
-
430
- this._delay = setTimeout(() => {
431
- const prevUrl = new URL(window.location.href);
432
- const nextUrl = new URL(window.location.href);
433
- nextUrl.hash = this._viewer ? this.getHashString() : "";
434
-
435
- // Skip hash update if no changes
436
- if(prevUrl.hash == nextUrl.hash) { return; }
437
-
438
- const prevPic = this._getCurrentHash().pic || "";
439
- const nextPic = this._viewer?.psv?.getPictureMetadata()?.id || "";
440
-
441
- const prevFocus = this._getCurrentHash().focus || "";
442
- const nextFocus = nextUrl.hash.includes("focus=meta") ? "meta" : (nextUrl.hash.includes("focus=map") ? "map" : "pic");
443
-
444
- try {
445
- // If different pic, add entry in browser history
446
- if(prevPic != nextPic) {
447
- window.history.pushState(window.history.state, null, nextUrl.href);
448
- }
449
- // If metadata popup is open, come back to pic/map
450
- else if(prevFocus != nextFocus && nextFocus == "meta") {
451
- window.history.pushState(window.history.state, null, nextUrl.href);
452
- }
453
- // If same pic, just update viewer params
454
- else {
455
- window.history.replaceState(window.history.state, null, nextUrl.href);
456
- }
457
-
458
- if(this._viewer) {
459
- const event = new CustomEvent("url-changed", { detail: {url: nextUrl.href}});
460
- this.dispatchEvent(event);
461
- }
462
- } catch (SecurityError) {
463
- // IE11 does not allow this if the page is within an iframe created
464
- // with iframe.contentWindow.document.write(...).
465
- // https://github.com/mapbox/mapbox-gl-js/issues/7410
466
- }
467
- }, 500);
468
- }
469
- }