@panoramax/web-viewer 3.2.3 → 4.0.0-develop-9f9cf858

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 +56 -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,70 +0,0 @@
1
- /* Main container */
2
- .gvs {
3
- container-type: inline-size;
4
- box-sizing: border-box;
5
- }
6
-
7
- .gvs * { box-sizing: border-box; }
8
-
9
- /* Colors */
10
- :root {
11
- --white: #ffffff;
12
- --black: #181818;
13
- --black-pale: #1b1a17;
14
- --red: #f70000;
15
- --red-pale: #ff726f;
16
- --grey: #f5f5f5;
17
- --grey-pale: #cfd2cf;
18
- --grey-semi-dark: #808080;
19
- --grey-dark: #3e3e3e;
20
- --blue: #2954e9;
21
- --blue-dark: #0a1f69;
22
- --blue-semi: #d7dffc;
23
- --blue-pale: #f2f5ff;
24
- --blue-geovisio: #34495e;
25
- --beige: #f5f3ec;
26
- --yellow: #fec868;
27
- --orange: #ff6f00;
28
- --orange-pale: #fffafa;
29
- --green: #7ec636;
30
- --green-pale: #f0ffee;
31
- }
32
-
33
- /* Titles */
34
- .gvs h3 {
35
- font-size: 1.1em;
36
- line-height: 1.1em;
37
- font-weight: 500;
38
- margin: 10px 0 10px 0;
39
- }
40
-
41
- .gvs h4 {
42
- font-size: 1.0em;
43
- line-height: 1.0em;
44
- font-weight: 500;
45
- margin: 15px 0;
46
- }
47
-
48
- .gvs h4:first-of-type { margin-top: 0; }
49
-
50
- .gvs h4 svg {
51
- height: 18px;
52
- vertical-align: sub;
53
- margin-right: 2px;
54
- }
55
-
56
- .gvs h4 a svg {
57
- height: 16px;
58
- vertical-align: sub;
59
- margin-left: 2px;
60
- }
61
-
62
- /* Hidden elements on mobile */
63
- @container (max-width: 576px) {
64
- .gvs-mobile-hidden { display: none !important; }
65
- }
66
-
67
- /* Hidden elements on print */
68
- @media print {
69
- .gvs-print-hidden { display: none !important; }
70
- }
@@ -1,175 +0,0 @@
1
- import "./CoreView.css";
2
- import API from "../utils/API";
3
- import { getTranslations } from "../utils/I18n";
4
- import { DEFAULT_TILES } from "../utils/Map";
5
- import { BASE_PANORAMA_ID, isInIframe, isInternetFast } from "../utils/Utils";
6
- import PACKAGE_JSON from "../../package.json";
7
- import Loader from "./Loader";
8
-
9
-
10
- /**
11
- * Core view is an abstract class used for setting up any of the main Panoramax JS view components.
12
- *
13
- * It is used to prepare API, internationalization, options checks... for Viewer, StandaloneMap and Editor classes.
14
- *
15
- * @param {string|Element} container The DOM element to create viewer into
16
- * @param {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md))
17
- * @param {object} [options] View options.
18
- * @param {string} [options.selectedSequence] The ID of sequence to highlight on load (defaults to none)
19
- * @param {string} [options.selectedPicture] The ID of picture to highlight on load (defaults to none)
20
- * @param {object} [options.fetchOptions=null] Set custom options for fetch calls made against API ([same syntax as fetch options parameter](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters))
21
- * @param {string|string[]} [options.users] List of user IDs to default use for display. Defaults to all users.
22
- * @param {string|object} [options.style] The map's MapLibre style. This can be an a JSON object conforming to the schema described in the [MapLibre Style Specification](https://maplibre.org/maplibre-gl-js-docs/style-spec/), or a URL string pointing to one. Defaults to OSMFR vector tiles.
23
- *
24
- * @property {object} _t The translations labels
25
- * @property {string} _selectedSeqId The selected sequence ID
26
- * @property {string} _selectedPicId The selected picture ID
27
- * @property {API} _api The API handler
28
- * @property {Loader} _loader The initial loader message
29
- * @property {object} _options The stored options
30
- * @property {Element} container The DOM container
31
- */
32
- export default class CoreView extends EventTarget {
33
- constructor(container, endpoint, options = {}) {
34
- super();
35
-
36
- this._options = options;
37
- if(this._options == null) { this._options = {}; }
38
- if(!this._options.users) { this._options.users = ["geovisio"]; }
39
- if(typeof this._options.users === "string") { this._options.users = [this._options.users]; }
40
- if(!this._options.style) { this._options.style = DEFAULT_TILES; }
41
-
42
- if(!this._options.testing) {
43
- // Display version in logs
44
- console.info(`📷 Panoramax ${this.getClassName()} - Version ${PACKAGE_JSON.version} (${__COMMIT_HASH__})
45
-
46
- 🆘 Issues can be reported at ${PACKAGE_JSON.repository.url}`);
47
- }
48
-
49
- // Translations
50
- this._t = getTranslations(this._options.lang);
51
-
52
- // Internet speed check
53
- this._isInternetFast = null;
54
- isInternetFast().then(isFast => this._isInternetFast = isFast);
55
-
56
- // Selected IDs
57
- this._selectedSeqId = this._options.selectedSequence || null;
58
- this._selectedPicId = this._options.selectedPicture || null;
59
-
60
- // Container init
61
- this.container = typeof container === "string" ? document.getElementById(container) : container;
62
- if(!(this.container instanceof Element)) { throw new Error("Container is not a valid HTML element, does it exist in your page ?"); }
63
- this.container.classList.add("gvs", `gvs-${this.getClassName().toLocaleLowerCase()}`);
64
- if(isInIframe()) { this.container.classList.add("gvs-iframed"); }
65
-
66
- // Loader init
67
- this.loaderContainer = document.createElement("div");
68
- this.container.appendChild(this.loaderContainer);
69
- this._loader = new Loader(this, this.loaderContainer);
70
-
71
- // API init)
72
- endpoint = (endpoint || "").replace("/api/search", "/api");
73
- try {
74
- this._api = new API(endpoint, {
75
- users: this._options.users,
76
- fetch: this._options?.fetchOptions,
77
- style: this._options.style,
78
- });
79
- this._api.onceReady()
80
- .then(() => {
81
- let unavailable = this._api.getUnavailableFeatures();
82
- let available = this._api.getAvailableFeatures();
83
- available = unavailable.length === 0 ? "✅ All features available" : "✅ Available features: "+available.join(", ");
84
- unavailable = unavailable.length === 0 ? "" : "🚫 Unavailable features: "+unavailable.join(", ");
85
- console.info(`🌐 Connected to API "${this._api._metadata.name}" (${this._api._endpoint})
86
- ℹ️ API runs STAC ${this._api._metadata.stac_version} ${this._api._metadata.geovisio_version ? "& GeoVisio "+this._api._metadata.geovisio_version : ""}
87
- ${available}
88
- ${unavailable}
89
- `.trim());
90
- })
91
- .catch(e => this._loader.dismiss(e, this._t.gvs.error_api));
92
- }
93
- catch(e) {
94
- this._loader.dismiss(e, this._t.gvs.error_api);
95
- }
96
- }
97
-
98
- /**
99
- * This allows to retrieve an always correct class name.
100
- * This is crap, but avoids issues with Webpack & so on.
101
- *
102
- * Each inheriting class must override this method.
103
- */
104
- getClassName() {
105
- return "CoreView";
106
- }
107
-
108
- /**
109
- * Ends all form of life in this object.
110
- *
111
- * This is useful for Single Page Applications (SPA), to remove various event listeners.
112
- */
113
- destroy() {
114
- delete this._options;
115
- delete this._t;
116
- delete this._api;
117
- delete this._loader;
118
- this.loaderContainer.remove();
119
- delete this.loaderContainer;
120
- }
121
-
122
- /**
123
- * Is the view running in a small container (small embed or smartphone)
124
- * @returns {boolean} True if container is small
125
- */
126
- isWidthSmall() {
127
- return this.container?.offsetWidth < 576;
128
- }
129
-
130
- /**
131
- * Is the view running in a small-height container (small embed or smartphone)
132
- * @returns {boolean} True if container height is small
133
- */
134
- isHeightSmall() {
135
- return this.container?.offsetHeight < 400;
136
- }
137
-
138
- /**
139
- * Change the currently picture and/or sequence.
140
- * Calling the method without parameters unselects.
141
- * @param {string} [seqId] The sequence UUID
142
- * @param {string} [picId] The picture UUID
143
- * @param {boolean} [force=false] Force select even if already selected
144
- */
145
- select(seqId = null, picId = null, force = false) {
146
- if(picId === BASE_PANORAMA_ID) { picId = null; }
147
- const prevSeqId = this._selectedSeqId || null;
148
- const prevPicId = this._selectedPicId || null;
149
- if(!force && prevPicId == picId && prevSeqId == seqId) { return; } // Avoid running if already selected
150
-
151
- this._selectedSeqId = seqId;
152
- this._selectedPicId = picId;
153
-
154
- /**
155
- * Event for sequence/picture selection
156
- *
157
- * @event select
158
- * @memberof CoreView
159
- * @type {object}
160
- * @property {object} detail Event information
161
- * @property {string} detail.seqId The selected sequence ID
162
- * @property {string} detail.picId The selected picture ID (or null if not a precise picture clicked)
163
- * @property {string} [detail.prevSeqId] The previously selected sequence ID (or null if none)
164
- * @property {string} [detail.prevPicId] The previously selected picture ID (or null if none)
165
- */
166
- this.dispatchEvent(new CustomEvent("select", {
167
- detail: {
168
- seqId,
169
- picId,
170
- prevSeqId,
171
- prevPicId,
172
- }
173
- }));
174
- }
175
- }
@@ -1,74 +0,0 @@
1
- .gvs .gvs-loader {
2
- position: relative;
3
- width: 100%;
4
- height: 100%;
5
- z-index: 0;
6
- }
7
-
8
- .gvs .gvs-loader.gvs-loader-visible {
9
- visibility: visible;
10
- opacity: 1;
11
- }
12
-
13
- /* Loader overlay */
14
- .gvs .gvs-loader {
15
- visibility: hidden;
16
- position: absolute;
17
- top: 0;
18
- right: 0;
19
- left: 0;
20
- bottom: 0;
21
- opacity: 0;
22
- display: flex;
23
- flex-direction: column;
24
- justify-content: center;
25
- gap: 20px;
26
- align-items: center;
27
- background: #37474F;
28
- z-index: 9000;
29
- transition: all 0.5s;
30
- font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
31
- font-weight: 550;
32
- color: white;
33
- font-size: 1.4em;
34
- text-align: center;
35
- }
36
-
37
- .gvs .gvs-loader a {
38
- color: white !important;
39
- }
40
-
41
- /* Flashing text */
42
- .gvs .gvs-loader > div > span {
43
- animation: blinker 2s linear infinite;
44
- }
45
- @keyframes blinker { 50% { opacity: 0.3; } }
46
-
47
- /* Rotating logo */
48
- .gvs .gvs-loader .gvs-loader-img {
49
- width: 150px;
50
- animation: rotating 1.4s linear infinite;
51
- }
52
-
53
- @keyframes rotating {
54
- from { transform: rotate(0deg); }
55
- to { transform: rotate(360deg); }
56
- }
57
-
58
- /* Call to action button */
59
- .gvs .gvs-loader .gvs-loader-cta {
60
- border: none;
61
- border-radius: 7px;
62
- font-weight: 500;
63
- font-size: 1.0em;
64
- color: white;
65
- background-color: #EF6C00;
66
- cursor: pointer;
67
- margin: 10px;
68
- padding: 5px 30px;
69
- box-shadow: 2px 2px 2px rgba(0,0,0,0.3);
70
- }
71
-
72
- .gvs .gvs-loader .gvs-loader-cta:hover {
73
- background-color: #F57C00;
74
- }
@@ -1,120 +0,0 @@
1
- import "./Loader.css";
2
- import LogoDead from "../img/logo_dead.svg";
3
- import LoaderImg from "../img/marker.svg";
4
-
5
- /**
6
- * Loader is a full-screen loading message.
7
- * @private
8
- *
9
- * @param {CoreView} parent The parent view
10
- * @param {Element} container The DOM element to create loader into
11
- */
12
- export default class Loader {
13
- constructor(parent, container) {
14
- this._parent = parent;
15
- this.container = container;
16
- this.container.classList.add("gvs-loader", "gvs-loader-visible");
17
-
18
- // Logo
19
- const logo = document.createElement("img");
20
- logo.src = LoaderImg;
21
- logo.alt = "";
22
- logo.title = this._parent._t.map.loading;
23
- logo.classList.add("gvs-loader-img");
24
- this.container.appendChild(logo);
25
-
26
- // Label (1 serious, then fun ones)
27
- const labelWrapper = document.createElement("div");
28
- const label = document.createElement("span");
29
- const nextLabelFun = () => (
30
- this._parent._t.gvs.loading_labels_fun[
31
- Math.floor(Math.random() * this._parent._t.gvs.loading_labels_fun.length)
32
- ]
33
- );
34
- label.innerHTML = this._parent._t.gvs.loading_labels_serious[
35
- Math.floor(Math.random() * this._parent._t.gvs.loading_labels_serious.length)
36
- ];
37
- const nextLabelFct = () => setTimeout(() => {
38
- label.innerHTML = nextLabelFun();
39
- this._loaderLabelChanger = nextLabelFct();
40
- }, 500 + Math.random() * 1000);
41
- this._loaderLabelChanger = nextLabelFct();
42
- labelWrapper.appendChild(label);
43
-
44
- this.container.appendChild(labelWrapper);
45
- }
46
-
47
- /**
48
- * Is the loader visible ?
49
- * @returns {boolean} True if visible
50
- */
51
- isVisible() {
52
- return this.container.classList.contains("gvs-loader-visible");
53
- }
54
-
55
- /**
56
- * Dismiss loader, or show error
57
- * @param {object} [err] Optional error object to show in browser console
58
- * @param {str} [errMeaningful] Optional error message to show to user
59
- * @param {fct} [next] Optional function to run after loader dismiss
60
- */
61
- dismiss(err = null, errMeaningful = null, next = null) {
62
- clearTimeout(this._loaderLabelChanger);
63
-
64
- if(!err) {
65
- this.container.classList.remove("gvs-loader-visible");
66
- setTimeout(() => this.container.remove(), 2000);
67
-
68
- /**
69
- * Event for viewer being ready to use (API loaded)
70
- *
71
- * @event ready
72
- * @memberof CoreView
73
- */
74
- const readyEvt = new CustomEvent("ready");
75
- this._parent.dispatchEvent(readyEvt);
76
-
77
- if(next) { next(); }
78
- }
79
- else {
80
- if(err !== true) { console.error(err); }
81
-
82
- // Change content
83
- this.container.children[0].src = LogoDead;
84
- this.container.children[0].style.width = "200px";
85
- this.container.children[0].style.animation = "unset";
86
-
87
- let errHtml;
88
- if(next) {
89
- errHtml = `<button class="gvs-loader-cta">${this._parent._t.gvs.error_click}</button>`;
90
- }
91
- else {
92
- errHtml = `<small>${this._parent._t.gvs.error_retry}</small>`;
93
- }
94
-
95
- if(errMeaningful) { errHtml = errMeaningful + "<br />" + errHtml; }
96
- this.container.children[1].innerHTML = `${this._parent._t.gvs.error}<br />${errHtml}`;
97
- if(next) {
98
- this.container.addEventListener("click", next);
99
- }
100
- const errLabel = errMeaningful || "Panoramax JS had a blocking exception";
101
-
102
- /**
103
- * Event for viewer failing to initially load
104
- *
105
- * @event broken
106
- * @memberof CoreView
107
- * @type {object}
108
- * @property {object} detail Event information
109
- * @property {string} detail.error The user-friendly error message to display
110
- */
111
- const brokenEvt = new CustomEvent("broken", {
112
- detail: { error: errLabel }
113
- });
114
- this._parent.dispatchEvent(brokenEvt);
115
-
116
- // Throw error
117
- throw new Error(errLabel);
118
- }
119
- }
120
- }
Binary file
package/src/utils/Exif.js DELETED
@@ -1,193 +0,0 @@
1
- /**
2
- * Read float value from EXIF tags (to handle fractions & all)
3
- * @param {*} val The input EXIF tag value
4
- * @returns {number|undefined} The parsed value, or undefined if value is not readable
5
- * @private
6
- */
7
- export function getExifFloat(val) {
8
- // Null-like values
9
- if(
10
- [null, undefined, ""].includes(val)
11
- || typeof val === "string" && val.trim() === ""
12
- ) {
13
- return undefined;
14
- }
15
- // Already valid number
16
- else if(typeof val === "number") {
17
- return val;
18
- }
19
- // String
20
- else if(typeof val === "string") {
21
- // Check if looks like a fraction
22
- if(/^-?\d+(\.\d+)?\/-?\d+(\.\d+)?$/.test(val)) {
23
- const parts = val.split("/").map(p => parseFloat(p));
24
- return parts[0] / parts[1];
25
- }
26
-
27
- // Try a direct cast to float
28
- try { return parseFloat(val); }
29
- catch(e) {} // eslint-disable-line no-empty
30
-
31
- // Unrecognized
32
- return undefined;
33
- }
34
- else { return undefined; }
35
- }
36
-
37
- /**
38
- * Find in picture metadata the GPS precision.
39
- * @param {object} picture The GeoJSON picture feature
40
- * @returns {string} The precision value (poor, fair, moderate, good, excellent, ideal, unknown)
41
- * @private
42
- */
43
- export function getGPSPrecision(picture) {
44
- let quality = "❓";
45
- const gpsHPosError = picture?.properties?.["quality:horizontal_accuracy"] || getExifFloat(picture?.properties?.exif?.["Exif.GPSInfo.GPSHPositioningError"]);
46
- const gpsDop = getExifFloat(picture?.properties?.exif?.["Exif.GPSInfo.GPSDOP"]);
47
-
48
- if(gpsHPosError !== undefined) {
49
- quality = `${gpsHPosError} m`;
50
- }
51
- else if(gpsDop !== undefined) {
52
- if(gpsDop < 1) { quality = "ideal"; }
53
- else if(gpsDop < 2) { quality = "excellent"; }
54
- else if(gpsDop < 5) { quality = "good"; }
55
- else if(gpsDop < 10) { quality = "moderate"; }
56
- else if(gpsDop < 20) { quality = "fair"; }
57
- else { quality = "poor"; }
58
- }
59
-
60
- return quality;
61
- }
62
-
63
- /**
64
- * Compute PSV sphere correction based on picture metadata & EXIF tags.
65
- * @param {object} picture The GeoJSON picture feature
66
- * @returns {object} The PSV sphereCorrection value
67
- * @private
68
- */
69
- export function getSphereCorrection(picture) {
70
- // Photo direction
71
- let dir = picture.properties?.["view:azimuth"];
72
- if(dir === undefined) {
73
- const v = getExifFloat(picture.properties?.exif?.["Exif.GPSInfo.GPSImgDirection"]);
74
- if(v !== undefined) {
75
- dir = v;
76
- }
77
- }
78
- dir = dir || 0;
79
-
80
- // Yaw
81
- let yaw = picture.properties?.["pers:yaw"];
82
- let exifFallbacks = ["Xmp.GPano.PoseHeadingDegrees", "Xmp.Camera.Yaw", "Exif.MpfInfo.MPFYawAngle"];
83
- if(yaw === undefined) {
84
- for(let exif of exifFallbacks) {
85
- const v = getExifFloat(picture.properties?.exif?.[exif]);
86
- if(v !== undefined) {
87
- yaw = v;
88
- break;
89
- }
90
- }
91
- }
92
- yaw = yaw || 0;
93
-
94
- // Check if yaw is applicable: different from photo direction
95
- if(Math.round(dir) === Math.round(yaw) && yaw > 0) {
96
- console.warn("Picture with UUID", picture.id, "has same GPS Image direction and Yaw, could cause rendering issues");
97
- // yaw = 0;
98
- }
99
-
100
- // Pitch
101
- let pitch = picture.properties?.["pers:pitch"];
102
- exifFallbacks = ["Xmp.GPano.PosePitchDegrees", "Xmp.Camera.Pitch", "Exif.MpfInfo.MPFPitchAngle"];
103
- if(pitch === undefined) {
104
- for(let exif of exifFallbacks) {
105
- const v = getExifFloat(picture.properties?.exif?.[exif]);
106
- if(v !== undefined) {
107
- pitch = v;
108
- break;
109
- }
110
- }
111
- }
112
- pitch = pitch || 0;
113
-
114
- // Roll
115
- let roll = picture.properties?.["pers:roll"];
116
- exifFallbacks = ["Xmp.GPano.PoseRollDegrees", "Xmp.Camera.Roll", "Exif.MpfInfo.MPFRollAngle"];
117
- if(roll === undefined) {
118
- for(let exif of exifFallbacks) {
119
- const v = getExifFloat(picture.properties?.exif?.[exif]);
120
- if(v !== undefined) {
121
- roll = v;
122
- break;
123
- }
124
- }
125
- }
126
- roll = roll || 0;
127
-
128
- // Send result
129
- return pitch !== 0 && roll !== 0 ? {
130
- pan: yaw * Math.PI / 180,
131
- tilt: pitch * Math.PI / 180,
132
- roll: roll * Math.PI / 180,
133
- } : {};
134
- }
135
-
136
- /**
137
- * Compute PSV panoData for cropped panorama based on picture metadata & EXIF tags.
138
- * @param {object} picture The GeoJSON picture feature
139
- * @returns {object} The PSV panoData values
140
- * @private
141
- */
142
- export function getCroppedPanoData(picture) {
143
- let res;
144
-
145
- if(picture.properties?.["pers:interior_orientation"]) {
146
- if(
147
- picture.properties["pers:interior_orientation"]?.["visible_area"]
148
- && picture.properties["pers:interior_orientation"]?.["sensor_array_dimensions"]
149
- ) {
150
- const va = picture.properties["pers:interior_orientation"]["visible_area"];
151
- const sad = picture.properties["pers:interior_orientation"]["sensor_array_dimensions"];
152
- try {
153
- res = {
154
- fullWidth: parseInt(sad[0]),
155
- fullHeight: parseInt(sad[1]),
156
- croppedX: parseInt(va[0]),
157
- croppedY: parseInt(va[1]),
158
- croppedWidth: parseInt(sad[0]) - parseInt(va[2]) - parseInt(va[0]),
159
- croppedHeight: parseInt(sad[1]) - parseInt(va[3]) - parseInt(va[1]),
160
- };
161
- }
162
- catch(e) {
163
- console.warn("Invalid pers:interior_orientation values for cropped panorama "+picture.id);
164
- }
165
- }
166
- }
167
-
168
- if(!res && picture.properties?.exif) {
169
- try {
170
- res = {
171
- fullWidth: parseInt(picture.properties.exif?.["Xmp.GPano.FullPanoWidthPixels"]),
172
- fullHeight: parseInt(picture.properties.exif?.["Xmp.GPano.FullPanoHeightPixels"]),
173
- croppedX: parseInt(picture.properties.exif?.["Xmp.GPano.CroppedAreaLeftPixels"]),
174
- croppedY: parseInt(picture.properties.exif?.["Xmp.GPano.CroppedAreaTopPixels"]),
175
- croppedWidth: parseInt(picture.properties.exif?.["Xmp.GPano.CroppedAreaImageWidthPixels"]),
176
- croppedHeight: parseInt(picture.properties.exif?.["Xmp.GPano.CroppedAreaImageHeightPixels"]),
177
- };
178
- }
179
- catch(e) {
180
- console.warn("Invalid XMP.GPano values for cropped panorama "+picture.id);
181
- }
182
- }
183
-
184
- // Check if crop is really necessary
185
- if(res) {
186
- res = Object.fromEntries(Object.entries(res || {}).filter(e => !isNaN(e[1])));
187
- if(res.fullWidth == res.croppedWidth && res.fullHeight == res.croppedHeight) {
188
- res = {};
189
- }
190
- }
191
-
192
- return res || {};
193
- }