@panoramax/web-viewer 4.0.3 → 4.1.0-develop-e5370cde

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 (106) hide show
  1. package/CHANGELOG.md +45 -1
  2. package/build/index.css +9 -9
  3. package/build/index.css.map +1 -1
  4. package/build/index.js +640 -456
  5. package/build/index.js.map +1 -1
  6. package/build/map.html +1 -1
  7. package/build/photo.html +1 -1
  8. package/build/viewer.html +3 -3
  9. package/build/widgets.html +1 -1
  10. package/config/jest/mocks.js +9 -1
  11. package/docs/03_URL_settings.md +21 -0
  12. package/docs/09_Develop.md +6 -0
  13. package/docs/images/comparative_3drender.jpg +0 -0
  14. package/docs/index.md +13 -0
  15. package/docs/reference/components/core/Editor.md +18 -0
  16. package/docs/reference/components/core/PhotoViewer.md +1 -0
  17. package/docs/reference/components/core/Viewer.md +1 -0
  18. package/docs/reference/components/menus/MapLegend.md +17 -0
  19. package/docs/reference/components/menus/MiniPictureLegend.md +15 -0
  20. package/docs/reference/components/menus/PictureLegend.md +17 -0
  21. package/docs/reference/components/ui/AnnotationsSwitch.md +15 -0
  22. package/docs/reference/components/ui/Button.md +1 -1
  23. package/docs/reference/components/ui/CopyButton.md +1 -1
  24. package/docs/reference/components/ui/LinkButton.md +1 -1
  25. package/docs/reference/components/ui/Map.md +18 -2
  26. package/docs/reference/components/ui/MapMore.md +6 -2
  27. package/docs/reference/components/ui/SemanticsEditor.md +87 -0
  28. package/docs/reference/components/ui/widgets/Legend.md +5 -4
  29. package/docs/reference/utils/URLHandler.md +7 -0
  30. package/docs/reference.md +3 -1
  31. package/docs/tutorials/aerial_imagery.md +13 -11
  32. package/mkdocs.yml +3 -1
  33. package/package.json +7 -7
  34. package/public/map.html +3 -3
  35. package/public/photo.html +1 -1
  36. package/public/viewer.html +3 -3
  37. package/public/widgets.html +32 -0
  38. package/src/components/core/Basic.css +2 -0
  39. package/src/components/core/Basic.js +3 -1
  40. package/src/components/core/CoverageMap.css +1 -0
  41. package/src/components/core/CoverageMap.js +6 -0
  42. package/src/components/core/Editor.css +2 -0
  43. package/src/components/core/Editor.js +56 -7
  44. package/src/components/core/PhotoViewer.css +10 -10
  45. package/src/components/core/PhotoViewer.js +56 -23
  46. package/src/components/core/Viewer.css +14 -2
  47. package/src/components/core/Viewer.js +62 -33
  48. package/src/components/layout/BottomDrawer.js +2 -1
  49. package/src/components/layout/Tabs.js +4 -0
  50. package/src/components/menus/AnnotationsList.js +13 -9
  51. package/src/components/menus/MapBackground.js +8 -3
  52. package/src/components/menus/MapFilters.js +11 -2
  53. package/src/components/menus/MapLayers.js +3 -2
  54. package/src/components/menus/MapLegend.js +35 -4
  55. package/src/components/menus/MiniPictureLegend.js +74 -0
  56. package/src/components/menus/PictureLegend.js +88 -33
  57. package/src/components/menus/PictureMetadata.js +49 -17
  58. package/src/components/menus/PlayerOptions.js +3 -3
  59. package/src/components/menus/Share.js +3 -3
  60. package/src/components/menus/index.js +5 -4
  61. package/src/components/styles.js +11 -0
  62. package/src/components/ui/AnnotationsSwitch.js +171 -0
  63. package/src/components/ui/Button.js +1 -1
  64. package/src/components/ui/CopyButton.js +1 -1
  65. package/src/components/ui/LinkButton.js +1 -1
  66. package/src/components/ui/Map.css +4 -0
  67. package/src/components/ui/Map.js +17 -5
  68. package/src/components/ui/MapMore.js +61 -25
  69. package/src/components/ui/Photo.css +11 -2
  70. package/src/components/ui/Photo.js +6 -3
  71. package/src/components/ui/SemanticsEditor.js +157 -0
  72. package/src/components/ui/index.js +2 -1
  73. package/src/components/ui/widgets/GeoSearch.js +3 -2
  74. package/src/components/ui/widgets/Legend.js +76 -15
  75. package/src/components/ui/widgets/MapFiltersButton.js +3 -3
  76. package/src/components/ui/widgets/MapLayersButton.js +3 -3
  77. package/src/components/ui/widgets/OSMEditors.js +2 -2
  78. package/src/components/ui/widgets/PictureLegendActions.js +24 -42
  79. package/src/components/ui/widgets/Player.js +3 -3
  80. package/src/components/ui/widgets/Zoom.js +4 -2
  81. package/src/translations/ar.json +1 -0
  82. package/src/translations/da.json +3 -2
  83. package/src/translations/de.json +64 -13
  84. package/src/translations/en.json +5 -1
  85. package/src/translations/eo.json +32 -2
  86. package/src/translations/fr.json +7 -1
  87. package/src/translations/it.json +33 -2
  88. package/src/translations/nl.json +53 -11
  89. package/src/translations/zh_Hant.json +29 -2
  90. package/src/utils/API.js +17 -1
  91. package/src/utils/InitParameters.js +46 -4
  92. package/src/utils/URLHandler.js +9 -1
  93. package/src/utils/map.js +24 -1
  94. package/src/utils/semantics.js +53 -1
  95. package/src/utils/services.js +16 -0
  96. package/src/utils/widgets.js +38 -0
  97. package/tests/components/core/Editor.test.js +1 -1
  98. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +18 -6
  99. package/tests/components/core/__snapshots__/Viewer.test.js.snap +15 -3
  100. package/tests/components/ui/Photo.test.js +1 -0
  101. package/tests/components/ui/__snapshots__/Map.test.js.snap +164 -0
  102. package/tests/utils/InitParameters.test.js +27 -0
  103. package/tests/utils/map.test.js +12 -0
  104. package/tests/utils/semantics.test.js +34 -5
  105. package/docs/reference/components/ui/HashTags.md +0 -15
  106. package/src/components/ui/HashTags.js +0 -98
@@ -7,6 +7,7 @@
7
7
  * [.URLHandler](#Panoramax.utils.URLHandler)
8
8
  * [new URLHandler(parent)](#new_Panoramax.utils.URLHandler_new)
9
9
  * [.listenToChanges()](#Panoramax.utils.URLHandler+listenToChanges)
10
+ * [.destroy()](#Panoramax.utils.URLHandler+destroy)
10
11
  * [.nextURLParams()](#Panoramax.utils.URLHandler+nextURLParams) ⇒ <code>object</code>
11
12
  * [.nextURLString()](#Panoramax.utils.URLHandler+nextURLString) ⇒ <code>string</code>
12
13
  * [.currentURLParams([readFromHash])](#Panoramax.utils.URLHandler+currentURLParams) ⇒ <code>object</code>
@@ -34,6 +35,12 @@ Note that you may call `listenToChanges()` for this class to be effective once p
34
35
  Start listening to URL & parent changes through events.
35
36
  This leads to parent & URL updates.
36
37
 
38
+ **Kind**: instance method of [<code>URLHandler</code>](#Panoramax.utils.URLHandler)
39
+ <a name="Panoramax.utils.URLHandler+destroy"></a>
40
+
41
+ ### urlHandler.destroy()
42
+ Call this function to stop listening to global events.
43
+
37
44
  **Kind**: instance method of [<code>URLHandler</code>](#Panoramax.utils.URLHandler)
38
45
  <a name="Panoramax.utils.URLHandler+nextURLParams"></a>
39
46
 
package/docs/reference.md CHANGED
@@ -30,6 +30,7 @@ All-in-one, ready-to-use menus for complex operations. Note that they don't embe
30
30
  - [MapFilters](./reference/components/menus/MapFilters.md) : set map filters.
31
31
  - [MapLayers](./reference/components/menus/MapLayers.md) : change map theme and background.
32
32
  - [MapLegend](./reference/components/menus/MapLegend.md) : display map sources and Panoramax info.
33
+ - [MiniPictureLegend](./reference/components/menus/PictureLegend.md) : display date of a picture when it's shown reduced.
33
34
  - [PictureLegend](./reference/components/menus/PictureLegend.md) : display date, author and info for a picture.
34
35
  - [PictureMetadata](./reference/components/menus/PictureMetadata.md) : display full details about a picture.
35
36
  - [PlayerOptions](./reference/components/menus/PlayerOptions.md) : speed and constrast settings for play sequence feature.
@@ -41,11 +42,11 @@ All-in-one, ready-to-use menus for complex operations. Note that they don't embe
41
42
 
42
43
  Basic UI components:
43
44
 
45
+ - [AnnotationsSwitch](./reference/components/ui/AnnotationsSwitch.md) : a switch button for showing/hiding picture annotations.
44
46
  - [Button](./reference/components/ui/Button.md) : a simple button.
45
47
  - [ButtonGroup](./reference/components/ui/ButtonGroup.md) : button bar.
46
48
  - [CopyButton](./reference/components/ui/CopyButton.md) : a copy-to-clipboard button.
47
49
  - [Grade](./reference/components/ui/Grade.md) : a 5-star rating display.
48
- - [HashTags](./reference/components/ui/HashTags.md) : a list of hashtags associated to a picture.
49
50
  - [LinkButton](./reference/components/ui/LinkButton.md) : a link button.
50
51
  - [ListGroup](./reference/components/ui/ListGroup.md) : a menu-like list of buttons and links.
51
52
  - [ListItem](./reference/components/ui/ListItem.md) : a Material Design-like list entry.
@@ -57,6 +58,7 @@ Basic UI components:
57
58
  - [ProgressBar](./reference/components/ui/ProgressBar.md) : a progress bar.
58
59
  - [QualityScore](./reference/components/ui/QualityScore.md) : a A/B/C/D/E grade display and input.
59
60
  - [SearchBar](./reference/components/ui/SearchBar.md) : a search bar.
61
+ - [SemanticsEditor](./reference/components/ui/SemanticsEditor.md) : input field for editing semantic tags of a picture/annotation.
60
62
  - [SemanticsTable](./reference/components/ui/SemanticsTable.md) : table for showing complete semantic tags of a picture/annotation.
61
63
  - [TogglableGroup](./reference/components/ui/TogglableGroup.md) : an helper for showing a menu on button click.
62
64
 
@@ -5,15 +5,17 @@ In complement of classic _streets_ rendering, you can add an aerial imagery as m
5
5
  ```html
6
6
  <pnx-viewer
7
7
  endpoint="https://panoramax.ign.fr/api"
8
- map='{"raster": {
9
- "type": "raster",
10
- "tiles": [
11
- "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}"
12
- ],
13
- "minzoom": 0,
14
- "maxzoom": 21,
15
- "attribution": "&copy; IGN",
16
- "tileSize": 256
17
- }}'
18
- />
8
+ map='{
9
+ raster: {
10
+ type: "raster",
11
+ tiles: [
12
+ "https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTHOIMAGERY.ORTHOPHOTOS&STYLE=normal&FORMAT=image/jpeg&TILEMATRIXSET=PM_0_19&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}"
13
+ ],
14
+ minzoom: 0,
15
+ maxzoom: 19,
16
+ attribution: "&copy; IGN",
17
+ tileSize: 256
18
+ }
19
+ }'
20
+ ></pnx-viewer>
19
21
  ```
package/mkdocs.yml CHANGED
@@ -70,6 +70,7 @@ nav:
70
70
  - MapFilters: 'reference/components/menus/MapFilters.md'
71
71
  - MapLayers: 'reference/components/menus/MapLayers.md'
72
72
  - MapLegend: 'reference/components/menus/MapLegend.md'
73
+ - MiniPictureLegend: 'reference/components/menus/MiniPictureLegend.md'
73
74
  - PictureLegend: 'reference/components/menus/PictureLegend.md'
74
75
  - PictureMetadata: 'reference/components/menus/PictureMetadata.md'
75
76
  - PlayerOptions: 'reference/components/menus/PlayerOptions.md'
@@ -87,11 +88,11 @@ nav:
87
88
  - PictureLegendActions: 'reference/components/ui/widgets/PictureLegendActions.md'
88
89
  - Player: 'reference/components/ui/widgets/Player.md'
89
90
  - Zoom: 'reference/components/ui/widgets/Zoom.md'
91
+ - AnnotationsSwitch: 'reference/components/ui/AnnotationsSwitch.md'
90
92
  - Button: 'reference/components/ui/Button.md'
91
93
  - ButtonGroup: 'reference/components/ui/ButtonGroup.md'
92
94
  - CopyButton: 'reference/components/ui/CopyButton.md'
93
95
  - Grade: 'reference/components/ui/Grade.md'
94
- - HashTags: 'reference/components/ui/HashTags.md'
95
96
  - LinkButton: 'reference/components/ui/LinkButton.md'
96
97
  - ListGroup: 'reference/components/ui/ListGroup.md'
97
98
  - ListItem: 'reference/components/ui/ListItem.md'
@@ -103,6 +104,7 @@ nav:
103
104
  - ProgressBar: 'reference/components/ui/ProgressBar.md'
104
105
  - QualityScore: 'reference/components/ui/QualityScore.md'
105
106
  - SearchBar: 'reference/components/ui/SearchBar.md'
107
+ - SemanticsEditor: 'reference/components/ui/SemanticsEditor.md'
106
108
  - SemanticsTable: 'reference/components/ui/SemanticsTable.md'
107
109
  - TogglableGroup: 'reference/components/ui/TogglableGroup.md'
108
110
  - utils:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panoramax/web-viewer",
3
- "version": "4.0.3",
3
+ "version": "4.1.0-develop-e5370cde",
4
4
  "description": "Panoramax web viewer for geolocated pictures",
5
5
  "main": "build/index.js",
6
6
  "author": "Panoramax team",
@@ -93,15 +93,15 @@
93
93
  "@fortawesome/fontawesome-svg-core": "^6.7.2",
94
94
  "@fortawesome/free-regular-svg-icons": "^6.7.2",
95
95
  "@fortawesome/free-solid-svg-icons": "^6.7.2",
96
- "@photo-sphere-viewer/core": "5.12.1",
97
- "@photo-sphere-viewer/equirectangular-tiles-adapter": "5.12.1",
98
- "@photo-sphere-viewer/gallery-plugin": "5.12.1",
99
- "@photo-sphere-viewer/markers-plugin": "5.12.1",
100
- "@photo-sphere-viewer/virtual-tour-plugin": "5.12.1",
96
+ "@photo-sphere-viewer/core": "5.13.3",
97
+ "@photo-sphere-viewer/equirectangular-tiles-adapter": "5.13.3",
98
+ "@photo-sphere-viewer/gallery-plugin": "5.13.3",
99
+ "@photo-sphere-viewer/markers-plugin": "5.13.3",
100
+ "@photo-sphere-viewer/virtual-tour-plugin": "5.13.3",
101
101
  "iconify-icon": "^3.0.0",
102
102
  "json5": "^2.2.3",
103
103
  "lit": "^3.2.1",
104
- "maplibre-gl": "^5.3.0",
104
+ "maplibre-gl": "^5.6.0",
105
105
  "pmtiles": "^4.3.0",
106
106
  "query-selector-shadow-dom": "^1.0.1"
107
107
  },
package/public/map.html CHANGED
@@ -5,13 +5,13 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6
6
  <title>Panoramax Coverage Map</title>
7
7
  <style>
8
- #map {
8
+ #coverage {
9
9
  position: relative;
10
10
  width: 95%;
11
11
  margin: 2.5%;
12
12
  height: 400px;
13
13
  }
14
- #map.fullpage {
14
+ #coverage.fullpage {
15
15
  position: fixed;
16
16
  top: 0;
17
17
  bottom: 0;
@@ -32,7 +32,7 @@
32
32
  id="coverage"
33
33
  class="fullpage"
34
34
  endpoint="https://api.panoramax.xyz/api"
35
- />
35
+ ></pnx-coverage-map>
36
36
 
37
37
  <script>
38
38
  // Retrieve component from DOM
package/public/photo.html CHANGED
@@ -33,7 +33,7 @@
33
33
  class="fullpage"
34
34
  sequence="ecfe4b2c-0acd-4d3a-a10d-c3e6818755c8"
35
35
  picture="329af5c6-4761-4a6d-9c1e-674fd6daa8b6"
36
- />
36
+ ></pnx-photo-viewer>
37
37
 
38
38
  <script>
39
39
  var servers = {
@@ -35,15 +35,15 @@
35
35
  raster: {
36
36
  type: "raster",
37
37
  tiles: [
38
- "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}"
38
+ "https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ORTHOIMAGERY.ORTHOPHOTOS&STYLE=normal&FORMAT=image/jpeg&TILEMATRIXSET=PM_0_19&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}"
39
39
  ],
40
40
  minzoom: 0,
41
- maxzoom: 21,
41
+ maxzoom: 19,
42
42
  attribution: "&copy; IGN",
43
43
  tileSize: 256
44
44
  }
45
45
  }'
46
- />
46
+ ></pnx-viewer>
47
47
 
48
48
  <script>
49
49
  var servers = {
@@ -39,6 +39,7 @@
39
39
  <a href="#search-bar">Search bar</a>
40
40
  <a href="#progress-bar">Progress bar</a>
41
41
  <a href="#tabs">Tabs</a>
42
+ <a href="#semantics-editor">Semantics Editor</a>
42
43
  </nav>
43
44
 
44
45
  <h2 id="button">Button</h2>
@@ -302,5 +303,36 @@
302
303
  <div slot="content">Tab 3 content</div>
303
304
  </pnx-tabs>
304
305
  </div>
306
+
307
+ <h2 id="semantics-editor">Semantics editor</h2>
308
+ <script>
309
+ window.addEventListener("load", () => {
310
+ const semeditors = document.getElementsByTagName("pnx-semantics-editor");
311
+ for(let i=0; i < semeditors.length; i++) {
312
+ const semeditor = semeditors[i];
313
+ const div = semeditor.nextSibling;
314
+ semeditor.addEventListener("change", e => {
315
+ console.log("Semantics change > evt =", e.detail, "| attr =", semeditor.getAttribute("semantics"));
316
+ });
317
+ }
318
+ });
319
+ </script>
320
+ <div class="test-bench">
321
+ <h3>Empty</h3>
322
+ <pnx-semantics-editor _t='{"pnx": {"semantics_editor_error": "The syntax is invalid. Your tags may look like:\nkey=value\nprefix|key=value\nprefix|key[qualif_key=qualif_val]=value"}}'></pnx-semantics-editor>
323
+ </div>
324
+ <div class="test-bench">
325
+ <h3>Filled</h3>
326
+ <pnx-semantics-editor semantics="[{key: 'osm|traffic_sign', value: 'FR:A14b'}]"></pnx-semantics-editor>
327
+ </div>
328
+ <div class="test-bench">
329
+ <h3>Many rows</h3>
330
+ <pnx-semantics-editor rows="5" semantics="[{key: 'osm|traffic_sign', value: 'FR:A14b'}]"></pnx-semantics-editor>
331
+ </div>
332
+ <div class="test-bench">
333
+ <h3>Custom style</h3>
334
+ <style>#pnx-sem-ed3::part(text) { color: blue; }</style>
335
+ <pnx-semantics-editor id="pnx-sem-ed3" semantics="[{key: 'osm|traffic_sign', value: 'FR:A14b'}]"></pnx-semantics-editor>
336
+ </div>
305
337
  </body>
306
338
  </html>
@@ -28,11 +28,13 @@
28
28
  --widget-bg-inactive: var(--grey-pale);
29
29
  --widget-bg-primary: var(--blue-semi);
30
30
  --widget-bg-primary-hover: #e0e7ff;
31
+ --widget-bg-warn: #FFECB3;
31
32
  --widget-border-div: var(--grey-pale);
32
33
  --widget-border-btn: var(--blue);
33
34
  --widget-font: var(--grey-dark);
34
35
  --widget-font-active: var(--white);
35
36
  --widget-font-direct: var(--blue);
37
+ --widget-font-warn: #BF360C;
36
38
  --font-family: "Atkinson Hyperlegible Next", sans-serif;
37
39
  overscroll-behavior-y: contain;
38
40
  }
@@ -341,7 +341,9 @@ export default class Basic extends LitElement {
341
341
  static GetJSONConverter() {
342
342
  return {
343
343
  fromAttribute: (value) => {
344
- return typeof value === "object" ? value : JSON5.parse(value);
344
+ if(value === null || value === "") { return null; }
345
+ else if(typeof value === "object" || Array.isArray(value)) { return value; }
346
+ else { return JSON5.parse(value); }
345
347
  },
346
348
  toAttribute: (value) => JSON.stringify(value)
347
349
  };
@@ -1,5 +1,6 @@
1
1
  pnx-coverage-map {
2
2
  display: block;
3
+ position: relative;
3
4
  }
4
5
 
5
6
  pnx-coverage-map .maplibregl-map {
@@ -59,6 +59,12 @@ export default class CoverageMap extends Basic {
59
59
  });
60
60
  }
61
61
 
62
+ /** @private */
63
+ disconnectedCallback() {
64
+ super.disconnectedCallback();
65
+ this.map?.destroy();
66
+ }
67
+
62
68
  getClassName() {
63
69
  return "CoverageMap";
64
70
  }
@@ -2,6 +2,7 @@
2
2
  pnx-editor {
3
3
  display: flex;
4
4
  flex-direction: column;
5
+ position: relative;
5
6
  }
6
7
 
7
8
  pnx-editor .pnx-map,
@@ -20,4 +21,5 @@ pnx-editor pnx-map-background {
20
21
  color: var(--widget-font);
21
22
  bottom: 10px;
22
23
  left: 10px;
24
+ font-family: var(--font-family);
23
25
  }
@@ -3,13 +3,10 @@ import "./Editor.css";
3
3
  import Basic from "./Basic";
4
4
  import Map from "../ui/Map";
5
5
  import Photo from "../ui/Photo";
6
- import BackgroundAerial from "../../img/bg_aerial.jpg";
7
- import BackgroundStreets from "../../img/bg_streets.jpg";
8
6
  import { apiFeatureToPSVNode } from "../../utils/picture";
9
7
  import { linkMapAndPhoto } from "../../utils/map";
10
8
  import { VECTOR_STYLES } from "../../utils/map";
11
9
  import { SYSTEM as PSSystem } from "@photo-sphere-viewer/core";
12
- import { css } from "lit";
13
10
  import { createWebComp } from "../../utils/widgets";
14
11
 
15
12
  const LAYER_HEADING_ID = "sequence-headings";
@@ -19,6 +16,8 @@ const LAYER_HEADING_ID = "sequence-headings";
19
16
  * It shows both picture and map.
20
17
  *
21
18
  * Make sure to set width/height through CSS for proper display.
19
+ *
20
+ * This component has a [CorneredGrid](#Panoramax.components.layout.CorneredGrid) layout, you can use directly any slot element to pass custom widgets.
22
21
  * @class Panoramax.components.core.Editor
23
22
  * @element pnx-editor
24
23
  * @extends Panoramax.components.core.Basic
@@ -29,12 +28,28 @@ const LAYER_HEADING_ID = "sequence-headings";
29
28
  * @property {Panoramax.utils.API} api The API manager
30
29
  * @property {Panoramax.components.ui.Map} map The MapLibre GL map itself
31
30
  * @property {Panoramax.components.ui.Photo} psv The Photo Sphere Viewer component itself
31
+ * @property {Panoramax.components.layout.CorneredGrid} grid The grid layout manager
32
+ * @slot `top-left` The top-left corner
33
+ * @slot `top` The top middle corner
34
+ * @slot `top-right` The top-right corner
35
+ * @slot `bottom-left` The bottom-left corner
36
+ * @slot `bottom` The bottom middle corner
37
+ * @slot `bottom-right` The bottom-right corner
32
38
  * @example
33
39
  * ```html
40
+ * <!-- Basic example -->
34
41
  * <pnx-editor
35
42
  * endpoint="https://panoramax.openstreetmap.fr/"
36
43
  * style="width: 300px; height: 250px"
37
44
  * />
45
+ *
46
+ * <!-- With slotted widgets -->
47
+ * <pnx-editor
48
+ * endpoint="https://panoramax.openstreetmap.fr/"
49
+ * style="width: 300px; height: 250px"
50
+ * >
51
+ * <p slot="top-right">My custom text</p>
52
+ * </pnx-editor>
38
53
  * ```
39
54
  */
40
55
  export default class Editor extends Basic {
@@ -67,7 +82,13 @@ export default class Editor extends Basic {
67
82
 
68
83
  // Create sub-containers
69
84
  this._psvContainer = document.createElement("div");
85
+ this._psvContainer.setAttribute("slot", "bg");
70
86
  this._mapContainer = document.createElement("div");
87
+ this._mapContainer.setAttribute("slot", "bg");
88
+
89
+ this.grid = createWebComp("pnx-cornered-grid");
90
+ this.grid.appendChild(this._psvContainer);
91
+ this.grid.appendChild(this._mapContainer);
71
92
 
72
93
  this.onceAPIReady().then(() => {
73
94
  this.loader.setAttribute("value", 30);
@@ -83,6 +104,13 @@ export default class Editor extends Basic {
83
104
  });
84
105
  }
85
106
 
107
+ /** @private */
108
+ disconnectedCallback() {
109
+ super.disconnectedCallback();
110
+ this.map?.destroy();
111
+ this.psv?.destroy();
112
+ }
113
+
86
114
  getClassName() {
87
115
  return "Editor";
88
116
  }
@@ -102,6 +130,10 @@ export default class Editor extends Basic {
102
130
  this.users = [];
103
131
  }
104
132
  super.connectedCallback();
133
+
134
+ window.addEventListener("DOMContentLoaded", () => {
135
+ this._moveChildToGrid();
136
+ }, { once: true });
105
137
  }
106
138
 
107
139
  attributeChangedCallback(name, old, value) {
@@ -115,11 +147,11 @@ export default class Editor extends Basic {
115
147
 
116
148
  /** @private */
117
149
  render() {
118
- return [this.loader, this._psvContainer, this._mapContainer];
150
+ return [this.loader, this.grid];
119
151
  }
120
152
 
121
153
  getSubComponentsNames() {
122
- return super.getSubComponentsNames().concat(["map", "psv"]);
154
+ return super.getSubComponentsNames().concat(["map", "psv", "grid"]);
123
155
  }
124
156
 
125
157
  /** @private */
@@ -142,6 +174,7 @@ export default class Editor extends Basic {
142
174
  background: this.background,
143
175
  supplementaryStyle: this._createMapStyle(),
144
176
  zoom: 15, // Hack to avoid _initMapPosition call
177
+ picMarkerDraggable: true,
145
178
  });
146
179
  linkMapAndPhoto(this);
147
180
  this.loader.setAttribute("value", 50);
@@ -243,6 +276,7 @@ export default class Editor extends Basic {
243
276
  "type": "FeatureCollection",
244
277
  "features": [
245
278
  {
279
+ "id": this.sequence,
246
280
  "type": "Feature",
247
281
  "properties": {
248
282
  "id": this.sequence,
@@ -312,8 +346,23 @@ export default class Editor extends Basic {
312
346
  */
313
347
  _addMapBackgroundWidget() {
314
348
  // Container
315
- const pnlLayers = createWebComp("pnx-map-background", {_parent: this, size: "sm"});
316
- this._mapContainer.appendChild(pnlLayers);
349
+ const pnlLayers = createWebComp("pnx-map-background", {_parent: this, size: "sm", slot: "bottom-left"});
350
+ this.grid.appendChild(pnlLayers);
351
+ }
352
+
353
+ /** @private */
354
+ _moveChildToGrid() {
355
+ const slotContent = Array.from(this.querySelectorAll("[slot]"));
356
+
357
+ slotContent.forEach(n => {
358
+ // Add parent + translation for our components
359
+ if(n.tagName?.toLowerCase().startsWith("pnx-")) {
360
+ n._parent = this;
361
+ n._t = this._t;
362
+ }
363
+
364
+ this.grid.appendChild(n);
365
+ });
317
366
  }
318
367
 
319
368
  /**
@@ -1,3 +1,8 @@
1
+ pnx-photo-viewer {
2
+ position: relative;
3
+ display: block;
4
+ }
5
+
1
6
  /* Maximized components */
2
7
  pnx-photo-viewer .pnx-psv {
3
8
  position: absolute;
@@ -35,14 +40,9 @@ pnx-photo-viewer pnx-cornered-grid::part(corner-bottom-right) {
35
40
  }
36
41
  }
37
42
 
38
- @media screen and (min-width: 576px) {
39
- pnx-photo-viewer pnx-widget-legend {
40
- position: absolute;
41
- left: 10px;
42
- top: 60px;
43
- }
44
-
45
- pnx-photo-viewer pnx-widget-legend {
46
- top: 10px;
47
- }
43
+ /* Hidden widgets on sequence play */
44
+ pnx-photo-viewer.pnx-playing pnx-bottom-drawer,
45
+ pnx-photo-viewer.pnx-playing pnx-widget-legend,
46
+ pnx-photo-viewer.pnx-playing pnx-widget-zoom {
47
+ display: none;
48
48
  }
@@ -7,13 +7,14 @@ import URLHandler from "../../utils/URLHandler";
7
7
  import Basic from "./Basic";
8
8
  import Photo, { PSV_DEFAULT_ZOOM, PSV_ANIM_DURATION } from "../ui/Photo";
9
9
  import { createWebComp } from "../../utils/widgets";
10
- import { isNullId } from "../../utils/utils";
10
+ import { isNullId, isInIframe } from "../../utils/utils";
11
11
  import { default as InitParameters, alterPSVState, alterMapState, alterPhotoViewerState } from "../../utils/InitParameters";
12
12
  import PresetManager from "../../utils/PresetsManager";
13
13
 
14
14
 
15
15
  export const PSV_ZOOM_DELTA = 20;
16
16
  const PSV_MOVE_DELTA = Math.PI / 6;
17
+ export const KEYBOARD_SKIP_FOCUS_WIDGETS = ["pnx-mini", "pnx-widget-player", "pnx-widget-zoom"];
17
18
 
18
19
 
19
20
  /**
@@ -85,11 +86,13 @@ export default class PhotoViewer extends Basic {
85
86
  * @property {object} [fetchOptions] 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))
86
87
  * @property {string} [lang] To override language used for labels. Defaults to using user's preferred languages.
87
88
  * @property {string} [url-parameters=true] Should the component add and update URL query parameters to save viewer state ?
89
+ * @property {string} [keyboard-shortcuts=true] Should keyboard shortcuts be enabled ? Set to "false" to fully disable any keyboard shortcuts.
88
90
  */
89
91
  static properties = {
90
92
  psv: {converter: Basic.GetJSONConverter()},
91
93
  widgets: {type: String},
92
94
  "url-parameters": {type: String},
95
+ "keyboard-shortcuts": {type: String},
93
96
  ...Basic.properties
94
97
  };
95
98
 
@@ -99,6 +102,7 @@ export default class PhotoViewer extends Basic {
99
102
  // Defaults
100
103
  this.psv = {};
101
104
  this["url-parameters"] = this.getAttribute("url-parameters") || true;
105
+ this["keyboard-shortcuts"] = this.getAttribute("keyboard-shortcuts") || true;
102
106
  this.widgets = this.getAttribute("widgets") || "true";
103
107
 
104
108
  // Init DOM containers
@@ -121,14 +125,33 @@ export default class PhotoViewer extends Basic {
121
125
  /** @private */
122
126
  _initWidgets() {
123
127
  if(this._initParams.getParentPostInit().widgets !== "false") {
124
- this.grid.appendChild(createWebComp("pnx-widget-player", {
125
- slot: "top",
126
- _parent: this,
127
- class: "pnx-only-psv pnx-print-hidden",
128
- size: this.isHeightSmall() ? "md": "xl",
129
- }));
130
-
131
- if(!this.isWidthSmall()) {
128
+ if(!isInIframe()) {
129
+ this.grid.appendChild(createWebComp("pnx-widget-player", {
130
+ slot: "top",
131
+ _parent: this,
132
+ class: "pnx-only-psv pnx-print-hidden",
133
+ size: this.isHeightSmall() ? "md": "xl",
134
+ }));
135
+
136
+ this.grid.appendChild(createWebComp("pnx-annotations-switch", {
137
+ slot: "top",
138
+ _parent: this,
139
+ class: "pnx-only-psv pnx-print-hidden",
140
+ size: this.isHeightSmall() ? "md": "xl",
141
+ }));
142
+ }
143
+
144
+ if(isInIframe()) {
145
+ this.legend = createWebComp("pnx-widget-legend", {
146
+ slot: "bottom-right",
147
+ light: true,
148
+ _parent: this,
149
+ focus: this._initParams.getParentPostInit().focus,
150
+ picture: this._initParams.getParentPostInit().picture,
151
+ });
152
+ this.grid.appendChild(this.legend);
153
+ }
154
+ else if(!this.isWidthSmall()) {
132
155
  this.legend = createWebComp("pnx-widget-legend", {
133
156
  slot: !this.isWidthSmall() ? "top-left" : undefined,
134
157
  _parent: this,
@@ -142,12 +165,6 @@ export default class PhotoViewer extends Basic {
142
165
  _parent: this
143
166
  }));
144
167
  this.grid.appendChild(this.legend);
145
-
146
- this.grid.appendChild(createWebComp("pnx-hashtags", {
147
- slot: "top-right",
148
- _parent: this,
149
- class: "pnx-only-psv pnx-print-hidden",
150
- }));
151
168
  }
152
169
  else {
153
170
  this.legend = createWebComp("pnx-picture-legend", { _parent: this });
@@ -181,12 +198,17 @@ export default class PhotoViewer extends Basic {
181
198
  }
182
199
 
183
200
  this.onceAPIReady().then(this._postAPIInit.bind(this));
201
+
202
+ window.addEventListener("DOMContentLoaded", () => {
203
+ this._moveChildToGrid();
204
+ }, { once: true });
184
205
  }
185
206
 
186
207
  /** @private */
187
- firstUpdated() {
188
- super.firstUpdated();
189
- this._moveChildToGrid();
208
+ disconnectedCallback() {
209
+ super.disconnectedCallback();
210
+ this.urlHandler?.destroy();
211
+ this.psv?.destroy();
190
212
  }
191
213
 
192
214
  getClassName() {
@@ -266,7 +288,10 @@ export default class PhotoViewer extends Basic {
266
288
  this._initPSV();
267
289
  this._initWidgets();
268
290
  alterPhotoViewerState(this, myPostInitParams);
269
- this._handleKeyboardManagement();
291
+
292
+ if(myPostInitParams.keyboardShortcuts) {
293
+ this._handleKeyboardManagement();
294
+ }
270
295
 
271
296
  if(myPostInitParams.picture) {
272
297
  this.psv.addEventListener("picture-loaded", () => this.loader.dismiss(), {once: true});
@@ -313,6 +338,10 @@ export default class PhotoViewer extends Basic {
313
338
  this.loader.setAttribute("value", 50);
314
339
  alterPSVState(this.psv, this._initParams.getPSVPostInit());
315
340
  });
341
+
342
+ // Show class when PSV is playing sequence
343
+ this.psv.addEventListener("sequence-playing", () => this.classList.add("pnx-playing"));
344
+ this.psv.addEventListener("sequence-stopped", () => this.classList.remove("pnx-playing"));
316
345
  }
317
346
  catch(e) {
318
347
  let err = !PSSystem.isWebGLSupported ? this._t.pnx.error_webgl : this._t.pnx.error_psv;
@@ -327,13 +356,17 @@ export default class PhotoViewer extends Basic {
327
356
  const keytopsv = () => this.psv.startKeyboardControl();
328
357
 
329
358
  // Popup
330
- this.popup.addEventListener("open", () => keytonone());
331
- this.popup.addEventListener("close", () => keytopsv());
359
+ this.popup.addEventListener("open", keytonone);
360
+ this.popup.addEventListener("close", keytopsv);
361
+ this.psv.addEventListener("click", keytopsv);
332
362
 
333
363
  // Widgets
334
364
  for(let cn of this.grid.childNodes) {
335
- if(cn.getAttribute("slot") !== "bg") {
336
- cn.addEventListener("focusin", () => keytonone());
365
+ if(
366
+ cn.getAttribute("slot") !== "bg"
367
+ && !KEYBOARD_SKIP_FOCUS_WIDGETS.includes(cn.tagName.toLowerCase())
368
+ ) {
369
+ cn.addEventListener("focusin", keytonone);
337
370
  cn.addEventListener("focusout", () => {
338
371
  if(this.popup.getAttribute("visible") === null) {
339
372
  keytopsv();
@@ -1,3 +1,8 @@
1
+ pnx-viewer {
2
+ position: relative;
3
+ display: block;
4
+ }
5
+
1
6
  /* Maximized components */
2
7
  pnx-viewer .pnx-map.maplibregl-map,
3
8
  pnx-viewer .pnx-psv {
@@ -56,7 +61,6 @@ pnx-viewer pnx-mini {
56
61
  pnx-viewer pnx-mini {
57
62
  min-width: unset;
58
63
  min-height: unset;
59
- margin-bottom: 40px;
60
64
  }
61
65
  }
62
66
 
@@ -95,4 +99,12 @@ pnx-viewer .pnx-map .maplibregl-ctrl-attrib {
95
99
  width: 250px;
96
100
  max-width: 40vw;
97
101
  }
98
- }
102
+ }
103
+
104
+ /* Hidden widgets on sequence play */
105
+ pnx-viewer.pnx-playing pnx-bottom-drawer,
106
+ pnx-viewer.pnx-playing pnx-mini,
107
+ pnx-viewer.pnx-playing pnx-widget-legend,
108
+ pnx-viewer.pnx-playing pnx-widget-zoom {
109
+ display: none;
110
+ }