@panoramax/web-viewer 3.2.3-develop-d7e5a16d → 3.2.3-develop-6257391e

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 (221) hide show
  1. package/.gitlab-ci.yml +3 -0
  2. package/CHANGELOG.md +19 -0
  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 +2 -2
  7. package/build/index.css.map +1 -1
  8. package/build/index.html +1 -1
  9. package/build/index.js +1682 -5
  10. package/build/index.js.map +1 -1
  11. package/build/map.html +1 -1
  12. package/build/viewer.html +10 -1
  13. package/build/widgets.html +1 -0
  14. package/config/jest/mocks.js +172 -0
  15. package/config/paths.js +1 -0
  16. package/config/webpack.config.js +26 -0
  17. package/docs/03_URL_settings.md +3 -11
  18. package/docs/05_Compatibility.md +59 -76
  19. package/docs/09_Develop.md +30 -11
  20. package/docs/90_Releases.md +2 -2
  21. package/docs/images/class_diagram.drawio +28 -28
  22. package/docs/images/class_diagram.jpg +0 -0
  23. package/docs/index.md +112 -0
  24. package/docs/reference/components/core/Basic.md +153 -0
  25. package/docs/reference/components/core/CoverageMap.md +160 -0
  26. package/docs/reference/components/core/Editor.md +172 -0
  27. package/docs/reference/components/core/Viewer.md +288 -0
  28. package/docs/reference/components/layout/CorneredGrid.md +29 -0
  29. package/docs/reference/components/layout/Mini.md +45 -0
  30. package/docs/reference/components/menus/MapBackground.md +32 -0
  31. package/docs/reference/components/menus/MapFilters.md +15 -0
  32. package/docs/reference/components/menus/MapLayers.md +15 -0
  33. package/docs/reference/components/menus/MapLegend.md +15 -0
  34. package/docs/reference/components/menus/PictureLegend.md +15 -0
  35. package/docs/reference/components/menus/PictureMetadata.md +15 -0
  36. package/docs/reference/components/menus/PlayerOptions.md +15 -0
  37. package/docs/reference/components/menus/QualityScoreDoc.md +15 -0
  38. package/docs/reference/components/menus/ReportForm.md +15 -0
  39. package/docs/reference/components/menus/ShareMenu.md +15 -0
  40. package/docs/reference/components/ui/Button.md +39 -0
  41. package/docs/reference/components/ui/ButtonGroup.md +36 -0
  42. package/docs/reference/components/ui/CopyButton.md +35 -0
  43. package/docs/reference/components/ui/Grade.md +32 -0
  44. package/docs/reference/components/ui/LinkButton.md +44 -0
  45. package/docs/reference/components/ui/Loader.md +54 -0
  46. package/docs/reference/components/ui/Map.md +214 -0
  47. package/docs/reference/components/ui/MapMore.md +233 -0
  48. package/docs/reference/components/ui/Photo.md +369 -0
  49. package/docs/reference/components/ui/Popup.md +56 -0
  50. package/docs/reference/components/ui/QualityScore.md +45 -0
  51. package/docs/reference/components/ui/SearchBar.md +63 -0
  52. package/docs/reference/components/ui/TogglableGroup.md +39 -0
  53. package/docs/reference/components/ui/widgets/GeoSearch.md +32 -0
  54. package/docs/reference/components/ui/widgets/Legend.md +32 -0
  55. package/docs/reference/components/ui/widgets/MapFiltersButton.md +33 -0
  56. package/docs/reference/components/ui/widgets/MapLayersButton.md +15 -0
  57. package/docs/reference/components/ui/widgets/Player.md +32 -0
  58. package/docs/reference/components/ui/widgets/Share.md +15 -0
  59. package/docs/reference/components/ui/widgets/Zoom.md +15 -0
  60. package/docs/reference/utils/API.md +311 -0
  61. package/docs/reference/utils/InitParameters.md +67 -0
  62. package/docs/reference/utils/URLHandler.md +102 -0
  63. package/docs/reference.md +73 -0
  64. package/docs/shortcuts.md +11 -0
  65. package/docs/tutorials/aerial_imagery.md +19 -0
  66. package/docs/tutorials/authentication.md +10 -0
  67. package/docs/tutorials/custom_widgets.md +64 -0
  68. package/docs/tutorials/map_style.md +27 -0
  69. package/docs/tutorials/migrate_v4.md +122 -0
  70. package/docs/tutorials/synced_coverage.md +42 -0
  71. package/mkdocs.yml +60 -5
  72. package/package.json +10 -7
  73. package/public/editor.html +21 -29
  74. package/public/index.html +3 -3
  75. package/public/map.html +19 -18
  76. package/public/viewer.html +18 -24
  77. package/public/widgets.html +265 -0
  78. package/scripts/doc.js +77 -0
  79. package/src/components/core/Basic.css +44 -0
  80. package/src/components/core/Basic.js +258 -0
  81. package/src/components/core/CoverageMap.css +9 -0
  82. package/src/components/core/CoverageMap.js +105 -0
  83. package/src/components/core/Editor.css +23 -0
  84. package/src/components/core/Editor.js +354 -0
  85. package/src/components/core/Viewer.css +109 -0
  86. package/src/components/core/Viewer.js +707 -0
  87. package/src/components/core/index.js +11 -0
  88. package/src/components/index.js +13 -0
  89. package/src/components/layout/CorneredGrid.js +109 -0
  90. package/src/components/layout/Mini.js +117 -0
  91. package/src/components/layout/index.js +7 -0
  92. package/src/components/menus/MapBackground.js +106 -0
  93. package/src/components/menus/MapFilters.js +386 -0
  94. package/src/components/menus/MapLayers.js +143 -0
  95. package/src/components/menus/MapLegend.js +54 -0
  96. package/src/components/menus/PictureLegend.js +103 -0
  97. package/src/components/menus/PictureMetadata.js +188 -0
  98. package/src/components/menus/PlayerOptions.js +96 -0
  99. package/src/components/menus/QualityScoreDoc.js +36 -0
  100. package/src/components/menus/ReportForm.js +133 -0
  101. package/src/components/menus/Share.js +228 -0
  102. package/src/components/menus/index.js +15 -0
  103. package/src/components/styles.js +365 -0
  104. package/src/components/ui/Button.js +75 -0
  105. package/src/components/ui/ButtonGroup.css +49 -0
  106. package/src/components/ui/ButtonGroup.js +68 -0
  107. package/src/components/ui/CopyButton.js +71 -0
  108. package/src/components/ui/Grade.js +54 -0
  109. package/src/components/ui/LinkButton.js +68 -0
  110. package/src/components/ui/Loader.js +188 -0
  111. package/src/components/{Map.css → ui/Map.css} +5 -17
  112. package/src/components/{Map.js → ui/Map.js} +114 -138
  113. package/src/components/ui/MapMore.js +324 -0
  114. package/src/components/{Photo.css → ui/Photo.css} +6 -6
  115. package/src/components/{Photo.js → ui/Photo.js} +279 -90
  116. package/src/components/ui/Popup.js +145 -0
  117. package/src/components/ui/QualityScore.js +152 -0
  118. package/src/components/ui/SearchBar.js +363 -0
  119. package/src/components/ui/TogglableGroup.js +162 -0
  120. package/src/components/ui/index.js +20 -0
  121. package/src/components/ui/widgets/GeoSearch.css +21 -0
  122. package/src/components/ui/widgets/GeoSearch.js +139 -0
  123. package/src/components/ui/widgets/Legend.js +51 -0
  124. package/src/components/ui/widgets/MapFiltersButton.js +104 -0
  125. package/src/components/ui/widgets/MapLayersButton.js +79 -0
  126. package/src/components/ui/widgets/Player.css +7 -0
  127. package/src/components/ui/widgets/Player.js +148 -0
  128. package/src/components/ui/widgets/Share.js +30 -0
  129. package/src/components/ui/widgets/Zoom.js +82 -0
  130. package/src/components/ui/widgets/index.js +12 -0
  131. package/src/img/panoramax.svg +13 -0
  132. package/src/img/switch_big.svg +20 -10
  133. package/src/index.js +6 -9
  134. package/src/translations/da.json +1 -1
  135. package/src/translations/de.json +1 -1
  136. package/src/translations/en.json +5 -3
  137. package/src/translations/eo.json +1 -1
  138. package/src/translations/es.json +1 -1
  139. package/src/translations/fr.json +5 -3
  140. package/src/translations/hu.json +1 -1
  141. package/src/translations/it.json +1 -1
  142. package/src/translations/ja.json +1 -1
  143. package/src/translations/nl.json +1 -1
  144. package/src/translations/pl.json +1 -1
  145. package/src/translations/sv.json +1 -1
  146. package/src/translations/zh_Hant.json +1 -1
  147. package/src/utils/API.js +74 -42
  148. package/src/utils/InitParameters.js +354 -0
  149. package/src/utils/URLHandler.js +364 -0
  150. package/src/utils/geocoder.js +116 -0
  151. package/src/utils/{I18n.js → i18n.js} +3 -1
  152. package/src/utils/index.js +11 -0
  153. package/src/utils/{Map.js → map.js} +216 -80
  154. package/src/utils/picture.js +433 -0
  155. package/src/utils/utils.js +315 -0
  156. package/src/utils/widgets.js +93 -0
  157. package/tests/components/ui/CopyButton.test.js +52 -0
  158. package/tests/components/ui/Loader.test.js +54 -0
  159. package/tests/components/{Map.test.js → ui/Map.test.js} +19 -61
  160. package/tests/components/{Photo.test.js → ui/Photo.test.js} +89 -57
  161. package/tests/components/ui/Popup.test.js +24 -0
  162. package/tests/components/ui/QualityScore.test.js +17 -0
  163. package/tests/components/ui/SearchBar.test.js +107 -0
  164. package/tests/components/ui/__snapshots__/CopyButton.test.js.snap +34 -0
  165. package/tests/components/ui/__snapshots__/Loader.test.js.snap +56 -0
  166. package/tests/components/{__snapshots__ → ui/__snapshots__}/Map.test.js.snap +11 -38
  167. package/tests/components/{__snapshots__ → ui/__snapshots__}/Photo.test.js.snap +57 -4
  168. package/tests/components/ui/__snapshots__/Popup.test.js.snap +29 -0
  169. package/tests/components/ui/__snapshots__/QualityScore.test.js.snap +11 -0
  170. package/tests/components/ui/__snapshots__/SearchBar.test.js.snap +65 -0
  171. package/tests/utils/API.test.js +1 -14
  172. package/tests/utils/InitParameters.test.js +485 -0
  173. package/tests/utils/URLHandler.test.js +350 -0
  174. package/tests/utils/__snapshots__/URLHandler.test.js.snap +21 -0
  175. package/tests/utils/__snapshots__/picture.test.js.snap +315 -0
  176. package/tests/utils/__snapshots__/widgets.test.js.snap +19 -0
  177. package/tests/utils/geocoder.test.js +37 -0
  178. package/tests/utils/{I18n.test.js → i18n.test.js} +1 -1
  179. package/tests/utils/map.test.js +67 -0
  180. package/tests/utils/picture.test.js +745 -0
  181. package/tests/utils/utils.test.js +288 -0
  182. package/tests/utils/widgets.test.js +90 -0
  183. package/docs/01_Start.md +0 -149
  184. package/docs/02_Usage.md +0 -831
  185. package/docs/04_Advanced_examples.md +0 -216
  186. package/src/Editor.css +0 -37
  187. package/src/Editor.js +0 -361
  188. package/src/StandaloneMap.js +0 -114
  189. package/src/Viewer.css +0 -203
  190. package/src/Viewer.js +0 -1246
  191. package/src/components/CoreView.css +0 -70
  192. package/src/components/CoreView.js +0 -175
  193. package/src/components/Loader.css +0 -74
  194. package/src/components/Loader.js +0 -120
  195. package/src/utils/Exif.js +0 -193
  196. package/src/utils/Utils.js +0 -631
  197. package/src/utils/Widgets.js +0 -562
  198. package/src/viewer/URLHash.js +0 -469
  199. package/src/viewer/Widgets.css +0 -880
  200. package/src/viewer/Widgets.js +0 -1470
  201. package/tests/Editor.test.js +0 -126
  202. package/tests/StandaloneMap.test.js +0 -45
  203. package/tests/Viewer.test.js +0 -366
  204. package/tests/__snapshots__/Editor.test.js.snap +0 -298
  205. package/tests/__snapshots__/StandaloneMap.test.js.snap +0 -30
  206. package/tests/__snapshots__/Viewer.test.js.snap +0 -195
  207. package/tests/components/CoreView.test.js +0 -92
  208. package/tests/components/Loader.test.js +0 -38
  209. package/tests/components/__snapshots__/Loader.test.js.snap +0 -15
  210. package/tests/utils/Exif.test.js +0 -124
  211. package/tests/utils/Map.test.js +0 -113
  212. package/tests/utils/Utils.test.js +0 -300
  213. package/tests/utils/Widgets.test.js +0 -107
  214. package/tests/utils/__snapshots__/Exif.test.js.snap +0 -43
  215. package/tests/utils/__snapshots__/Utils.test.js.snap +0 -41
  216. package/tests/utils/__snapshots__/Widgets.test.js.snap +0 -44
  217. package/tests/viewer/URLHash.test.js +0 -559
  218. package/tests/viewer/Widgets.test.js +0 -127
  219. package/tests/viewer/__snapshots__/URLHash.test.js.snap +0 -108
  220. package/tests/viewer/__snapshots__/Widgets.test.js.snap +0 -403
  221. /package/tests/utils/__snapshots__/{Map.test.js.snap → geocoder.test.js.snap} +0 -0
@@ -0,0 +1,162 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { panel } from "../styles";
3
+ import { listenForMenuClosure } from "../../utils/widgets";
4
+
5
+ /**
6
+ * Togglable Group element allows to make a menu appear/disappear based on button click.
7
+ * @class Panoramax.components.ui.TogglableGroup
8
+ * @element pnx-togglable-group
9
+ * @slot `button` The button on which click leads to open/close menu
10
+ * @slot `default` The menu to make shown/hidden on button click
11
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
12
+ * @example
13
+ * ```html
14
+ * <pnx-togglable-group padded="false" ._parent=${viewer}>
15
+ * <pnx-button slot="button">
16
+ * Open menu
17
+ * </pnx-button>
18
+ * <div>Menu content</div>
19
+ * </pnx-togglable-group>
20
+ * ```
21
+ */
22
+ export default class TogglableGroup extends LitElement {
23
+ /** @private */
24
+ static styles = [ panel, css`
25
+ div.container {
26
+ position: relative;
27
+ height: 100%;
28
+ }
29
+
30
+ .pnx-panel {
31
+ z-index: 130;
32
+ }
33
+ ` ];
34
+
35
+ /**
36
+ * Component properties.
37
+ * @memberof Panoramax.components.ui.TogglableGroup#
38
+ * @type {Object}
39
+ * @property {string} [padded] If set, adds a 15px padding to the menu panel.
40
+ */
41
+ static properties = {
42
+ _opened: {state: true},
43
+ padded: {type: String},
44
+ };
45
+
46
+ constructor() {
47
+ super();
48
+ this._opened = false;
49
+ }
50
+
51
+ /** @private */
52
+ open() {
53
+ this._opened = true;
54
+ this._parent?.dispatchEvent(new CustomEvent("menu-opened", { detail: { menu: this }}));
55
+ this.adjustMenuPosition(this._btn);
56
+ if(this._chevron) { this._chevron.style.rotate = "180deg"; }
57
+ }
58
+
59
+ /** @private */
60
+ close() {
61
+ this._opened = false;
62
+ if(this._chevron) { this._chevron.style.rotate = ""; }
63
+ }
64
+
65
+ /** @private */
66
+ connectedCallback() {
67
+ super.connectedCallback();
68
+ listenForMenuClosure(this, this.close.bind(this));
69
+ }
70
+
71
+ /** @private */
72
+ handleButtonSlotChange(e) {
73
+ this._btn = e.target.assignedNodes().pop();
74
+ if(this._btn) {
75
+ // Chevron
76
+ this._chevron = this._btn.querySelector("svg.fa-chevron-down");
77
+ if(this._chevron) {
78
+ this._chevron.style.transition = "rotate 0.2s";
79
+ this._chevron.style.rotate = this._opened ? "180deg" : "";
80
+ }
81
+
82
+ this._btn.addEventListener("click", () => {
83
+ if(this._opened) { this.close(); }
84
+ else { this.open(); }
85
+ });
86
+ }
87
+ }
88
+
89
+ /** @private */
90
+ adjustMenuPosition(btn) {
91
+ const smallWidth = window.innerWidth < 576;
92
+ const menu = this.shadowRoot.querySelector(".pnx-panel");
93
+ const btnRect = btn.getBoundingClientRect();
94
+ let menuRect = menu.getBoundingClientRect();
95
+
96
+ const overflowHeight = menuRect.height > window.innerHeight * 0.8;
97
+ if(overflowHeight) {
98
+ menu.style.height = `${window.innerHeight * 0.8}px`;
99
+ menu.style.overflowY = "scroll";
100
+ menuRect = menu.getBoundingClientRect();
101
+ }
102
+ else {
103
+ // Try to remove height limiter
104
+ menu.style.height = "unset";
105
+ menu.style.overflowY = "unset";
106
+ menuRect = menu.getBoundingClientRect();
107
+
108
+ // If height is too high, put back limitation
109
+ if(menuRect.height > window.innerHeight * 0.8) {
110
+ menu.style.height = `${window.innerHeight * 0.8}px`;
111
+ menu.style.overflowY = "scroll";
112
+ menuRect = menu.getBoundingClientRect();
113
+ }
114
+ }
115
+
116
+ const overflowRight = btnRect.left + menuRect.width > window.innerWidth;
117
+ const overflowBottom = btnRect.bottom + menuRect.height > window.innerHeight;
118
+ const overflowTop = btnRect.top - menuRect.height < 0;
119
+
120
+ if(overflowRight && overflowBottom && overflowTop) {
121
+ menu.style.top = smallWidth ? "0px" : `${btnRect.height + 5}px`;
122
+ menu.style.bottom = null;
123
+ menu.style.right = `${btnRect.width + 5}px`;
124
+ menu.style.left = null;
125
+ }
126
+ else if(overflowRight && overflowBottom) {
127
+ menu.style.top = null;
128
+ menu.style.bottom = "0px";
129
+ menu.style.right = `${btnRect.width + 5}px`;
130
+ menu.style.left = null;
131
+ }
132
+ else if(overflowRight) {
133
+ menu.style.top = smallWidth ? "0px" : `${btnRect.height + 5}px`;
134
+ menu.style.bottom = null;
135
+ menu.style.right = smallWidth ? `${btnRect.width + 5}px` : "0px";
136
+ menu.style.left = null;
137
+ }
138
+ else if(overflowBottom && !overflowTop) {
139
+ menu.style.top = null;
140
+ menu.style.bottom = "0px";
141
+ menu.style.left = `${btnRect.width + 5}px`;
142
+ }
143
+ else {
144
+ menu.style.top = `${btnRect.height + 5}px`;
145
+ menu.style.right = null;
146
+ menu.style.left = "0px";
147
+ menu.style.bottom = null;
148
+ }
149
+ }
150
+
151
+ /** @private */
152
+ render() {
153
+ return html`<div class="container">
154
+ <slot name="button" @slotchange=${this.handleButtonSlotChange}></slot>
155
+ <div class="pnx-panel ${this._opened ? "" : "pnx-hidden"} ${this.padded == "false" ? "" : "pnx-padded"}">
156
+ <slot></slot>
157
+ </div>
158
+ </div>`;
159
+ }
160
+ }
161
+
162
+ customElements.define("pnx-togglable-group", TogglableGroup);
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Smaller UI pieces components
3
+ * @module Panoramax:components:ui
4
+ */
5
+
6
+ export {default as ButtonGroup} from "./ButtonGroup";
7
+ export {default as Button} from "./Button";
8
+ export {default as CopyButton} from "./CopyButton";
9
+ export {default as Grade} from "./Grade";
10
+ export {default as LinkButton} from "./LinkButton";
11
+ export {default as Loader} from "./Loader";
12
+ export {default as Map} from "./Map";
13
+ export {default as MapMore} from "./MapMore";
14
+ export {default as Photo} from "./Photo";
15
+ export {default as Popup} from "./Popup";
16
+ export {default as QualityScore} from "./QualityScore";
17
+ export {default as SearchBar} from "./SearchBar";
18
+ export {default as TogglableGroup} from "./TogglableGroup";
19
+ import * as widgets from "./widgets";
20
+ export {widgets};
@@ -0,0 +1,21 @@
1
+ pnx-widget-geosearch .maplibregl-ctrl {
2
+ box-shadow: none !important;
3
+ background: none !important;
4
+ }
5
+
6
+ pnx-widget-geosearch .maplibregl-ctrl-geolocate {
7
+ border-radius: 15px;
8
+ }
9
+
10
+ pnx-widget-geosearch pnx-search-bar[reduced] .maplibregl-ctrl-geolocate {
11
+ width: 40px;
12
+ }
13
+
14
+ pnx-widget-geosearch pnx-search-bar:not([reduced]) .maplibregl-ctrl-geolocate {
15
+ margin-left: -5px;
16
+ }
17
+
18
+ pnx-widget-geosearch pnx-search-bar:not([reduceable])::part(input) {
19
+ width: 300px;
20
+ max-width: 30vw;
21
+ }
@@ -0,0 +1,139 @@
1
+ // DO NOT REMOVE THE "!": bundled builds breaks otherwise !!!
2
+ import maplibregl from "!maplibre-gl";
3
+
4
+ import { LitElement, html } from "lit";
5
+ import { forwardGeocodingBAN, forwardGeocodingNominatim } from "../../../utils/geocoder";
6
+ import "./GeoSearch.css";
7
+
8
+ const GEOCODER_ENGINES = { "ban": forwardGeocodingBAN, "nominatim": forwardGeocodingNominatim };
9
+
10
+ /**
11
+ * Ready-to-use geocoder search bar.
12
+ * @class Panoramax.components.ui.widgets.GeoSearch
13
+ * @element pnx-widget-geosearch
14
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
15
+ * @example
16
+ * ```html
17
+ * <pnx-widget-geosearch _parent=${viewer} />
18
+ * ```
19
+ */
20
+ export default class GeoSearch extends LitElement {
21
+ /**
22
+ * Component properties.
23
+ * @memberof Panoramax.components.ui.widgets.GeoSearch#
24
+ * @type {Object}
25
+ * @property {string} [geocoder=nominatim] The geocoder engine to use (nominatim, ban)
26
+ */
27
+ static properties = {
28
+ geocoder: {type: String},
29
+ _geolocate: {state: true},
30
+ };
31
+
32
+ constructor() {
33
+ super();
34
+ this.geocoder = "nominatim";
35
+
36
+ this._geolocateCtrl = new maplibregl.GeolocateControl({
37
+ positionOptions: {
38
+ enableHighAccuracy: true,
39
+ timeout: 60000, // Max 1 minute for first position
40
+ maximumAge: 300000, // Accepts 5 minutes old position
41
+ },
42
+ showAccuracyCircle: true,
43
+ showUserLocation: true,
44
+ trackUserLocation: true,
45
+ });
46
+ }
47
+
48
+ /** @private */
49
+ createRenderRoot() {
50
+ return this;
51
+ }
52
+
53
+ /** @private */
54
+ connectedCallback() {
55
+ super.connectedCallback();
56
+
57
+ this._geocoderEngine = GEOCODER_ENGINES[this.geocoder];
58
+ this._parent?.onceMapReady?.().then(() => {
59
+ this._geolocate = this._geolocateCtrl.onAdd(this._parent.map);
60
+ this._geolocate.setAttribute("slot", "pre");
61
+ });
62
+ }
63
+
64
+ /** @private */
65
+ _onInput(query) {
66
+ const rgxCoords = /([-+]?\d{1,2}\.\d+),\s*([-+]?\d{1,3}\.\d+)/;
67
+ const coordsMatch = query.match(rgxCoords);
68
+ const rgxUuid = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/;
69
+ const uuidMatch = query.match(rgxUuid);
70
+
71
+ if(coordsMatch) {
72
+ const lat = parseFloat(coordsMatch[1]);
73
+ const lon = parseFloat(coordsMatch[2]);
74
+ this._parent.map.jumpTo({
75
+ center: [lon, lat],
76
+ zoom: 16,
77
+ });
78
+ return Promise.resolve(true);
79
+ }
80
+ else if(uuidMatch) {
81
+ this._parent.select(null, query);
82
+ return Promise.resolve(true);
83
+ }
84
+ else {
85
+ return this._geocoderEngine({
86
+ query,
87
+ limit: 3,
88
+ //bbox: this._parent.map.getBounds().toArray().map(d => d.join(",")).join(","),
89
+ proximity: this._parent.map.getCenter().lat+","+this._parent.map.getCenter().lng,
90
+ }).then(data => {
91
+ data = data.features.map(f => ({
92
+ title: f.place_name.split(",")[0],
93
+ subtitle: f.place_name.split(",").slice(1).join(", "),
94
+ data: f
95
+ }));
96
+ return data;
97
+ });
98
+ }
99
+ }
100
+
101
+ /** @private */
102
+ _onSelect(e) {
103
+ const entry = e.detail;
104
+ if(entry) {
105
+ if(entry.data.bounds) {
106
+ this._parent?.map.fitBounds(entry.data.bounds, {animate: false});
107
+ }
108
+ else {
109
+ this._parent?.map.jumpTo({
110
+ center: entry.data.center,
111
+ zoom: entry.data.zoom || 13,
112
+ });
113
+ }
114
+ }
115
+ }
116
+
117
+ /** @private */
118
+ render() {
119
+ const isSmall = this._parent?.isWidthSmall() || false;
120
+
121
+ return html`
122
+ <pnx-search-bar
123
+ id="pnx-widget-search-bar"
124
+ placeholder=${this._parent?._t.pnx.search_address}
125
+ ._parent=${this._parent}
126
+ .searcher=${this._onInput.bind(this)}
127
+ .reduceable=${isSmall}
128
+ .reduced=${isSmall}
129
+ size="xxl"
130
+ class="pnx-print-hidden"
131
+ @result=${this._onSelect.bind(this)}
132
+ >
133
+ ${this._geolocate}
134
+ </pnx-search-bar>
135
+ `;
136
+ }
137
+ }
138
+
139
+ customElements.define("pnx-widget-geosearch", GeoSearch);
@@ -0,0 +1,51 @@
1
+ import {LitElement, html, css} from "lit";
2
+ import { panel } from "../../styles";
3
+
4
+ /**
5
+ * Legend widget, handling switch between map and photo components.
6
+ * @class Panoramax.components.ui.widgets.Legend
7
+ * @element pnx-widget-legend
8
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
9
+ * @example
10
+ * ```html
11
+ * <pnx-widget-legend _parent=${viewer} />
12
+ * ```
13
+ */
14
+ export default class Legend extends LitElement {
15
+ /** @private */
16
+ static styles = [panel, css`
17
+ .pnx-panel.pnx-padded {
18
+ border-radius: 10px;
19
+ padding: 10px;
20
+ position: relative;
21
+ width: 250px;
22
+ max-width: 80vh;
23
+ z-index: 120;
24
+ }
25
+ `];
26
+
27
+ /**
28
+ * Component properties.
29
+ * @memberof Panoramax.components.ui.widgets.Legend#
30
+ * @type {Object}
31
+ * @property {string} [focus] The focused main component (map, pic)
32
+ */
33
+ static properties = {
34
+ focus: {type: String},
35
+ };
36
+
37
+ render() {
38
+ return html`<div class="pnx-panel pnx-padded" part="panel">
39
+ <pnx-picture-legend
40
+ ._parent=${this._parent}
41
+ style=${this.focus == "map" ? "display: none": ""}
42
+ ></pnx-picture-legend>
43
+ <pnx-map-legend
44
+ ._parent=${this._parent}
45
+ style=${this.focus != "map" ? "display: none": ""}
46
+ ></pnx-map-legend>
47
+ </div>`;
48
+ }
49
+ }
50
+
51
+ customElements.define("pnx-widget-legend", Legend);
@@ -0,0 +1,104 @@
1
+ import { LitElement, html, nothing } from "lit";
2
+ import { fa } from "../../../utils/widgets";
3
+ import { faSliders } from "@fortawesome/free-solid-svg-icons/faSliders";
4
+ import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
5
+ import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark";
6
+ import { activeIcon } from "../../styles";
7
+ import { MAP_FILTERS } from "../MapMore";
8
+
9
+ /**
10
+ * Collapsible button showing off map filters menus.
11
+ * @class Panoramax.components.ui.widgets.MapFiltersButton
12
+ * @element pnx-widget-mapfilters
13
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
14
+ * @example
15
+ * ```html
16
+ * <pnx-widget-mapfilters user-search="" _parent=${viewer} />
17
+ * ```
18
+ */
19
+ export default class MapFiltersButton extends LitElement {
20
+ /** @private */
21
+ static styles = [activeIcon];
22
+
23
+ /**
24
+ * Component properties.
25
+ * @memberof Panoramax.components.ui.widgets.MapFiltersButton#
26
+ * @type {Object}
27
+ * @property {boolean} [user-search=false] Should user search filter show up ?
28
+ * @property {boolean} [quality-score=false] Should quality score filter show up ?
29
+ */
30
+ static properties = {
31
+ "user-search": {type: Boolean},
32
+ "quality-score": {type: Boolean},
33
+ _active: {state: true},
34
+ };
35
+
36
+ constructor() {
37
+ super();
38
+ this["user-search"] = false;
39
+ this["quality-score"] = false;
40
+ this._active = false;
41
+ }
42
+
43
+ /** @private */
44
+ connectedCallback() {
45
+ super.connectedCallback();
46
+
47
+ // Listen to user visibility changes to switch the filter active icon
48
+ this._parent?.onceMapReady?.().then(() => {
49
+ this._active = (
50
+ Object.keys(this._parent.map._mapFilters).filter(d => d && d !== "theme").length > 0
51
+ || this._parent.map.getVisibleUsers().filter(u => u !== "geovisio").length > 0
52
+ );
53
+
54
+ this._parent.map.on("filters-changed", e => {
55
+ this._active = (
56
+ Object.keys(e).filter(d => d && MAP_FILTERS.includes(d) && d != "theme").length > 0
57
+ || this._parent.map.getVisibleUsers().filter(u => u !== "geovisio").length > 0
58
+ );
59
+ });
60
+
61
+ this._parent.map.on("users-changed", e => {
62
+ this._active = (
63
+ Object.keys(this._parent.map._mapFilters).filter(d => d && d !== "theme").length > 0
64
+ || e.usersIds.filter(u => u !== "geovisio").length > 0
65
+ );
66
+ });
67
+ });
68
+ }
69
+
70
+ /** @private */
71
+ render() {
72
+ const isSmall = this._parent?.isWidthSmall();
73
+ const resetIcon = fa(faXmark);
74
+ resetIcon.addEventListener("click", e => {
75
+ e.stopPropagation();
76
+ this.shadowRoot.querySelector("pnx-map-filters-menu")._onReset();
77
+ this.shadowRoot.querySelector("#pnx-widget-filter")._opened = false;
78
+ });
79
+
80
+ return html`
81
+ <pnx-togglable-group
82
+ id="pnx-widget-filter"
83
+ padded="false"
84
+ class="pnx-only-map pnx-print-hidden"
85
+ ._parent=${this._parent}
86
+ >
87
+ <pnx-button kind="flat" size="xl" slot="button">
88
+ ${fa(faSliders)}
89
+ ${this._active ? html`<span class="pnx-active-icon"></span>` : nothing}
90
+ ${isSmall ? nothing : this._parent?._t.pnx.filters}
91
+ ${isSmall ? nothing : (this._active ? resetIcon : fa(faChevronDown))}
92
+ </pnx-button>
93
+ <pnx-map-filters-menu
94
+ id="pnx-map-filters-menu"
95
+ ._parent=${this._parent}
96
+ user-search=${this["user-search"]}
97
+ quality-score=${this["quality-score"]}
98
+ ></pnx-map-filters-menu>
99
+ </pnx-togglable-group>
100
+ `;
101
+ }
102
+ }
103
+
104
+ customElements.define("pnx-widget-mapfilters", MapFiltersButton);
@@ -0,0 +1,79 @@
1
+ import { LitElement, html, nothing } from "lit";
2
+ import { fa } from "../../../utils/widgets";
3
+ import { faLayerGroup } from "@fortawesome/free-solid-svg-icons/faLayerGroup";
4
+ import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
5
+ import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark";
6
+ import { activeIcon } from "../../styles";
7
+
8
+ /**
9
+ * Collapsible button showing off map filters menus.
10
+ * @class Panoramax.components.ui.widgets.MapLayersButton
11
+ * @element pnx-widget-maplayers
12
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
13
+ * @example
14
+ * ```html
15
+ * <pnx-widget-maplayers _parent=${viewer} />
16
+ * ```
17
+ */
18
+ export default class MapLayersButton extends LitElement {
19
+ /** @private */
20
+ static styles = [activeIcon];
21
+
22
+ /** @private */
23
+ static properties = {
24
+ _active: {state: true},
25
+ };
26
+
27
+ constructor() {
28
+ super();
29
+ this._active = false;
30
+ }
31
+
32
+ /** @private */
33
+ connectedCallback() {
34
+ super.connectedCallback();
35
+
36
+ const nullThemes = [undefined, null, "", "default"];
37
+
38
+ this._parent?.onceMapReady?.().then(() => {
39
+ this._active = !nullThemes.includes(this._parent.map._mapFilters.theme);
40
+ this._parent.map.on("filters-changed", e => {
41
+ this._active = !nullThemes.includes(e.theme);
42
+ });
43
+ });
44
+ }
45
+
46
+ /** @private */
47
+ render() {
48
+ const isSmall = this._parent?.isWidthSmall();
49
+ const resetIcon = fa(faXmark);
50
+ resetIcon.addEventListener("click", e => {
51
+ e.stopPropagation();
52
+ const menu = this.shadowRoot.querySelector("pnx-map-layers-menu");
53
+ menu.shadowRoot.querySelector("#pnx-map-theme").value = "default";
54
+ menu._onThemeSelect({target: {value: "default"}});
55
+ this.shadowRoot.querySelector("#pnx-widget-map-layers")._opened = false;
56
+ });
57
+
58
+ return html`
59
+ <pnx-togglable-group
60
+ id="pnx-widget-map-layers"
61
+ class="pnx-print-hidden"
62
+ ._parent=${this._parent}
63
+ >
64
+ <pnx-button kind="flat" size="xl" slot="button">
65
+ ${fa(faLayerGroup)}
66
+ ${this._active ? html`<span class="pnx-active-icon"></span>` : nothing}
67
+ ${isSmall ? nothing : this._parent?._t.pnx.layers}
68
+ ${isSmall ? nothing : (this._active ? resetIcon : fa(faChevronDown))}
69
+ </pnx-button>
70
+ <pnx-map-layers-menu
71
+ id="pnx-map-layers-menu"
72
+ ._parent=${this._parent}
73
+ ></pnx-map-layers-menu>
74
+ </pnx-togglable-group>
75
+ `;
76
+ }
77
+ }
78
+
79
+ customElements.define("pnx-widget-maplayers", MapLayersButton);
@@ -0,0 +1,7 @@
1
+ pnx-widget-player {
2
+ pointer-events: none;
3
+ }
4
+
5
+ pnx-widget-player > pnx-button-group {
6
+ pointer-events: auto;
7
+ }