@panoramax/web-viewer 4.0.3 → 4.1.0

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 (103) hide show
  1. package/CHANGELOG.md +40 -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/photo.html +1 -1
  7. package/build/viewer.html +3 -3
  8. package/build/widgets.html +1 -1
  9. package/config/jest/mocks.js +9 -1
  10. package/docs/03_URL_settings.md +21 -0
  11. package/docs/09_Develop.md +6 -0
  12. package/docs/images/comparative_3drender.jpg +0 -0
  13. package/docs/index.md +13 -0
  14. package/docs/reference/components/core/Editor.md +18 -0
  15. package/docs/reference/components/core/PhotoViewer.md +1 -0
  16. package/docs/reference/components/core/Viewer.md +1 -0
  17. package/docs/reference/components/menus/MapLegend.md +17 -0
  18. package/docs/reference/components/menus/MiniPictureLegend.md +15 -0
  19. package/docs/reference/components/menus/PictureLegend.md +17 -0
  20. package/docs/reference/components/ui/AnnotationsSwitch.md +15 -0
  21. package/docs/reference/components/ui/Button.md +1 -1
  22. package/docs/reference/components/ui/CopyButton.md +1 -1
  23. package/docs/reference/components/ui/LinkButton.md +1 -1
  24. package/docs/reference/components/ui/Map.md +18 -2
  25. package/docs/reference/components/ui/MapMore.md +6 -2
  26. package/docs/reference/components/ui/SemanticsEditor.md +87 -0
  27. package/docs/reference/components/ui/widgets/Legend.md +5 -4
  28. package/docs/reference/utils/URLHandler.md +7 -0
  29. package/docs/reference.md +3 -1
  30. package/docs/tutorials/aerial_imagery.md +13 -11
  31. package/mkdocs.yml +3 -1
  32. package/package.json +7 -7
  33. package/public/photo.html +1 -1
  34. package/public/viewer.html +3 -3
  35. package/public/widgets.html +32 -0
  36. package/src/components/core/Basic.css +2 -0
  37. package/src/components/core/Basic.js +3 -1
  38. package/src/components/core/CoverageMap.js +6 -0
  39. package/src/components/core/Editor.css +1 -0
  40. package/src/components/core/Editor.js +58 -7
  41. package/src/components/core/PhotoViewer.css +5 -10
  42. package/src/components/core/PhotoViewer.js +55 -20
  43. package/src/components/core/Viewer.css +9 -2
  44. package/src/components/core/Viewer.js +62 -33
  45. package/src/components/layout/BottomDrawer.js +2 -1
  46. package/src/components/layout/Tabs.js +4 -0
  47. package/src/components/menus/AnnotationsList.js +13 -9
  48. package/src/components/menus/MapBackground.js +8 -3
  49. package/src/components/menus/MapFilters.js +11 -2
  50. package/src/components/menus/MapLayers.js +3 -2
  51. package/src/components/menus/MapLegend.js +28 -4
  52. package/src/components/menus/MiniPictureLegend.js +74 -0
  53. package/src/components/menus/PictureLegend.js +88 -33
  54. package/src/components/menus/PictureMetadata.js +49 -17
  55. package/src/components/menus/PlayerOptions.js +3 -3
  56. package/src/components/menus/Share.js +3 -3
  57. package/src/components/menus/index.js +5 -4
  58. package/src/components/styles.js +11 -0
  59. package/src/components/ui/AnnotationsSwitch.js +169 -0
  60. package/src/components/ui/Button.js +1 -1
  61. package/src/components/ui/CopyButton.js +1 -1
  62. package/src/components/ui/LinkButton.js +1 -1
  63. package/src/components/ui/Map.css +4 -0
  64. package/src/components/ui/Map.js +17 -5
  65. package/src/components/ui/MapMore.js +61 -25
  66. package/src/components/ui/Photo.css +11 -2
  67. package/src/components/ui/Photo.js +6 -3
  68. package/src/components/ui/SemanticsEditor.js +157 -0
  69. package/src/components/ui/index.js +2 -1
  70. package/src/components/ui/widgets/GeoSearch.js +3 -2
  71. package/src/components/ui/widgets/Legend.js +69 -14
  72. package/src/components/ui/widgets/MapFiltersButton.js +3 -3
  73. package/src/components/ui/widgets/MapLayersButton.js +3 -3
  74. package/src/components/ui/widgets/OSMEditors.js +2 -2
  75. package/src/components/ui/widgets/PictureLegendActions.js +24 -42
  76. package/src/components/ui/widgets/Player.js +3 -3
  77. package/src/components/ui/widgets/Zoom.js +4 -2
  78. package/src/translations/ar.json +1 -0
  79. package/src/translations/da.json +3 -2
  80. package/src/translations/de.json +64 -13
  81. package/src/translations/en.json +5 -1
  82. package/src/translations/eo.json +32 -2
  83. package/src/translations/fr.json +7 -1
  84. package/src/translations/it.json +33 -2
  85. package/src/translations/nl.json +53 -11
  86. package/src/translations/zh_Hant.json +29 -2
  87. package/src/utils/API.js +17 -1
  88. package/src/utils/InitParameters.js +46 -4
  89. package/src/utils/URLHandler.js +9 -1
  90. package/src/utils/map.js +24 -1
  91. package/src/utils/semantics.js +53 -1
  92. package/src/utils/services.js +16 -0
  93. package/src/utils/widgets.js +20 -0
  94. package/tests/components/core/Editor.test.js +1 -1
  95. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +18 -6
  96. package/tests/components/core/__snapshots__/Viewer.test.js.snap +15 -3
  97. package/tests/components/ui/Photo.test.js +1 -0
  98. package/tests/components/ui/__snapshots__/Map.test.js.snap +164 -0
  99. package/tests/utils/InitParameters.test.js +27 -0
  100. package/tests/utils/map.test.js +12 -0
  101. package/tests/utils/semantics.test.js +34 -5
  102. package/docs/reference/components/ui/HashTags.md +0 -15
  103. package/src/components/ui/HashTags.js +0 -98
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",
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/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
  };
@@ -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
  }
@@ -20,4 +20,5 @@ pnx-editor pnx-map-background {
20
20
  color: var(--widget-font);
21
21
  bottom: 10px;
22
22
  left: 10px;
23
+ font-family: var(--font-family);
23
24
  }
@@ -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
  }
@@ -104,6 +132,12 @@ export default class Editor extends Basic {
104
132
  super.connectedCallback();
105
133
  }
106
134
 
135
+ /** @private */
136
+ firstUpdated() {
137
+ super.firstUpdated();
138
+ this._moveChildToGrid();
139
+ }
140
+
107
141
  attributeChangedCallback(name, old, value) {
108
142
  if(name === "users" && Array.isArray(value) && value.length > 0) {
109
143
  console.warn("Parameters users can't be changed in Editor, only selected sequence can be visible");
@@ -115,11 +149,11 @@ export default class Editor extends Basic {
115
149
 
116
150
  /** @private */
117
151
  render() {
118
- return [this.loader, this._psvContainer, this._mapContainer];
152
+ return [this.loader, this.grid];
119
153
  }
120
154
 
121
155
  getSubComponentsNames() {
122
- return super.getSubComponentsNames().concat(["map", "psv"]);
156
+ return super.getSubComponentsNames().concat(["map", "psv", "grid"]);
123
157
  }
124
158
 
125
159
  /** @private */
@@ -142,6 +176,7 @@ export default class Editor extends Basic {
142
176
  background: this.background,
143
177
  supplementaryStyle: this._createMapStyle(),
144
178
  zoom: 15, // Hack to avoid _initMapPosition call
179
+ picMarkerDraggable: true,
145
180
  });
146
181
  linkMapAndPhoto(this);
147
182
  this.loader.setAttribute("value", 50);
@@ -243,6 +278,7 @@ export default class Editor extends Basic {
243
278
  "type": "FeatureCollection",
244
279
  "features": [
245
280
  {
281
+ "id": this.sequence,
246
282
  "type": "Feature",
247
283
  "properties": {
248
284
  "id": this.sequence,
@@ -312,8 +348,23 @@ export default class Editor extends Basic {
312
348
  */
313
349
  _addMapBackgroundWidget() {
314
350
  // Container
315
- const pnlLayers = createWebComp("pnx-map-background", {_parent: this, size: "sm"});
316
- this._mapContainer.appendChild(pnlLayers);
351
+ const pnlLayers = createWebComp("pnx-map-background", {_parent: this, size: "sm", slot: "bottom-left"});
352
+ this.grid.appendChild(pnlLayers);
353
+ }
354
+
355
+ /** @private */
356
+ _moveChildToGrid() {
357
+ const slotContent = Array.from(this.querySelectorAll("[slot]"));
358
+
359
+ slotContent.forEach(n => {
360
+ // Add parent + translation for our components
361
+ if(n.tagName?.toLowerCase().startsWith("pnx-")) {
362
+ n._parent = this;
363
+ n._t = this._t;
364
+ }
365
+
366
+ this.grid.appendChild(n);
367
+ });
317
368
  }
318
369
 
319
370
  /**
@@ -35,14 +35,9 @@ pnx-photo-viewer pnx-cornered-grid::part(corner-bottom-right) {
35
35
  }
36
36
  }
37
37
 
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
- }
38
+ /* Hidden widgets on sequence play */
39
+ pnx-photo-viewer.pnx-playing pnx-bottom-drawer,
40
+ pnx-photo-viewer.pnx-playing pnx-widget-legend,
41
+ pnx-photo-viewer.pnx-playing pnx-widget-zoom {
42
+ display: none;
48
43
  }
@@ -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 });
@@ -183,6 +200,13 @@ export default class PhotoViewer extends Basic {
183
200
  this.onceAPIReady().then(this._postAPIInit.bind(this));
184
201
  }
185
202
 
203
+ /** @private */
204
+ disconnectedCallback() {
205
+ super.disconnectedCallback();
206
+ this.urlHandler?.destroy();
207
+ this.psv?.destroy();
208
+ }
209
+
186
210
  /** @private */
187
211
  firstUpdated() {
188
212
  super.firstUpdated();
@@ -266,7 +290,10 @@ export default class PhotoViewer extends Basic {
266
290
  this._initPSV();
267
291
  this._initWidgets();
268
292
  alterPhotoViewerState(this, myPostInitParams);
269
- this._handleKeyboardManagement();
293
+
294
+ if(myPostInitParams.keyboardShortcuts) {
295
+ this._handleKeyboardManagement();
296
+ }
270
297
 
271
298
  if(myPostInitParams.picture) {
272
299
  this.psv.addEventListener("picture-loaded", () => this.loader.dismiss(), {once: true});
@@ -313,6 +340,10 @@ export default class PhotoViewer extends Basic {
313
340
  this.loader.setAttribute("value", 50);
314
341
  alterPSVState(this.psv, this._initParams.getPSVPostInit());
315
342
  });
343
+
344
+ // Show class when PSV is playing sequence
345
+ this.psv.addEventListener("sequence-playing", () => this.classList.add("pnx-playing"));
346
+ this.psv.addEventListener("sequence-stopped", () => this.classList.remove("pnx-playing"));
316
347
  }
317
348
  catch(e) {
318
349
  let err = !PSSystem.isWebGLSupported ? this._t.pnx.error_webgl : this._t.pnx.error_psv;
@@ -327,13 +358,17 @@ export default class PhotoViewer extends Basic {
327
358
  const keytopsv = () => this.psv.startKeyboardControl();
328
359
 
329
360
  // Popup
330
- this.popup.addEventListener("open", () => keytonone());
331
- this.popup.addEventListener("close", () => keytopsv());
361
+ this.popup.addEventListener("open", keytonone);
362
+ this.popup.addEventListener("close", keytopsv);
363
+ this.psv.addEventListener("click", keytopsv);
332
364
 
333
365
  // Widgets
334
366
  for(let cn of this.grid.childNodes) {
335
- if(cn.getAttribute("slot") !== "bg") {
336
- cn.addEventListener("focusin", () => keytonone());
367
+ if(
368
+ cn.getAttribute("slot") !== "bg"
369
+ && !KEYBOARD_SKIP_FOCUS_WIDGETS.includes(cn.tagName.toLowerCase())
370
+ ) {
371
+ cn.addEventListener("focusin", keytonone);
337
372
  cn.addEventListener("focusout", () => {
338
373
  if(this.popup.getAttribute("visible") === null) {
339
374
  keytopsv();
@@ -56,7 +56,6 @@ pnx-viewer pnx-mini {
56
56
  pnx-viewer pnx-mini {
57
57
  min-width: unset;
58
58
  min-height: unset;
59
- margin-bottom: 40px;
60
59
  }
61
60
  }
62
61
 
@@ -95,4 +94,12 @@ pnx-viewer .pnx-map .maplibregl-ctrl-attrib {
95
94
  width: 250px;
96
95
  max-width: 40vw;
97
96
  }
98
- }
97
+ }
98
+
99
+ /* Hidden widgets on sequence play */
100
+ pnx-viewer.pnx-playing pnx-bottom-drawer,
101
+ pnx-viewer.pnx-playing pnx-mini,
102
+ pnx-viewer.pnx-playing pnx-widget-legend,
103
+ pnx-viewer.pnx-playing pnx-widget-zoom {
104
+ display: none;
105
+ }