@panoramax/web-viewer 4.0.3 → 4.1.0-develop-55fdf56c

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 +46 -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 +16 -4
  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 +89 -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
@@ -66,6 +66,7 @@ describe("InitParameters", () => {
66
66
  geocoder: true,
67
67
  widgets: true,
68
68
  forceFocus: true,
69
+ keyboardShortcuts: true,
69
70
  });
70
71
  expect(initParams._psvInit).toEqual({});
71
72
  expect(initParams._psvAny).toEqual({
@@ -111,11 +112,13 @@ describe("InitParameters", () => {
111
112
  geocoder: true,
112
113
  widgets: true,
113
114
  forceFocus: true,
115
+ keyboardShortcuts: true,
114
116
  });
115
117
  });
116
118
 
117
119
  it("uses browserStorage parameters if no URL parameter is available", () => {
118
120
  componentAttrs.map.raster = {};
121
+ componentAttrs.picture = undefined;
119
122
  const initParams = new InitParameters(componentAttrs, undefined, browserStorage);
120
123
  expect(initParams._mapAny).toEqual({
121
124
  theme: "qualityscore",
@@ -128,6 +131,20 @@ describe("InitParameters", () => {
128
131
  });
129
132
  });
130
133
 
134
+ it("uses browserStorage parameters if no URL parameter is available, except map coords if picture is set", () => {
135
+ componentAttrs.map.raster = {};
136
+ const initParams = new InitParameters(componentAttrs, undefined, browserStorage);
137
+ expect(initParams._mapAny).toEqual({
138
+ theme: "qualityscore",
139
+ background: "aerial",
140
+ center: [0,0],
141
+ zoom: 19,
142
+ pitch: undefined,
143
+ bearing: undefined,
144
+ users: "user1,user2",
145
+ });
146
+ });
147
+
131
148
  it("should sanitize objects correctly", () => {
132
149
  const initParams = new InitParameters(componentAttrs, urlParams);
133
150
  const obj = { a: 1, b: undefined, c: 3 };
@@ -161,6 +178,7 @@ describe("InitParameters", () => {
161
178
  geocoder: true,
162
179
  widgets: true,
163
180
  forceFocus: true,
181
+ keyboardShortcuts: true,
164
182
  });
165
183
  });
166
184
 
@@ -243,6 +261,15 @@ describe("InitParameters", () => {
243
261
  expect(initParams._mapAny.background).toBe("streets");
244
262
  expect(console.warn).toHaveBeenCalledWith("Parameter background can't be 'aerial' as no aerial imagery is available");
245
263
  });
264
+
265
+ it("should handle keyboardShortcuts=false", () => {
266
+ componentAttrs["keyboard-shortcuts"] = "false";
267
+ const initParams = new InitParameters(componentAttrs, urlParams);
268
+ expect(initParams._mapInit.keyboard).toBe(false);
269
+ expect(initParams._parentPostInit.keyboardShortcuts).toBe(false);
270
+ expect(initParams._psvInit.keyboard).toBe(false);
271
+ expect(initParams._psvInit.keyboardActions).toEqual({});
272
+ });
246
273
  });
247
274
 
248
275
  describe("getMapPositionFromString", () => {
@@ -11,6 +11,18 @@ describe("getThumbGif", () => {
11
11
  });
12
12
  });
13
13
 
14
+ describe("isNullCoordinates", () => {
15
+ it.each([
16
+ [undefined, true],
17
+ [null, true],
18
+ [[0,0], true],
19
+ [[48.7, -1.5], false],
20
+ [[], true],
21
+ ])("works with %s", (input, expected) => {
22
+ expect(map.isNullCoordinates(input)).toBe(expected);
23
+ });
24
+ });
25
+
14
26
  describe("isLabelLayer", () => {
15
27
  it("works with just text-field", () => {
16
28
  const layer = { type: "symbol", layout: { "text-field": "Label" } };
@@ -1,4 +1,6 @@
1
- import { decodeKey, decodeBasicTag, groupByPrefix } from "../../src/utils/semantics";
1
+ import {
2
+ decodeKey, decodeBasicTag, computeDiffTags, groupByPrefix
3
+ } from "../../src/utils/semantics";
2
4
 
3
5
  describe("decodeBasicTag", () => {
4
6
  test("should return null if no equal sign is present", () => {
@@ -7,14 +9,14 @@ describe("decodeBasicTag", () => {
7
9
 
8
10
  test("should correctly decode a tag with an equal sign", () => {
9
11
  expect(decodeBasicTag("key=value")).toEqual({
10
- key: { prefix: "", subkey: "key", qualifies: null },
12
+ key: { key: "key", prefix: "", subkey: "key", qualifies: null },
11
13
  value: "value"
12
14
  });
13
15
  });
14
16
 
15
17
  test("should correctly decode a tag with a prefix", () => {
16
18
  expect(decodeBasicTag("osm|key=value")).toEqual({
17
- key: { prefix: "osm", subkey: "key", qualifies: null },
19
+ key: { key: "osm|key", prefix: "osm", subkey: "key", qualifies: null },
18
20
  value: "value"
19
21
  });
20
22
  });
@@ -23,6 +25,7 @@ describe("decodeBasicTag", () => {
23
25
  describe("decodeKey", () => {
24
26
  test("should return default structure if key does not match regex", () => {
25
27
  expect(decodeKey("panoKey")).toEqual({
28
+ key: "panoKey",
26
29
  prefix: "",
27
30
  subkey: "panoKey",
28
31
  qualifies: null
@@ -31,6 +34,7 @@ describe("decodeKey", () => {
31
34
 
32
35
  test("should correctly decode a key with a prefix", () => {
33
36
  expect(decodeKey("osm|traffic_sign")).toEqual({
37
+ key: "osm|traffic_sign",
34
38
  prefix: "osm",
35
39
  subkey: "traffic_sign",
36
40
  qualifies: null
@@ -39,21 +43,46 @@ describe("decodeKey", () => {
39
43
 
40
44
  test("should correctly decode a key with qualifiers", () => {
41
45
  expect(decodeKey("detection_model[camera_mount=pole]")).toEqual({
46
+ key: "detection_model[camera_mount=pole]",
42
47
  prefix: "",
43
48
  subkey: "detection_model",
44
- qualifies: { key: { prefix: "", subkey: "camera_mount", qualifies: null }, value: "pole" }
49
+ qualifies: { key: { key: "camera_mount", prefix: "", subkey: "camera_mount", qualifies: null }, value: "pole" }
45
50
  });
46
51
  });
47
52
 
48
53
  test("should correctly decode a key with a prefix and qualifiers", () => {
49
54
  expect(decodeKey("osm|source[osm|traffic_sign=stop]")).toEqual({
55
+ key: "osm|source[osm|traffic_sign=stop]",
50
56
  prefix: "osm",
51
57
  subkey: "source",
52
- qualifies: { key: { prefix: "osm", subkey: "traffic_sign", qualifies: null }, value: "stop" }
58
+ qualifies: { key: { key: "osm|traffic_sign", prefix: "osm", subkey: "traffic_sign", qualifies: null }, value: "stop" }
53
59
  });
54
60
  });
55
61
  });
56
62
 
63
+ describe("computeDiffTags", () => {
64
+ it("should return new set of tags when no tag is missing in next", () => {
65
+ const prev = [{key: "tag1", value: "value1"}, {key: "tag2", value: "value2"}];
66
+ const next = [{key: "tag1", value: "value1"}, {key: "tag2", value: "value2"}, {key: "tag3", value: "value3"}];
67
+
68
+ expect(computeDiffTags(prev, next)).toEqual([{key: "tag3", value: "value3", action: "add"}]);
69
+ });
70
+
71
+ it("should return new set of tags with missing tags marked as delete when some tag is missing in next", () => {
72
+ const prev = [{key: "tag1", value: "value1"}, {key: "tag2", value: "value2"}];
73
+ const next = [{key: "tag1", value: "value1"}];
74
+
75
+ expect(computeDiffTags(prev, next)).toEqual([{key: "tag2", value: "value2", action: "delete"}]);
76
+ });
77
+
78
+ it("should return new set of tags with all tags marked as delete when all tags are missing in next", () => {
79
+ const prev = [{key: "tag1", value: "value1"}, {key: "tag2", value: "value2"}];
80
+ const next = [];
81
+
82
+ expect(computeDiffTags(prev, next)).toEqual([{key: "tag1", value: "value1", action: "delete"}, {key: "tag2", value: "value2", action: "delete"}]);
83
+ });
84
+ });
85
+
57
86
  describe("groupByPrefix", () => {
58
87
  test("should group tags by prefix", () => {
59
88
  const tags = [
@@ -1,15 +0,0 @@
1
- <a name="Panoramax.components.ui.HashTags"></a>
2
-
3
- ## Panoramax.components.ui.HashTags ⇐ <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
4
- **Kind**: static class of <code>Panoramax.components.ui</code>
5
- **Extends**: <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
6
- **Element**: pnx-hashtags
7
- <a name="new_Panoramax.components.ui.HashTags_new"></a>
8
-
9
- ### new HashTags()
10
- HashTags component shows the list of hashtags associated to a picture.
11
-
12
- **Example**
13
- ```html
14
- <pnx-hashtags ._parent=${viewer} />
15
- ```
@@ -1,98 +0,0 @@
1
- import { LitElement, html, css, nothing } from "lit";
2
- import { getHashTags, hasAnnotations } from "../../utils/picture";
3
- import { fa } from "../../utils/widgets";
4
- import { faDrawPolygon } from "@fortawesome/free-solid-svg-icons/faDrawPolygon";
5
-
6
- /**
7
- * HashTags component shows the list of hashtags associated to a picture.
8
- * @class Panoramax.components.ui.HashTags
9
- * @element pnx-hashtags
10
- * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
11
- * @example
12
- * ```html
13
- * <pnx-hashtags ._parent=${viewer} />
14
- * ```
15
- */
16
- export default class HashTags extends LitElement {
17
- /** @private */
18
- static styles = css`
19
- div {
20
- background: linear-gradient(to bottom left, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.2));
21
- margin-top: -10px;
22
- margin-right: -10px;
23
- padding: 5px 10px;
24
- border-bottom-left-radius: 10px;
25
- font-family: var(--font-family);
26
- color: white;
27
- font-size: 0.8em;
28
- }
29
- `;
30
-
31
- /** @private */
32
- static properties = {
33
- _tags: {state: true},
34
- _visible: {state: true},
35
- _annotationsToggled: {state: true},
36
- };
37
-
38
- constructor() {
39
- super();
40
- this._tags = [];
41
- this._visible = false;
42
- this._annotationsToggled = false;
43
- }
44
-
45
- /** @private */
46
- connectedCallback() {
47
- super.connectedCallback();
48
-
49
- this._parent.onceReady().then(() => {
50
- this._tags = getHashTags(this._parent?.psv?.getPictureMetadata?.());
51
-
52
- // Component visibility : only if seen at least one pic with semantics
53
- if(
54
- !this._visible && (
55
- this._tags.length > 0
56
- || hasAnnotations(this._parent?.psv?.getPictureMetadata?.())
57
- )
58
- ) {
59
- this._visible = true;
60
- this._parent.psv.toggleAllAnnotations(true);
61
- }
62
-
63
- this._parent.psv.addEventListener("picture-loaded", () => {
64
- this._tags = getHashTags(this._parent.psv.getPictureMetadata());
65
- if(
66
- !this._visible && (
67
- this._tags.length > 0 ||
68
- hasAnnotations(this._parent.psv.getPictureMetadata())
69
- )
70
- ) {
71
- this._visible = true;
72
- this._parent.psv.toggleAllAnnotations(true);
73
- }
74
- });
75
-
76
- this._annotationsToggled = this._parent.psv.areAnnotationsVisible() || false;
77
- this._parent.psv.addEventListener("annotations-toggled", e => {
78
- this._annotationsToggled = e.detail.visible;
79
- });
80
- });
81
- }
82
-
83
- /** @private */
84
- render() {
85
- return this._visible ? html`<div>
86
- ${this._tags.join(" ")}
87
- <pnx-button
88
- kind="outline"
89
- style="vertical-align: middle"
90
- title=${this._annotationsToggled ? this._parent._t?.pnx.semantics_hide_annotations : this._parent._t?.pnx.semantics_show_annotations}
91
- active=${this._annotationsToggled ? "" : nothing}
92
- @click=${() => this._parent.psv.toggleAllAnnotations(!this._annotationsToggled)}
93
- >${fa(faDrawPolygon)}</pnx-button>
94
- </div>` : nothing;
95
- }
96
- }
97
-
98
- customElements.define("pnx-hashtags", HashTags);