@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,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
- }