@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,11 +1,10 @@
1
- // DO NOT REMOVE THE "!": bundled builds breaks otherwise !!!
2
- import maplibregl from "!maplibre-gl";
3
1
  import LoaderImg from "../img/marker.svg";
4
- import { COLORS, QUALITYSCORE_RES_FLAT_VALUES, QUALITYSCORE_RES_360_VALUES, QUALITYSCORE_GPS_VALUES, QUALITYSCORE_POND_RES, QUALITYSCORE_POND_GPS } from "./Utils";
5
- import { autoDetectLocale } from "./I18n";
2
+ import { COLORS, QUALITYSCORE_RES_FLAT_VALUES, QUALITYSCORE_RES_360_VALUES, QUALITYSCORE_GPS_VALUES, QUALITYSCORE_POND_RES, QUALITYSCORE_POND_GPS } from "./utils";
3
+ import { autoDetectLocale } from "./i18n";
4
+ import { isNullId } from "./utils";
6
5
 
7
6
  export const DEFAULT_TILES = "https://panoramax.openstreetmap.fr/pmtiles/basic.json";
8
- export const RASTER_LAYER_ID = "gvs-aerial";
7
+ export const RASTER_LAYER_ID = "pnx-aerial";
9
8
 
10
9
  export const TILES_PICTURES_ZOOM = 15;
11
10
  export const TILES_PICTURES_SYMBOL_ZOOM = 18;
@@ -37,7 +36,7 @@ export const VECTOR_STYLES = {
37
36
  "icon-opacity": ["interpolate", ["linear"], ["zoom"], TILES_PICTURES_SYMBOL_ZOOM, 0, TILES_PICTURES_SYMBOL_ZOOM+1, 1],
38
37
  },
39
38
  "layout": {
40
- "icon-image": ["case", ["==", ["get", "type"], "equirectangular"], "gvs-arrow-360", "gvs-arrow-flat"],
39
+ "icon-image": ["case", ["==", ["get", "type"], "equirectangular"], "pnx-arrow-360", "pnx-arrow-flat"],
41
40
  "icon-size": ["interpolate", ["linear"], ["zoom"], TILES_PICTURES_SYMBOL_ZOOM, 0.5, 24, 1],
42
41
  "icon-rotate": ["to-number", ["get", "heading"]],
43
42
  "icon-allow-overlap": true,
@@ -92,7 +91,7 @@ export function getThumbGif(lang) {
92
91
  thumbGif.src = LoaderImg;
93
92
  thumbGif.alt = lang.loading;
94
93
  thumbGif.title = lang.loading;
95
- thumbGif.classList.add("gvs-map-thumb", "gvs-map-thumb-loader");
94
+ thumbGif.classList.add("pnx-map-thumb", "pnx-map-thumb-loader");
96
95
  return thumbGif;
97
96
  }
98
97
 
@@ -106,7 +105,7 @@ export function getThumbGif(lang) {
106
105
  */
107
106
  export function isLabelLayer(l) {
108
107
  return l.type === "symbol"
109
- && l?.layout?.["text-field"]
108
+ && l?.layout?.["text-field"] !== undefined
110
109
  && (l.minzoom === undefined || l.minzoom < 15);
111
110
  }
112
111
 
@@ -123,9 +122,10 @@ export function isLabelLayer(l) {
123
122
  */
124
123
  export function combineStyles(parent, options) {
125
124
  // Get basic vector styles
126
- const style = parent._api.getMapStyle();
125
+ const style = parent.api.getMapStyle();
127
126
 
128
127
  // Complete styles
128
+ style.layers = style.layers || [];
129
129
  style.layers = style.layers.concat(getMissingLayerStyles(style.sources, style.layers));
130
130
  if(!style.metadata) { style.metadata = {}; }
131
131
 
@@ -136,13 +136,16 @@ export function combineStyles(parent, options) {
136
136
  style.layers = style.layers.concat(options.supplementaryStyle.layers || []);
137
137
  }
138
138
 
139
+ // Fix for empty layers causing sorting issues
140
+ style.layers = style.layers.filter(l => l.id);
141
+
139
142
  // Aerial imagery background
140
143
  if(options.raster) {
141
- style.sources["gvs-aerial"] = options.raster;
144
+ style.sources["pnx-aerial"] = options.raster;
142
145
  style.layers.push({
143
146
  "id": RASTER_LAYER_ID,
144
147
  "type": "raster",
145
- "source": "gvs-aerial",
148
+ "source": "pnx-aerial",
146
149
  "layout": {
147
150
  "visibility": options.background === "aerial" ? "visible" : "none",
148
151
  }
@@ -150,7 +153,7 @@ export function combineStyles(parent, options) {
150
153
  }
151
154
 
152
155
  // Filter out general tiles if necessary
153
- if(!parent._options?.users?.includes("geovisio")) {
156
+ if(!parent?.users?.includes("geovisio")) {
154
157
  style.layers.forEach(l => {
155
158
  if(l.source === "geovisio") {
156
159
  if(!l.layout) { l.layout = {}; }
@@ -181,7 +184,7 @@ export function combineStyles(parent, options) {
181
184
 
182
185
  // Override labels to use appropriate language
183
186
  if(style.metadata["panoramax:locales"]) {
184
- let prefLang = parent._options.lang || autoDetectLocale(style.metadata["panoramax:locales"], "latin");
187
+ let prefLang = parent.lang || autoDetectLocale(style.metadata["panoramax:locales"], "latin");
185
188
  if(prefLang.includes("-")) { prefLang = prefLang.split("-")[0]; }
186
189
  if(prefLang.includes("_")) { prefLang = prefLang.split("_")[0]; }
187
190
  style.layers.forEach(l => {
@@ -226,11 +229,11 @@ export function combineStyles(parent, options) {
226
229
  * which didn't offer a MapLibre JSON style directly.
227
230
  *
228
231
  * @param {object} sources Pre-existing MapLibre style sources
229
- * @param {object} layers Pre-existing MapLibre style layers
232
+ * @param {object[]} layers Pre-existing MapLibre style layers
230
233
  * @returns List of layers to add
231
234
  * @private
232
235
  */
233
- export function getMissingLayerStyles(sources, layers) {
236
+ export function getMissingLayerStyles(sources = {}, layers = []) {
234
237
  const newLayers = [];
235
238
 
236
239
  // GeoVisio API <= 2.5.0 : add sequences + pictures
@@ -389,81 +392,257 @@ export function switchCoefValue(expr, newCoefVal) {
389
392
  }
390
393
 
391
394
  /**
392
- * Transforms a set of parameters into an URL-ready string
393
- * It also removes null/undefined values
394
- *
395
- * @param {object} params The parameters object
396
- * @return {string} The URL query part
395
+ * Creates links between map and photo elements.
396
+ * This enable interactions like click on map showing picture.
397
+ *
398
+ * @param {CoreView} parent The view containing both Photo and Map elements
397
399
  * @private
398
400
  */
399
- export function geocoderParamsToURLString(params) {
400
- let p = {};
401
- Object.entries(params)
402
- .filter(e => e[1] !== undefined && e[1] !== null)
403
- .forEach(e => p[e[0]] = e[1]);
401
+ export function linkMapAndPhoto(parent) {
402
+ // Switched picture
403
+ const onPicLoad = e => {
404
+ if(isNullId(e.detail.picId)) {
405
+ parent.map.displayPictureMarker();
406
+ if(parent?.isMapWide?.()) {
407
+ parent?.mini?.setAttribute("collapsed", "");
408
+ }
409
+ }
410
+ else {
411
+ parent.map.displayPictureMarker(e.detail.lon, e.detail.lat, parent.psv.getXY().x, e.detail.first);
412
+ if(parent?.isMapWide?.()) {
413
+ parent?.mini?.removeAttribute("collapsed");
414
+ }
415
+ }
416
+ };
417
+ parent.psv.addEventListener("picture-loading", onPicLoad);
418
+ parent.psv.addEventListener("picture-loaded", onPicLoad);
419
+
420
+ // Picture view rotated
421
+ parent.psv.addEventListener("view-rotated", () => {
422
+ let x = parent.psv.getPosition().yaw * (180 / Math.PI);
423
+ x += parent.psv.getPictureOriginalHeading();
424
+ parent.map._picMarker.setRotation(x);
425
+ });
426
+
427
+ // Picture preview
428
+ parent.psv.addEventListener("picture-preview-started", e => {
429
+ // Show marker corresponding to selection
430
+ parent.map._picMarkerPreview
431
+ .setLngLat(e.detail.coordinates)
432
+ .setRotation(e.detail.direction || 0)
433
+ .addTo(parent.map);
434
+ });
435
+
436
+ parent.psv.addEventListener("picture-preview-stopped", () => {
437
+ parent.map._picMarkerPreview.remove();
438
+ });
404
439
 
405
- return new URLSearchParams(p).toString();
440
+ parent.psv.addEventListener("picture-loaded", e => {
441
+ if (parent.isWidthSmall() && parent._picPopup && e.detail.picId == parent._picPopup._picId) {
442
+ parent._picPopup.remove();
443
+ }
444
+ });
445
+
446
+ // Picture click
447
+ parent.map.on("picture-click", e => {
448
+ parent.select(e.seqId, e.picId);
449
+ if(!parent.psv._myVTour.state.currentNode && parent?._setFocus) { parent._setFocus("pic"); }
450
+ });
451
+
452
+ // Sequence click
453
+ parent.map.on("sequence-click", e => {
454
+ parent.api.getPicturesAroundCoordinates(
455
+ e.coordinates.lat,
456
+ e.coordinates.lng,
457
+ 1,
458
+ 1,
459
+ e.seqId
460
+ ).then(results => {
461
+ if(results?.features?.length > 0) {
462
+ parent.select(results.features[0]?.collection, results.features[0].id);
463
+ if(!parent.psv.getPictureMetadata() && parent?._setFocus) { parent._setFocus("pic"); }
464
+ }
465
+ });
466
+ });
467
+
468
+ // Focus changes
469
+ if(parent._setFocus) {
470
+ // PSV double click
471
+ parent.psv.addEventListener("dblclick", () => { if(parent.isMapWide()) { parent._setFocus("pic"); } });
472
+
473
+ // Map double-click: unselect if focused, toggle focus if unfocused
474
+ parent.map.on("dblclick", () => {
475
+ if(!parent.isMapWide()) { parent._setFocus("map"); }
476
+ else { parent.select(); }
477
+ });
478
+ }
406
479
  }
407
480
 
408
481
  /**
409
- * Nominatim (OSM) geocoder, ready to use for our Map
482
+ * Adds events related to keyboard
410
483
  * @private
411
484
  */
412
- export function forwardGeocodingNominatim(config) {
413
- // Transform parameters into Nominatim format
414
- const params = {
415
- q: config.query,
416
- countrycodes: config.countries,
417
- limit: config.limit,
418
- viewbox: config.bbox,
419
- };
485
+ export function initMapKeyboardHandler(parent) {
486
+ parent.map.keyboard.keydown = function(e) {
487
+ if (e.altKey || e.ctrlKey || e.metaKey) return;
488
+
489
+ // Custom keys
490
+ switch(e.key) {
491
+ case "*":
492
+ case "5":
493
+ parent.moveCenter();
494
+ return;
495
+
496
+ case "PageUp":
497
+ case "9":
498
+ parent.psv.goToNextPicture();
499
+ return;
500
+
501
+ case "PageDown":
502
+ case "3":
503
+ parent.psv.goToPrevPicture();
504
+ return;
505
+
506
+ case "Home":
507
+ case "7":
508
+ e.stopPropagation();
509
+ parent._toggleFocus();
510
+ return;
511
+
512
+ case "End":
513
+ case "1":
514
+ parent.mini.toggleAttribute("collapsed");
515
+ return;
516
+
517
+ case " ":
518
+ case "0":
519
+ parent.psv.toggleSequencePlaying();
520
+ return;
521
+ }
420
522
 
421
- return fetch(`https://nominatim.openstreetmap.org/search?${geocoderParamsToURLString(params)}&format=geojson&polygon_geojson=1&addressdetails=1`)
422
- .then(res => res.json())
423
- .then(res => {
424
- const finalRes = { features: [] };
425
- const listedNames = [];
426
- res.features.forEach(f => {
427
- if(!listedNames.includes(f.properties.display_name)) {
428
- finalRes.features.push({
429
- place_type: ["place"],
430
- place_name: f.properties.display_name,
431
- bounds: new maplibregl.LngLatBounds(f.bbox),
432
- });
433
- listedNames.push(f.properties.display_name);
434
- }
435
- });
436
- return finalRes;
437
- });
523
+ let zoomDir = 0;
524
+ let bearingDir = 0;
525
+ let pitchDir = 0;
526
+ let xDir = 0;
527
+ let yDir = 0;
528
+
529
+ switch (e.keyCode) {
530
+ case 61:
531
+ case 107:
532
+ case 171:
533
+ case 187:
534
+ zoomDir = 1;
535
+ break;
536
+
537
+ case 189:
538
+ case 109:
539
+ case 173:
540
+ zoomDir = -1;
541
+ break;
542
+
543
+ case 37:
544
+ case 100:
545
+ if (e.shiftKey) {
546
+ bearingDir = -1;
547
+ } else {
548
+ e.preventDefault();
549
+ xDir = -1;
550
+ }
551
+ break;
552
+
553
+ case 39:
554
+ case 102:
555
+ if (e.shiftKey) {
556
+ bearingDir = 1;
557
+ } else {
558
+ e.preventDefault();
559
+ xDir = 1;
560
+ }
561
+ break;
562
+
563
+ case 38:
564
+ case 104:
565
+ if (e.shiftKey) {
566
+ pitchDir = 1;
567
+ } else {
568
+ e.preventDefault();
569
+ yDir = -1;
570
+ }
571
+ break;
572
+
573
+ case 40:
574
+ case 98:
575
+ if (e.shiftKey) {
576
+ pitchDir = -1;
577
+ } else {
578
+ e.preventDefault();
579
+ yDir = 1;
580
+ }
581
+ break;
582
+
583
+ default:
584
+ return;
585
+ }
586
+
587
+ if (this._rotationDisabled) {
588
+ bearingDir = 0;
589
+ pitchDir = 0;
590
+ }
591
+
592
+ return {
593
+ cameraAnimation: (map) => {
594
+ const tr = this._tr;
595
+ map.easeTo({
596
+ duration: 300,
597
+ easeId: "keyboardHandler",
598
+ easing: t => t * (2-t),
599
+ zoom: zoomDir ? Math.round(tr.zoom) + zoomDir * (e.shiftKey ? 2 : 1) : tr.zoom,
600
+ bearing: tr.bearing + bearingDir * this._bearingStep,
601
+ pitch: tr.pitch + pitchDir * this._pitchStep,
602
+ offset: [-xDir * this._panStep, -yDir * this._panStep],
603
+ center: tr.center
604
+ }, {originalEvent: e});
605
+ }
606
+ };
607
+ }.bind(parent.map.keyboard);
438
608
  }
439
609
 
610
+ const MAP_PARAMS_STORAGE = "pnx-map-parameters";
611
+
440
612
  /**
441
- * Base adresse nationale (FR) geocoder, ready to use for our Map
442
- * @param {object} config Configuration sent by MapLibre GL Geocoder, following the geocoderApi format ( https://github.com/maplibre/maplibre-gl-geocoder/blob/main/API.md#setgeocoderapi )
443
- * @returns {object} GeoJSON Feature collection in Carmen GeoJSON format
613
+ * Reads map parameters from localStorage
444
614
  * @private
445
615
  */
446
- export function forwardGeocodingBAN(config) {
447
- // Transform parameters into BAN format
448
- const params = { q: config.query, limit: config.limit };
449
- if(typeof config.proximity === "string") {
450
- const [lat, lon] = config.proximity.split(",").map(v => parseFloat(v.trim()));
451
- params.lat = lat;
452
- params.lon = lon;
616
+ export function getMapParamsFromLocalStorage() {
617
+ const params = localStorage.getItem(MAP_PARAMS_STORAGE);
618
+ if(!params) { return {}; }
619
+ try {
620
+ return JSON.parse(params);
621
+ }
622
+ catch(e) {
623
+ console.warn("Can't read map parameters stored in localStorage", e);
624
+ return {};
453
625
  }
626
+ }
454
627
 
455
- const toPlaceName = p => [p.name, p.district, p.city].filter(v => v).join(", ");
456
- const placeTypeToZoom = { "housenumber": 20, "street": 18, "locality": 15, "municipality": 12 };
457
-
458
- return fetch(`https://api-adresse.data.gouv.fr/search/?${geocoderParamsToURLString(params)}`)
459
- .then(res => res.json())
460
- .then(res => {
461
- res.features = res.features.map(f => ({
462
- place_type: ["place"],
463
- place_name: toPlaceName(f.properties),
464
- center: new maplibregl.LngLat(...f.geometry.coordinates),
465
- zoom: placeTypeToZoom[f.properties.type],
466
- }));
467
- return res;
468
- });
469
- }
628
+ /**
629
+ * Save map parameters into localStorage.
630
+ * @private
631
+ */
632
+ export function saveMapParamsToLocalStorage(map) {
633
+ // Save map state in localStorage
634
+ const save = () => localStorage.setItem(MAP_PARAMS_STORAGE, JSON.stringify({
635
+ center: Object.fromEntries(Object.entries(map.getCenter()).map(([k,v]) => ([k,v.toFixed(7)]))),
636
+ zoom: map.getZoom().toFixed(1),
637
+ background: map.getBackground(),
638
+ theme: map._mapFilters.theme
639
+ }));
640
+
641
+ // Add events to know when to rewrite info
642
+ map.on("background-changed", save);
643
+ map.on("filters-changed", save);
644
+ map.on("moveend", save);
645
+ map.on("zoomend", save);
646
+ map.on("dragend", save);
647
+ map.on("boxzoomend", save);
648
+ }