@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
package/build/map.html CHANGED
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><title>Panoramax Standalone Map</title><style>#map{position:relative;width:95%;margin:2.5%;height:400px}#map.fullpage{position:fixed;top:0;bottom:0;left:0;right:0;height:unset;width:unset;margin:0}</style><script defer="defer" src="index.js"></script><link href="index.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="map" class="fullpage"></div><script>var map;window.onload=()=>{(map=new Panoramax.StandaloneMap("map","https://api.panoramax.xyz/api")).addEventListener("ready",(()=>{map.addEventListener("select",(e=>{console.log("Selected sequence",e.detail.seqId,"picture",e.detail.picId)})),map.addEventListener("map:sequence-hover",(e=>{console.log("Hovered sequence",e.detail.seqId)}))}))}</script></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><title>Panoramax Coverage Map</title><style>#map{position:relative;width:95%;margin:2.5%;height:400px}#map.fullpage{position:fixed;top:0;bottom:0;left:0;right:0;height:unset;width:unset;margin:0}</style><script defer="defer" src="index.js"></script><link href="index.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><pnx-coverage-map id="coverage" class="fullpage" endpoint="https://api.panoramax.xyz/api"/><script>var coverage=document.getElementById("coverage");coverage.addEventListener("ready",(()=>{coverage.map.on("sequence-hover",(e=>{console.log("Hovered sequence",e.seqId)})),coverage.addEventListener("select",(e=>{console.log("Selected sequence",e.detail.seqId,"picture",e.detail.picId)}))}),{once:!0})</script></body></html>
@@ -0,0 +1 @@
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><title>Panoramax Photo Viewer</title><style>#viewer{position:relative;width:95%;margin:2.5%;height:400px}#viewer.fullpage{position:fixed;top:0;bottom:0;left:0;right:0;height:unset;width:unset;margin:0}</style><script defer="defer" src="index.js"></script><link href="index.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><pnx-photo-viewer id="viewer" class="fullpage" sequence="ecfe4b2c-0acd-4d3a-a10d-c3e6818755c8" picture="329af5c6-4761-4a6d-9c1e-674fd6daa8b6"/><script>var servers={meta:"https://api.panoramax.xyz/api",ign:"https://panoramax.ign.fr/api",osm:"https://panoramax.openstreetmap.fr/api",local:"http://localhost:5000/api",dev:"https://panoramax.codeureusesenliberte.fr/api"},urlParams=new URLSearchParams(window.location.search),server=servers[urlParams.get("server")||"meta"];window.onload=()=>{document.getElementById("viewer").setAttribute("endpoint",server)}</script></body></html>
package/build/viewer.html CHANGED
@@ -1 +1,12 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><title>Panoramax Web Viewer</title><style>#viewer{position:relative;width:95%;margin:2.5%;height:400px}#viewer.fullpage{position:fixed;top:0;bottom:0;left:0;right:0;height:unset;width:unset;margin:0}</style><script defer="defer" src="index.js"></script><link href="index.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="viewer" class="fullpage"></div><script>var viewer,servers={meta:"https://api.panoramax.xyz/api",ign:"https://panoramax.ign.fr/api",osm:"https://panoramax.openstreetmap.fr/api",local:"http://localhost:5000/api",dev:"https://panoramax.codeureusesenliberte.fr/api"},urlParams=new URLSearchParams(window.location.search),server=servers[urlParams.get("server")||"meta"];window.onload=()=>{viewer=new Panoramax.Viewer("viewer",server,{widgets:{iframeBaseURL:"https://api.panoramax.xyz/"},map:{startWide:!0,raster:{type:"raster",tiles:["https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTHOIMAGERY.ORTHOPHOTOS&STYLE=normal&FORMAT=image/jpeg&TILEMATRIXSET=PM_0_21&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}"],minzoom:0,maxzoom:21,attribution:"&copy; IGN",tileSize:256}}})}</script></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><title>Panoramax Web Viewer</title><style>#viewer{position:relative;width:95%;margin:2.5%;height:400px}#viewer.fullpage{position:fixed;top:0;bottom:0;left:0;right:0;height:unset;width:unset;margin:0}</style><script defer="defer" src="index.js"></script><link href="index.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><pnx-viewer id="viewer" class="fullpage" map='{
2
+ raster: {
3
+ type: "raster",
4
+ tiles: [
5
+ "https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTHOIMAGERY.ORTHOPHOTOS&STYLE=normal&FORMAT=image/jpeg&TILEMATRIXSET=PM_0_21&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}"
6
+ ],
7
+ minzoom: 0,
8
+ maxzoom: 21,
9
+ attribution: "&copy; IGN",
10
+ tileSize: 256
11
+ }
12
+ }'/><script>var servers={meta:"https://api.panoramax.xyz/api",ign:"https://panoramax.ign.fr/api",osm:"https://panoramax.openstreetmap.fr/api",local:"http://localhost:5000/api",dev:"https://panoramax.codeureusesenliberte.fr/api"},urlParams=new URLSearchParams(window.location.search),server=servers[urlParams.get("server")||"meta"];window.onload=()=>{document.getElementById("viewer").setAttribute("endpoint",server)}</script></body></html>
@@ -0,0 +1 @@
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><title>Panoramax Widgets</title><style>body{font-family:sans-serif;padding-bottom:100px}h1,h2,nav,p{text-align:center}.test-bench{display:flex;width:100%;max-width:600px;margin:7px auto;justify-content:space-between;align-items:center}.test-bench h3{margin:0}hr.test-sep{width:100%;max-width:600px}</style><script defer="defer" src="index.js"></script><link href="index.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><h1>Panoramax widgets</h1><p>Test page for common Panoramax viewer widgets</p><nav><a href="#button">Button</a> <a href="#link-button">Link Button</a> <a href="#copy-button">Copy button</a> <a href="#button-group">Button Group</a> <a href="#5stars">5-stars grade</a> <a href="#quality-score">Quality Score</a> <a href="#search-bar">Search bar</a> <a href="#progress-bar">Progress bar</a> <a href="#tabs">Tabs</a></nav><h2 id="button">Button</h2><div class="test-bench"><h3>Text + click</h3><pnx-button onclick='alert("Stuff")'>Click to do stuff</pnx-button></div><div class="test-bench"><h3>Icon</h3><pnx-button>⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Active</h3><pnx-button active="true">Settings</pnx-button></div><div class="test-bench"><h3>CSS override</h3><div style="width:50%;display:flex;gap:5px;max-width:300px"><pnx-button style="width:50%">⚙️ Settings</pnx-button><pnx-button style="width:50%">🖨️ Print</pnx-button></div></div><hr class="test-sep"/><div class="test-bench"><h3>Full</h3><pnx-button kind="full">⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Full active</h3><pnx-button kind="full" active>⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Full L</h3><pnx-button kind="full" size="l">⚙️</pnx-button></div><div class="test-bench"><h3>Full XXL</h3><pnx-button kind="full" size="xxl">⚙️</pnx-button></div><div class="test-bench"><h3>Outline</h3><pnx-button kind="outline">⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Outline active</h3><pnx-button kind="outline" active>⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Outline L</h3><pnx-button kind="outline" size="l">⚙️</pnx-button></div><div class="test-bench"><h3>Outline XXL</h3><pnx-button kind="outline" size="xxl">⚙️</pnx-button></div><div class="test-bench"><h3>Inline</h3><pnx-button kind="inline">⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Inline active</h3><pnx-button kind="inline" active>⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Inline L</h3><pnx-button kind="inline" size="l">⚙️</pnx-button></div><div class="test-bench"><h3>Inline XXL</h3><pnx-button kind="inline" size="xxl">⚙️</pnx-button></div><div class="test-bench"><h3>Superinline</h3><pnx-button kind="superinline">⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Superinline active</h3><pnx-button kind="superinline" active>⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Superinline L</h3><pnx-button kind="superinline" size="l">⚙️</pnx-button></div><div class="test-bench"><h3>Superinline XXL</h3><pnx-button kind="superinline" size="xxl">⚙️</pnx-button></div><div class="test-bench"><h3>Flat</h3><pnx-button kind="flat">⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Flat active</h3><pnx-button kind="flat" active>⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Flat L</h3><pnx-button kind="flat" size="l">⚙️</pnx-button></div><div class="test-bench"><h3>Flat XXL</h3><pnx-button kind="flat" size="xxl">⚙️</pnx-button></div><div class="test-bench"><h3>Superflat</h3><pnx-button kind="superflat">⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Superflat active</h3><pnx-button kind="superflat" active>⚙️ Settings</pnx-button></div><div class="test-bench"><h3>Superflat L</h3><pnx-button kind="superflat" size="l">⚙️</pnx-button></div><div class="test-bench"><h3>Superflat XXL</h3><pnx-button kind="superflat" size="xxl">⚙️</pnx-button></div><h2 id="link-button">Link Button</h2><div class="test-bench"><h3>None set</h3><pnx-link-button>Click for nothing</pnx-link-button></div><div class="test-bench"><h3>All set</h3><pnx-link-button target="_blank" href="https://panoramax.fr" title="Do stuff">Click to do stuff</pnx-link-button></div><h2 id="copy-button">Copy button</h2><div class="test-bench"><h3>Default + text</h3><pnx-copy-button text="copypasta1"></pnx-copy-button></div><div class="test-bench"><h3>Custom + text</h3><pnx-copy-button text="copypasta2">🌐 Share URL</pnx-copy-button></div><div class="test-bench"><h3>Default + input</h3><div style="display:flex;gap:5px;align-items:center"><input value="copypasta3" id="copy-input-1"/><pnx-copy-button input="copy-input-1"></pnx-copy-button></div></div><h2 id="button-group">Button Group</h2><div class="test-bench"><h3>Full Row x2</h3><div><pnx-button-group dir="row"><pnx-button>☹️</pnx-button><pnx-button>🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Full Row x3</h3><div><pnx-button-group dir="row"><pnx-button>☹️</pnx-button><pnx-button>😐</pnx-button><pnx-button>🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Full Row mixed</h3><div><pnx-button-group dir="row"><pnx-button>☹️</pnx-button><pnx-link-button>😐</pnx-link-button><pnx-copy-button>🙂</pnx-copy-button></pnx-button-group></div></div><div class="test-bench"><h3>Full Column x2</h3><div><pnx-button-group dir="column"><pnx-button>☹️</pnx-button><pnx-button>🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Full Column x3</h3><div><pnx-button-group dir="column"><pnx-button>☹️</pnx-button><pnx-button>😐</pnx-button><pnx-button>🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Full Column mixed</h3><div><pnx-button-group dir="column"><pnx-button>☹️</pnx-button><pnx-link-button>😐</pnx-link-button><pnx-copy-button>🙂</pnx-copy-button></pnx-button-group></div></div><hr class="test-sep"/><div class="test-bench"><h3>Outline Row x2</h3><div><pnx-button-group dir="row"><pnx-button kind="outline">☹️</pnx-button><pnx-button kind="outline">🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Outline Row x3</h3><div><pnx-button-group dir="row"><pnx-button kind="outline">☹️</pnx-button><pnx-button kind="outline">😐</pnx-button><pnx-button kind="outline">🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Outline Column x2</h3><div><pnx-button-group dir="column"><pnx-button kind="outline">☹️</pnx-button><pnx-button kind="outline">🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Outline Column x3</h3><div><pnx-button-group dir="column"><pnx-button kind="outline">☹️</pnx-button><pnx-button kind="outline">😐</pnx-button><pnx-button kind="outline">🙂</pnx-button></pnx-button-group></div></div><hr class="test-sep"/><div class="test-bench"><h3>Flat Row x2</h3><div><pnx-button-group dir="row"><pnx-button kind="flat">☹️</pnx-button><pnx-button kind="flat">🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Flat Row x3</h3><div><pnx-button-group dir="row"><pnx-button kind="flat">☹️</pnx-button><pnx-button kind="flat">😐</pnx-button><pnx-button kind="flat">🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Flat Column x2</h3><div><pnx-button-group dir="column"><pnx-button kind="flat">☹️</pnx-button><pnx-button kind="flat">🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Flat Column x3</h3><div><pnx-button-group dir="column"><pnx-button kind="flat">☹️</pnx-button><pnx-button kind="flat">😐</pnx-button><pnx-button kind="flat">🙂</pnx-button></pnx-button-group></div></div><hr class="test-sep"/><div class="test-bench"><h3>Row XL</h3><div><pnx-button-group size="xl" dir="row"><pnx-button kind="flat">☹️</pnx-button><pnx-button kind="flat">😐</pnx-button><pnx-button kind="flat">🙂</pnx-button></pnx-button-group></div></div><div class="test-bench"><h3>Column XL</h3><div><pnx-button-group size="xl" dir="column"><pnx-button kind="flat">☹️</pnx-button><pnx-button kind="flat">😐</pnx-button><pnx-button kind="flat">🙂</pnx-button></pnx-button-group></div></div><h2 id="5stars">5-stars grade</h2><div class="test-bench"><h3>With a grade</h3><pnx-grade stars="5"/></div><div class="test-bench"><h3>Without a grade</h3><pnx-grade/></div><h2 id="quality-score">Quality Score</h2><div class="test-bench"><h3>Classic no grade</h3><pnx-quality-score/></div><div class="test-bench"><h3>Classic 1/5</h3><pnx-quality-score grade="1"/></div><div class="test-bench"><h3>Classic 2/5</h3><pnx-quality-score grade="2"/></div><div class="test-bench"><h3>Classic 3/5</h3><pnx-quality-score grade="3"/></div><div class="test-bench"><h3>Classic 4/5</h3><pnx-quality-score grade="4"/></div><div class="test-bench"><h3>Classic 5/5</h3><pnx-quality-score grade="5"/></div><hr class="test-sep"/><div class="test-bench"><h3>Input</h3><pnx-quality-score input="qs"/></div><div class="test-bench"><h3>Input 1/5</h3><pnx-quality-score input="qs" grade="1"/></div><div class="test-bench"><h3>Input 2/5</h3><pnx-quality-score input="qs" grade="2"/></div><div class="test-bench"><h3>Input 3/5</h3><pnx-quality-score input="qs" grade="3"/></div><div class="test-bench"><h3>Input 4/5</h3><pnx-quality-score input="qs" grade="4"/></div><div class="test-bench"><h3>Input 5/5</h3><pnx-quality-score input="qs" grade="5"/></div><div class="test-bench"><h3>Input many</h3><pnx-quality-score input="qs" grade="1,3,5"/></div><h2 id="search-bar">Search bar</h2><div class="test-bench"><h3>Simple</h3><pnx-search-bar placeholder="Start your search"></pnx-search-bar></div><div class="test-bench"><h3>With pre</h3><pnx-search-bar placeholder="Look for a place"><span slot="pre">🗺️</span></pnx-search-bar></div><div class="test-bench"><h3>Reduced</h3><pnx-search-bar reduceable reduced placeholder="Look for a place"></pnx-search-bar></div><hr class="test-sep"/><div class="test-bench"><h3>Size md full</h3><pnx-search-bar size="md" placeholder="Look for a place"><span slot="pre">🗺️</span></pnx-search-bar></div><div class="test-bench"><h3>Size md reduced</h3><pnx-search-bar size="md" reduceable reduced placeholder="Look for a place"></pnx-search-bar></div><div class="test-bench"><h3>Size xxl full</h3><pnx-search-bar size="xxl" placeholder="Look for a place"><span slot="pre">🗺️</span></pnx-search-bar></div><div class="test-bench"><h3>Size xxl reduced</h3><pnx-search-bar size="xxl" reduceable reduced placeholder="Look for a place"></pnx-search-bar></div><h2 id="progress-bar">Progress bar</h2><div class="test-bench"><h3>Half</h3><pnx-progress-bar value="42"></pnx-progress-bar></div><div class="test-bench"><h3>Indeterminate</h3><pnx-progress-bar></pnx-progress-bar></div><div class="test-bench"><h3>Full</h3><pnx-progress-bar value="100"></pnx-progress-bar></div><h2 id="tabs">Tabs</h2><div class="test-bench"><h3>Many</h3><pnx-tabs><h4 slot="title">Tab 1</h4><div slot="content">Tab 1 content</div><h4 slot="title">Tab 2</h4><div slot="content">Tab 2 content</div><h4 slot="title">Tab 3</h4><div slot="content">Tab 3 content</div></pnx-tabs></div></body></html>
@@ -0,0 +1,201 @@
1
+ /*
2
+ * Common Jest mocks for complex libraries
3
+ */
4
+
5
+ jest.mock("lit", () => {
6
+ class MockLitElement {
7
+ static properties = {};
8
+ static styles = [];
9
+
10
+ constructor() {
11
+ this.shadowRoot = {
12
+ innerHTML: "",
13
+ appendChild: jest.fn(),
14
+ };
15
+ this.requestUpdate = jest.fn();
16
+ this.updateComplete = Promise.resolve();
17
+ this.style = {};
18
+ this._handlers = {};
19
+ this._handlesOnce = {};
20
+ this.renderRoot = {
21
+ querySelectorAll: jest.fn(),
22
+ };
23
+ }
24
+
25
+ connectedCallback() {}
26
+ disconnectedCallback() {}
27
+ attributeChangedCallback() {}
28
+ adoptedCallback() {}
29
+ firstUpdated() {}
30
+ updated() {}
31
+ render() {
32
+ return "";
33
+ }
34
+ getAttribute() {}
35
+ addEventListener(type, handler, options) {
36
+ if(options?.once) {
37
+ if(!this._handlersOnce) { this._handlersOnce = {}; }
38
+ if(!this._handlersOnce?.[type]) { this._handlersOnce[type] = []; }
39
+ this._handlersOnce[type].push(handler);
40
+ }
41
+ else {
42
+ if(!this._handlers[type]) { this._handlers[type] = []; }
43
+ this._handlers[type].push(handler);
44
+ }
45
+ }
46
+ dispatchEvent(event, opts) {
47
+ this._handlers[event.type]?.forEach(f => f(opts));
48
+ this._handlersOnce?.[event.type]?.forEach(f => f(opts));
49
+ if(this._handlersOnce?.[event.type]) {
50
+ this._handlersOnce[event.type] = [];
51
+ }
52
+ }
53
+ }
54
+
55
+ return {
56
+ LitElement: MockLitElement,
57
+ css: jest.fn((styles) => styles),
58
+ html: jest.fn((strings, ...values) => strings.reduce((acc, str, i) => acc + str + (values[i] || ""), "")),
59
+ nothing: Symbol("lit-nothing"),
60
+ unsafeCSS: jest.fn((styles) => styles),
61
+ };
62
+ });
63
+
64
+
65
+ jest.mock("lit/directives/class-map.js", () => ({
66
+ classMap: jest.fn(),
67
+ }));
68
+
69
+
70
+ jest.mock("lit/directives/map.js", () => ({
71
+ map: jest.fn(),
72
+ }));
73
+
74
+
75
+ jest.mock("maplibre-gl", () => ({
76
+ addProtocol: jest.fn(),
77
+ AttributionControl: jest.fn(),
78
+ NavigationControl: jest.fn(),
79
+ GeolocateControl: class {
80
+ onAdd() {;}
81
+ },
82
+ Marker: jest.fn(),
83
+ Popup: function() {
84
+ return {
85
+ on: jest.fn(),
86
+ };
87
+ },
88
+ Map: class {
89
+ constructor(opts) {
90
+ this._mapOpts = opts;
91
+ this._handlers = {};
92
+ this._handlersOnce = {};
93
+ }
94
+ getContainer() {
95
+ return this._mapOpts.container;
96
+ }
97
+ addControl() {;}
98
+ addSource() {;}
99
+ addLayer() {;}
100
+ getLayer() {;}
101
+ setLayoutProperty() {;}
102
+ setPaintProperty() {;}
103
+ getStyle() {
104
+ return {
105
+ layers: [],
106
+ sources: {},
107
+ metadata: {},
108
+ };
109
+ }
110
+ resize() {;}
111
+ on(type, handler) {
112
+ if(!this._handlers[type]) { this._handlers[type] = []; }
113
+ this._handlers[type].push(handler);
114
+ }
115
+ once(type, handler) {
116
+ if(!this._handlersOnce[type]) { this._handlersOnce[type] = []; }
117
+ this._handlersOnce[type].push(handler);
118
+ }
119
+ fire(type, opts) {
120
+ this._handlers[type]?.forEach(f => f(opts));
121
+ this._handlersOnce?.[type]?.forEach(f => f(opts));
122
+ if(this._handlersOnce?.[type]) {
123
+ this._handlersOnce[type] = [];
124
+ }
125
+ }
126
+ },
127
+ LngLat: function() {
128
+ return { lng: -1.7, lat: 47.8 };
129
+ },
130
+ LngLatBounds: function() {
131
+ return { sw: { lng: -1.7, lat: 47.8 }, ne: { lng: -1.7, lat: 47.8 } };
132
+ },
133
+ }));
134
+
135
+
136
+ jest.mock("@photo-sphere-viewer/core", () => ({
137
+ Viewer: class {
138
+ constructor(opts) {
139
+ this._psvOpts = opts;
140
+ this.loader = {
141
+ canvas: { setAttribute: jest.fn() },
142
+ __updateContent: jest.fn(),
143
+ show: jest.fn(),
144
+ };
145
+ this.renderer = {
146
+ renderer: {
147
+ toneMapping: null,
148
+ toneMappingExposure: null,
149
+ }
150
+ };
151
+ this.receivedEvents = [];
152
+ }
153
+ addEventListener(t, h) {
154
+ this.receivedEvents.push([t, h]);
155
+ if(t == "ready") { h(); }
156
+ }
157
+ dispatchEvent(e) {
158
+ this.receivedEvents
159
+ .filter(([t,h]) => e.type === t)
160
+ .forEach(([t,h]) => h(e?.detail));
161
+ }
162
+ getPlugin() {
163
+ return {
164
+ addEventListener: jest.fn(),
165
+ datasource: {
166
+ nodeResolver: jest.fn(),
167
+ },
168
+ arrowsRenderer: {
169
+ clear: jest.fn(),
170
+ },
171
+ state: {
172
+ currentNode: null,
173
+ datasource: { nodes: {} },
174
+ },
175
+ config: {
176
+ transitionOptions: jest.fn(),
177
+ },
178
+ getCurrentNode: jest.fn(),
179
+ __onEnterObject: jest.fn(),
180
+ __onLeaveObject: jest.fn(),
181
+ };
182
+ }
183
+ },
184
+ SYSTEM: {},
185
+ DEFAULTS: {},
186
+ }));
187
+
188
+
189
+ jest.mock("@photo-sphere-viewer/equirectangular-tiles-adapter", () => ({
190
+ EquirectangularTilesAdapter: jest.fn(),
191
+ }));
192
+
193
+
194
+ jest.mock("@photo-sphere-viewer/virtual-tour-plugin", () => ({
195
+ VirtualTourPlugin: jest.fn(),
196
+ }));
197
+
198
+
199
+ jest.mock("query-selector-shadow-dom", () => ({
200
+ querySelectorDeep: jest.fn(),
201
+ }));
package/config/paths.js CHANGED
@@ -53,6 +53,8 @@ module.exports = {
53
53
  appHtmlMap: resolveApp('public/map.html'),
54
54
  appHtmlEditor: resolveApp('public/editor.html'),
55
55
  appHtmlViewer: resolveApp('public/viewer.html'),
56
+ appHtmlPhotoViewer: resolveApp('public/photo.html'),
57
+ appHtmlWidgets: resolveApp('public/widgets.html'),
56
58
  appLibIndexJs: resolveModule(resolveApp, 'src/index'),
57
59
  appPackageJson: resolveApp('package.json'),
58
60
  appSrc: resolveApp('src'),
@@ -718,6 +718,58 @@ module.exports = function (webpackEnv) {
718
718
  : undefined
719
719
  )
720
720
  ),
721
+ new HtmlWebpackPlugin(
722
+ Object.assign(
723
+ {},
724
+ {
725
+ inject: true,
726
+ filename: "widgets.html",
727
+ template: paths.appHtmlWidgets,
728
+ },
729
+ isEnvProduction
730
+ ? {
731
+ minify: {
732
+ removeComments: true,
733
+ collapseWhitespace: true,
734
+ removeRedundantAttributes: true,
735
+ useShortDoctype: true,
736
+ removeEmptyAttributes: true,
737
+ removeStyleLinkTypeAttributes: true,
738
+ keepClosingSlash: true,
739
+ minifyJS: true,
740
+ minifyCSS: true,
741
+ minifyURLs: true,
742
+ },
743
+ }
744
+ : undefined
745
+ )
746
+ ),
747
+ new HtmlWebpackPlugin(
748
+ Object.assign(
749
+ {},
750
+ {
751
+ inject: true,
752
+ filename: "photo.html",
753
+ template: paths.appHtmlPhotoViewer,
754
+ },
755
+ isEnvProduction
756
+ ? {
757
+ minify: {
758
+ removeComments: true,
759
+ collapseWhitespace: true,
760
+ removeRedundantAttributes: true,
761
+ useShortDoctype: true,
762
+ removeEmptyAttributes: true,
763
+ removeStyleLinkTypeAttributes: true,
764
+ keepClosingSlash: true,
765
+ minifyJS: true,
766
+ minifyCSS: true,
767
+ minifyURLs: true,
768
+ },
769
+ }
770
+ : undefined
771
+ )
772
+ ),
721
773
  // Inlines the webpack runtime script. This script is too small to warrant
722
774
  // a network request.
723
775
  // https://github.com/facebook/create-react-app/issues/5358
@@ -1,27 +1,34 @@
1
1
  # URL settings
2
2
 
3
- Various settings could be set from URL hash part in order to create permalinks.
3
+ Various settings could be set from URL query part in order to create permalinks.
4
4
 
5
- These are set after the `#` symbol of the URL, following a `key=value` format, each being separated by `&` symbol.
5
+ These are set after the `?` symbol of the URL, following a `key=value` format, each being separated by `&` symbol.
6
6
 
7
7
  Example:
8
8
 
9
9
  ```urlencoded
10
- https://panoramax.xyz/#map=19.51/48.1204522/-1.7199004&pic=890b6268-7716-4e34-ada9-69985e6c1657
10
+ https://api.panoramax.xyz/?map=19.51/48.1204522/-1.7199004&pic=890b6268-7716-4e34-ada9-69985e6c1657
11
11
  ```
12
12
 
13
+ !!! note
14
+
15
+ This works only for __Viewer__ and __Photo Viewer__ components, not for __Editor__ or __Coverage Map__.
16
+
13
17
  ## :fontawesome-solid-computer: Interface settings
14
18
 
15
19
  ### :material-target: `focus`: main shown element
16
20
 
17
- Switch to choose which element between map, picture or metadata should be shown wide at start. Examples:
21
+ Switch to choose which element between map or picture should be shown wide at start. Examples:
18
22
 
19
23
  - `focus=map`
20
24
  - `focus=pic`
21
- - `focus=meta`
22
25
 
23
26
  By default, picture is shown wide.
24
27
 
28
+ !!! note
29
+
30
+ In versions prior to 4.0.0, another `meta` value was also available to display picture metadata popup. As this part of interface is shown directly on picture side since 4.0.0, this parameter was removed. If present, picture is shown focused.
31
+
25
32
  ### :simple-speedtest: `speed`: sequence play speed
26
33
 
27
34
  The duration of stay on a picture during sequence play (excluding image dowloading time), in milliseconds. Authorized values are between 0 and 3000. Example:
@@ -36,11 +43,7 @@ Choose the allowed navigation between pictures, to eventually restrict what is v
36
43
 
37
44
  - `nav=any` (or no value): no restriction in navigation (default)
38
45
  - `nav=seq`: can only see pictures in same sequence
39
- - `nav=none`: can only see current picture, no navigation to other picture allowed
40
-
41
- !!! note
42
-
43
- This parameter is intended to work on page first load. If used after page load, you may switch to another picture or fully reload pictures metadata cache in order to have expected behaviour.
46
+ - `nav=none/pic`: can only see current picture, no navigation to other picture allowed
44
47
 
45
48
  ## :material-image: Picture settings
46
49
 
@@ -78,8 +81,7 @@ xyz=10/25/50
78
81
 
79
82
  The `map` parameters handles both map visibility and position. It can take different values:
80
83
 
81
- - `map=none`: to completely disable the map.
82
- - `map=zoom/latitude/longitude`: for setting the map position (following [MapLibre GL JS hash format](https://maplibre.org/maplibre-gl-js-docs/api/map/#map-parameters)). It updates automatically when map is moved.
84
+ - `map=zoom/latitude/longitude`: for setting the map position (following [MapLibre GL JS hash format](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/#hash)). It updates automatically when map is moved.
83
85
  - no parameter set: shows the map of the whole world, or zoomed on instance area of interest.
84
86
 
85
87
  Example:
@@ -88,10 +90,6 @@ Example:
88
90
  map=19.51/48.1204522/-1.7199004
89
91
  ```
90
92
 
91
- !!! note
92
-
93
- The `map=none` is intended to work __on page first load only__. Changing it dynamically will not hide the map, and will be reset on next map movement.
94
-
95
93
  ### :date: `date_from` and `date_to`: filter map data by date
96
94
 
97
95
  Minimum and maximum capture date for pictures and sequences to show on map (if map is enabled), in ISO format:
@@ -1,91 +1,74 @@
1
1
  # Compatibility with STAC API
2
2
 
3
- Panoramax viewer works best with a [Panoramax API](https://gitlab.com/panoramax/server/api), but is designed to be compatible with a wide range of [STAC API](https://github.com/radiantearth/stac-api-spec). Although, third-party STAC API needs the following requirements to work with our viewer:
3
+ Panoramax viewer works best with a [Panoramax API](https://gitlab.com/panoramax/server/api), but is designed to be compatible with a wide range of [STAC API](https://github.com/radiantearth/stac-api-spec). Although, third-party STAC API needs the following requirements to work with our viewer.
4
4
 
5
- - Collections corresponding to pictures sequences, and items corresponding to individual pictures
6
- - Offer a `/search` endpoint ([documentation](https://github.com/radiantearth/stac-api-spec/tree/main/item-search))
7
- - Picture items should have required metadata documented below.
8
- - Offer a vector tiles endpoint for map display, either with:
9
- - A [MapLibre Style JSON](https://maplibre.org/maplibre-style-spec/) file, advertised through landing page (`/api`) with a `xyz-style` link.
10
- - A direct tiles URL, pointing to tiles in [MVT format](https://mapbox.github.io/vector-tile-spec/) and following layer structure described below. It must be advertised in landing page (`/api`) using [Web Map Links](https://github.com/stac-extensions/web-map-links) STAC extension (as `xyz` link).
5
+ ## :octicons-search-16: Search endpoint
11
6
 
12
- Optional metadata could also be supplied by third-party STAC API to improve viewer usability:
7
+ Your STAC API should offer a `/search` endpoint ([documentation](https://github.com/radiantearth/stac-api-spec/tree/main/item-search)).
13
8
 
14
- - In landing page (`/api` route, corresponding to main STAC Catalog):
15
- - An `extent` property ([following this format](https://github.com/radiantearth/stac-spec/blob/master/collection-spec/collection-spec.md#extent-object)) could be provided to make map zoom in available data area by default.
16
- - A `collection-preview` link pointing to a formatted URL (like `https://yourserver.fr/api/collections/{id}/thumb.jpg`) which is a direct link to a thumbnail image to represent a specific sequence.
17
- - A `item-preview` link pointing to a formatted URL (like `http://localhost:5000/api/pictures/{id}/thumb.jpg`) which is a direct link to a thumbnail image for a given picture.
18
- - A `data` link with `application/rss+xml` media type pointing to a RSS feed of recently uploaded collections. Given link may also support a `bbox` query string parameter to filter collections by their location.
19
- - Links `user-xyz` (MVT media type) and `user-search` (JSON media type) to allow filtering by user.
20
- - A `report` link with `application/json` media type to allow posting pictures reports.
21
- - A `title` property for showing proper API name in viewer debug.
9
+ ## :fontawesome-regular-images: Collections and items
22
10
 
11
+ Collections should correspond to :fontawesome-regular-images: __pictures sequences__, and items corresponding to :fontawesome-regular-image: __individual pictures__.
23
12
 
24
- ## Perspective imagery metadata
25
-
26
- Pictures metadata follow [STAC item specification](https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md), plus some extensions:
13
+ Individual pictures should follow [STAC item specification](https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md), plus some extensions:
27
14
 
28
15
  - _Perspective imagery specification_ for its pictures and sequences metadata ([documentation](https://github.com/stac-extensions/perspective-imagery))
29
16
  - _Tiled assets specification_ for smooth display of high-resolution pictures ([documentation](https://github.com/stac-extensions/tiled-assets))
30
17
 
31
- Viewer relies on following item metadata for display:
32
-
33
- - `assets`
34
- - [`roles`](https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md#asset-roles): `data`, `visual` and `thumbnail`
35
- - `type`: `image/jpeg` or `image/webp`
36
- - `href`
37
- - `assets_templates`
38
- - `tiles`
39
- - `role`: `data`
40
- - `href`
41
- - `geometry`
42
- - `collection`
43
- - `id`
44
- - `links`
45
- - [`rel`](https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md#link-object): `prev`, `next`, `related`
46
- - `type`: `application/geo+json`
47
- - `id`
48
- - `geometry`
49
- - `datetime`
50
- - `properties`
51
- - `pers:interior_orientation`
52
- - `field_of_view`
53
- - `focal_length`
54
- - `view:azimuth`
55
- - `pers:roll`
56
- - `pers:pitch`
57
- - `datetime` or `datetimetz`
58
- - `tiles:tile_matrix_sets`
59
- - `geovisio`
60
- - `type`: `TileMatrixSetType`
61
- - `tileMatrix`
62
- - `matrixHeight`
63
- - `matrixWidth`
64
- - `tileHeight`
65
- - `tileWidth`
66
-
67
-
68
- ## Vector tiles format
69
-
70
- MVT Vector tiles must contain at least two layers : sequences and pictures.
71
-
72
- Layer _sequences_:
18
+ ??? info "List of support item metadata"
73
19
 
74
- - Available on all zoom levels
75
- - Available properties: `id` (sequence ID)
76
-
77
- Layer _pictures_:
78
-
79
- - Available on zoom levels >= 15
80
- - Available properties: `id` (picture ID), `ts` (picture date/time), `heading` (picture heading in degrees)
81
-
82
- A supplementary layer _grid_ can be made available for low-zoom overview:
83
-
84
- - Available on zoom levels < 6
85
- - Available properties: `id` (grid cell ID), `nb_pictures` (amount of pictures), `coef` (value from 0 to 1, relative quantity of available pictures)
86
- - Optional properties: `nb_360_pictures`, `coef_360_pictures`, `nb_flat_pictures`, `coef_flat_pictures` (similar to `nb_pictures` and `coef` but separated by picture type)
87
-
88
- ### Labels translation
20
+ - `assets`
21
+ - [`roles`](https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md#asset-roles): `data`, `visual` and `thumbnail`
22
+ - `type`: `image/jpeg` or `image/webp`
23
+ - `href`
24
+ - `assets_templates`
25
+ - `tiles`
26
+ - `role`: `data`
27
+ - `href`
28
+ - `geometry`
29
+ - `collection`
30
+ - `id`
31
+ - `links`
32
+ - [`rel`](https://github.com/radiantearth/stac-spec/blob/master/item-spec/item-spec.md#link-object): `prev`, `next`, `related`, `via`
33
+ - `type`: `application/geo+json` or `application/json`
34
+ - `id`
35
+ - `geometry`
36
+ - `datetime`
37
+ - `properties`
38
+ - `pers:interior_orientation`
39
+ - `field_of_view`
40
+ - `focal_length`
41
+ - `view:azimuth`
42
+ - `pers:roll`
43
+ - `pers:pitch`
44
+ - `datetime` or `datetimetz`
45
+ - `tiles:tile_matrix_sets`
46
+ - `geovisio`
47
+ - `type`: `TileMatrixSetType`
48
+ - `tileMatrix`
49
+ - `matrixHeight`
50
+ - `matrixWidth`
51
+ - `tileHeight`
52
+ - `tileWidth`
53
+
54
+ ## :map: Vector tiles
55
+
56
+ If you want to use map in viewer, your STAC API should offer :map: vector tiles, through one of these ways:
57
+
58
+ - A [MapLibre Style JSON](https://maplibre.org/maplibre-style-spec/) file, advertised through landing page (`/api`) with a `xyz-style` link.
59
+ - A direct tiles URL, pointing to tiles in [MVT format](https://mapbox.github.io/vector-tile-spec/) and following layer structure described below. It must be advertised in landing page (`/api`) using [Web Map Links](https://github.com/stac-extensions/web-map-links) STAC extension (as `xyz` link).
60
+
61
+ ### Layers
62
+
63
+ MVT Vector tiles must have the following layers:
64
+
65
+ | Name | Zooms | Mandatory | Properties |
66
+ |------|-------|:---------:|------------|
67
+ | `sequences` | All | ✅ | - `id`: sequence ID |
68
+ | `pictures` | >= 15 | ✅ | - `id`: picture ID<br />- `ts`: picture date/time<br />- `heading`: picture heading in degrees |
69
+ | `grid` | < 6 | ❌ | __Mandatory:__<br />- `id`: grid cell ID<br />- `nb_pictures`: amount of pictures<br />- `coef`: value from 0 to 1, relative quantity of available pictures<br />__Optional:__<br />- `nb_360_pictures`<br />- `coef_360_pictures`<br />- `nb_flat_pictures`<br />- `coef_flat_pictures`<br />(similar to `nb_pictures` and `coef` but separated by picture type) |
70
+
71
+ ### Translation
89
72
 
90
73
  If your vector tiles support multiple languages, you can set in your `style.json` the list of supported languages :
91
74