@panoramax/web-viewer 3.2.3 → 4.0.0-develop-39167b4d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/.gitlab-ci.yml +13 -6
  2. package/CHANGELOG.md +53 -1
  3. package/CODE_OF_CONDUCT.md +1 -1
  4. package/README.md +1 -1
  5. package/build/editor.html +10 -1
  6. package/build/index.css +12 -12
  7. package/build/index.css.map +1 -1
  8. package/build/index.html +1 -1
  9. package/build/index.js +2126 -14
  10. package/build/index.js.map +1 -1
  11. package/build/map.html +1 -1
  12. package/build/photo.html +1 -0
  13. package/build/static/media/atkinson-hyperlegible-next-latin-400-normal..woff +0 -0
  14. package/build/static/media/atkinson-hyperlegible-next-latin-400-normal..woff2 +0 -0
  15. package/build/static/media/atkinson-hyperlegible-next-latin-ext-400-normal..woff +0 -0
  16. package/build/static/media/atkinson-hyperlegible-next-latin-ext-400-normal..woff2 +0 -0
  17. package/build/viewer.html +12 -1
  18. package/build/widgets.html +1 -0
  19. package/config/jest/mocks.js +201 -0
  20. package/config/paths.js +2 -0
  21. package/config/webpack.config.js +52 -0
  22. package/docs/03_URL_settings.md +14 -16
  23. package/docs/05_Compatibility.md +59 -76
  24. package/docs/09_Develop.md +46 -11
  25. package/docs/90_Releases.md +2 -2
  26. package/docs/images/class_diagram.drawio +60 -45
  27. package/docs/images/class_diagram.jpg +0 -0
  28. package/docs/images/screenshot.jpg +0 -0
  29. package/docs/index.md +135 -0
  30. package/docs/reference/components/core/Basic.md +196 -0
  31. package/docs/reference/components/core/CoverageMap.md +210 -0
  32. package/docs/reference/components/core/Editor.md +224 -0
  33. package/docs/reference/components/core/PhotoViewer.md +307 -0
  34. package/docs/reference/components/core/Viewer.md +350 -0
  35. package/docs/reference/components/layout/BottomDrawer.md +35 -0
  36. package/docs/reference/components/layout/CorneredGrid.md +29 -0
  37. package/docs/reference/components/layout/Mini.md +45 -0
  38. package/docs/reference/components/layout/Tabs.md +45 -0
  39. package/docs/reference/components/menus/MapBackground.md +32 -0
  40. package/docs/reference/components/menus/MapFilters.md +15 -0
  41. package/docs/reference/components/menus/MapLayers.md +15 -0
  42. package/docs/reference/components/menus/MapLegend.md +15 -0
  43. package/docs/reference/components/menus/PictureLegend.md +16 -0
  44. package/docs/reference/components/menus/PictureMetadata.md +15 -0
  45. package/docs/reference/components/menus/PlayerOptions.md +15 -0
  46. package/docs/reference/components/menus/QualityScoreDoc.md +15 -0
  47. package/docs/reference/components/menus/ReportForm.md +15 -0
  48. package/docs/reference/components/menus/ShareMenu.md +15 -0
  49. package/docs/reference/components/ui/Button.md +40 -0
  50. package/docs/reference/components/ui/ButtonGroup.md +36 -0
  51. package/docs/reference/components/ui/CopyButton.md +38 -0
  52. package/docs/reference/components/ui/Grade.md +32 -0
  53. package/docs/reference/components/ui/LinkButton.md +45 -0
  54. package/docs/reference/components/ui/ListGroup.md +22 -0
  55. package/docs/reference/components/ui/Loader.md +56 -0
  56. package/docs/reference/components/ui/Map.md +239 -0
  57. package/docs/reference/components/ui/MapMore.md +256 -0
  58. package/docs/reference/components/ui/Photo.md +385 -0
  59. package/docs/reference/components/ui/Popup.md +56 -0
  60. package/docs/reference/components/ui/ProgressBar.md +32 -0
  61. package/docs/reference/components/ui/QualityScore.md +45 -0
  62. package/docs/reference/components/ui/SearchBar.md +63 -0
  63. package/docs/reference/components/ui/TogglableGroup.md +39 -0
  64. package/docs/reference/components/ui/widgets/GeoSearch.md +32 -0
  65. package/docs/reference/components/ui/widgets/Legend.md +49 -0
  66. package/docs/reference/components/ui/widgets/MapFiltersButton.md +33 -0
  67. package/docs/reference/components/ui/widgets/MapLayersButton.md +15 -0
  68. package/docs/reference/components/ui/widgets/OSMEditors.md +15 -0
  69. package/docs/reference/components/ui/widgets/PictureLegendActions.md +32 -0
  70. package/docs/reference/components/ui/widgets/Player.md +33 -0
  71. package/docs/reference/components/ui/widgets/Zoom.md +15 -0
  72. package/docs/reference/utils/API.md +334 -0
  73. package/docs/reference/utils/InitParameters.md +68 -0
  74. package/docs/reference/utils/URLHandler.md +107 -0
  75. package/docs/reference.md +79 -0
  76. package/docs/shortcuts.md +11 -0
  77. package/docs/tutorials/aerial_imagery.md +19 -0
  78. package/docs/tutorials/authentication.md +10 -0
  79. package/docs/tutorials/custom_widgets.md +59 -0
  80. package/docs/tutorials/map_style.md +39 -0
  81. package/docs/tutorials/migrate_v4.md +153 -0
  82. package/docs/tutorials/synced_coverage.md +43 -0
  83. package/mkdocs.yml +66 -5
  84. package/package.json +22 -17
  85. package/public/editor.html +21 -29
  86. package/public/index.html +17 -12
  87. package/public/map.html +19 -18
  88. package/public/photo.html +55 -0
  89. package/public/viewer.html +22 -26
  90. package/public/widgets.html +306 -0
  91. package/scripts/doc.js +79 -0
  92. package/src/components/core/Basic.css +48 -0
  93. package/src/components/core/Basic.js +349 -0
  94. package/src/components/core/CoverageMap.css +9 -0
  95. package/src/components/core/CoverageMap.js +139 -0
  96. package/src/components/core/Editor.css +23 -0
  97. package/src/components/core/Editor.js +390 -0
  98. package/src/components/core/PhotoViewer.css +48 -0
  99. package/src/components/core/PhotoViewer.js +499 -0
  100. package/src/components/core/Viewer.css +98 -0
  101. package/src/components/core/Viewer.js +564 -0
  102. package/src/components/core/index.js +12 -0
  103. package/src/components/index.js +13 -0
  104. package/src/components/layout/BottomDrawer.js +257 -0
  105. package/src/components/layout/CorneredGrid.js +112 -0
  106. package/src/components/layout/Mini.js +117 -0
  107. package/src/components/layout/Tabs.js +133 -0
  108. package/src/components/layout/index.js +9 -0
  109. package/src/components/menus/MapBackground.js +106 -0
  110. package/src/components/menus/MapFilters.js +400 -0
  111. package/src/components/menus/MapLayers.js +143 -0
  112. package/src/components/menus/MapLegend.js +34 -0
  113. package/src/components/menus/PictureLegend.js +257 -0
  114. package/src/components/menus/PictureMetadata.js +317 -0
  115. package/src/components/menus/PlayerOptions.js +95 -0
  116. package/src/components/menus/QualityScoreDoc.js +36 -0
  117. package/src/components/menus/ReportForm.js +133 -0
  118. package/src/components/menus/Share.js +100 -0
  119. package/src/components/menus/index.js +15 -0
  120. package/src/components/styles.js +383 -0
  121. package/src/components/ui/Button.js +77 -0
  122. package/src/components/ui/ButtonGroup.css +57 -0
  123. package/src/components/ui/ButtonGroup.js +68 -0
  124. package/src/components/ui/CopyButton.js +106 -0
  125. package/src/components/ui/Grade.js +54 -0
  126. package/src/components/ui/LinkButton.js +67 -0
  127. package/src/components/ui/ListGroup.js +66 -0
  128. package/src/components/ui/Loader.js +203 -0
  129. package/src/components/{Map.css → ui/Map.css} +5 -17
  130. package/src/components/{Map.js → ui/Map.js} +148 -156
  131. package/src/components/ui/MapMore.js +324 -0
  132. package/src/components/{Photo.css → ui/Photo.css} +6 -6
  133. package/src/components/{Photo.js → ui/Photo.js} +313 -101
  134. package/src/components/ui/Popup.js +145 -0
  135. package/src/components/ui/ProgressBar.js +104 -0
  136. package/src/components/ui/QualityScore.js +147 -0
  137. package/src/components/ui/SearchBar.js +367 -0
  138. package/src/components/ui/TogglableGroup.js +157 -0
  139. package/src/components/ui/index.js +22 -0
  140. package/src/components/ui/widgets/GeoSearch.css +21 -0
  141. package/src/components/ui/widgets/GeoSearch.js +139 -0
  142. package/src/components/ui/widgets/Legend.js +113 -0
  143. package/src/components/ui/widgets/MapFiltersButton.js +104 -0
  144. package/src/components/ui/widgets/MapLayersButton.js +79 -0
  145. package/src/components/ui/widgets/OSMEditors.js +155 -0
  146. package/src/components/ui/widgets/PictureLegendActions.js +117 -0
  147. package/src/components/ui/widgets/Player.css +7 -0
  148. package/src/components/ui/widgets/Player.js +151 -0
  149. package/src/components/ui/widgets/Zoom.js +82 -0
  150. package/src/components/ui/widgets/index.js +13 -0
  151. package/src/img/loader_base.jpg +0 -0
  152. package/src/img/panoramax.svg +13 -0
  153. package/src/img/switch_big.svg +20 -10
  154. package/src/index.js +7 -9
  155. package/src/translations/br.json +1 -0
  156. package/src/translations/da.json +38 -15
  157. package/src/translations/de.json +5 -3
  158. package/src/translations/en.json +35 -15
  159. package/src/translations/eo.json +38 -15
  160. package/src/translations/es.json +1 -1
  161. package/src/translations/fr.json +36 -16
  162. package/src/translations/hu.json +1 -1
  163. package/src/translations/it.json +39 -16
  164. package/src/translations/ja.json +182 -1
  165. package/src/translations/nl.json +106 -6
  166. package/src/translations/pl.json +1 -1
  167. package/src/translations/sv.json +182 -0
  168. package/src/translations/zh_Hant.json +35 -14
  169. package/src/utils/API.js +109 -49
  170. package/src/utils/InitParameters.js +388 -0
  171. package/src/utils/PhotoAdapter.js +1 -0
  172. package/src/utils/URLHandler.js +362 -0
  173. package/src/utils/geocoder.js +152 -0
  174. package/src/utils/{I18n.js → i18n.js} +7 -3
  175. package/src/utils/index.js +11 -0
  176. package/src/utils/{Map.js → map.js} +256 -77
  177. package/src/utils/picture.js +442 -0
  178. package/src/utils/utils.js +324 -0
  179. package/src/utils/widgets.js +55 -0
  180. package/tests/components/core/Basic.test.js +121 -0
  181. package/tests/components/core/BasicMock.js +25 -0
  182. package/tests/components/core/CoverageMap.test.js +20 -0
  183. package/tests/components/core/Editor.test.js +20 -0
  184. package/tests/components/core/PhotoViewer.test.js +57 -0
  185. package/tests/components/core/Viewer.test.js +84 -0
  186. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +73 -0
  187. package/tests/components/core/__snapshots__/Viewer.test.js.snap +145 -0
  188. package/tests/components/ui/CopyButton.test.js +52 -0
  189. package/tests/components/ui/Loader.test.js +55 -0
  190. package/tests/components/{Map.test.js → ui/Map.test.js} +73 -61
  191. package/tests/components/{Photo.test.js → ui/Photo.test.js} +97 -63
  192. package/tests/components/ui/Popup.test.js +26 -0
  193. package/tests/components/ui/QualityScore.test.js +18 -0
  194. package/tests/components/ui/SearchBar.test.js +110 -0
  195. package/tests/components/ui/__snapshots__/CopyButton.test.js.snap +33 -0
  196. package/tests/components/ui/__snapshots__/Loader.test.js.snap +56 -0
  197. package/tests/components/{__snapshots__ → ui/__snapshots__}/Map.test.js.snap +11 -38
  198. package/tests/components/{__snapshots__ → ui/__snapshots__}/Photo.test.js.snap +70 -6
  199. package/tests/components/ui/__snapshots__/Popup.test.js.snap +29 -0
  200. package/tests/components/ui/__snapshots__/QualityScore.test.js.snap +11 -0
  201. package/tests/components/ui/__snapshots__/SearchBar.test.js.snap +65 -0
  202. package/tests/utils/API.test.js +83 -83
  203. package/tests/utils/InitParameters.test.js +499 -0
  204. package/tests/utils/URLHandler.test.js +401 -0
  205. package/tests/utils/__snapshots__/API.test.js.snap +10 -0
  206. package/tests/utils/__snapshots__/URLHandler.test.js.snap +21 -0
  207. package/tests/utils/__snapshots__/{Map.test.js.snap → geocoder.test.js.snap} +1 -1
  208. package/tests/utils/__snapshots__/map.test.js.snap +11 -0
  209. package/tests/utils/__snapshots__/picture.test.js.snap +327 -0
  210. package/tests/utils/__snapshots__/widgets.test.js.snap +19 -0
  211. package/tests/utils/geocoder.test.js +37 -0
  212. package/tests/utils/{I18n.test.js → i18n.test.js} +8 -8
  213. package/tests/utils/map.test.js +126 -0
  214. package/tests/utils/picture.test.js +745 -0
  215. package/tests/utils/utils.test.js +288 -0
  216. package/tests/utils/widgets.test.js +31 -0
  217. package/docs/01_Start.md +0 -149
  218. package/docs/02_Usage.md +0 -831
  219. package/docs/04_Advanced_examples.md +0 -216
  220. package/src/Editor.css +0 -37
  221. package/src/Editor.js +0 -361
  222. package/src/StandaloneMap.js +0 -114
  223. package/src/Viewer.css +0 -203
  224. package/src/Viewer.js +0 -1246
  225. package/src/components/CoreView.css +0 -70
  226. package/src/components/CoreView.js +0 -175
  227. package/src/components/Loader.css +0 -74
  228. package/src/components/Loader.js +0 -120
  229. package/src/img/loader_hd.jpg +0 -0
  230. package/src/utils/Exif.js +0 -193
  231. package/src/utils/Utils.js +0 -631
  232. package/src/utils/Widgets.js +0 -562
  233. package/src/viewer/URLHash.js +0 -469
  234. package/src/viewer/Widgets.css +0 -880
  235. package/src/viewer/Widgets.js +0 -1470
  236. package/tests/Editor.test.js +0 -126
  237. package/tests/StandaloneMap.test.js +0 -45
  238. package/tests/Viewer.test.js +0 -366
  239. package/tests/__snapshots__/Editor.test.js.snap +0 -298
  240. package/tests/__snapshots__/StandaloneMap.test.js.snap +0 -30
  241. package/tests/__snapshots__/Viewer.test.js.snap +0 -195
  242. package/tests/components/CoreView.test.js +0 -92
  243. package/tests/components/Loader.test.js +0 -38
  244. package/tests/components/__snapshots__/Loader.test.js.snap +0 -15
  245. package/tests/utils/Exif.test.js +0 -124
  246. package/tests/utils/Map.test.js +0 -113
  247. package/tests/utils/Utils.test.js +0 -300
  248. package/tests/utils/Widgets.test.js +0 -107
  249. package/tests/utils/__snapshots__/Exif.test.js.snap +0 -43
  250. package/tests/utils/__snapshots__/Utils.test.js.snap +0 -41
  251. package/tests/utils/__snapshots__/Widgets.test.js.snap +0 -44
  252. package/tests/viewer/URLHash.test.js +0 -559
  253. package/tests/viewer/Widgets.test.js +0 -127
  254. package/tests/viewer/__snapshots__/URLHash.test.js.snap +0 -108
  255. package/tests/viewer/__snapshots__/Widgets.test.js.snap +0 -403
@@ -0,0 +1,390 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import "./Editor.css";
3
+ import Basic from "./Basic";
4
+ import Map from "../ui/Map";
5
+ import Photo from "../ui/Photo";
6
+ import BackgroundAerial from "../../img/bg_aerial.jpg";
7
+ import BackgroundStreets from "../../img/bg_streets.jpg";
8
+ import { apiFeatureToPSVNode } from "../../utils/picture";
9
+ import { linkMapAndPhoto } from "../../utils/map";
10
+ import { VECTOR_STYLES } from "../../utils/map";
11
+ import { SYSTEM as PSSystem } from "@photo-sphere-viewer/core";
12
+ import { css } from "lit";
13
+ import { createWebComp } from "../../utils/widgets";
14
+
15
+ const LAYER_HEADING_ID = "sequence-headings";
16
+
17
+ /**
18
+ * Editor allows to focus on a single sequence, and preview what you edits would look like.
19
+ * It shows both picture and map.
20
+ *
21
+ * Make sure to set width/height through CSS for proper display.
22
+ * @class Panoramax.components.core.Editor
23
+ * @element pnx-editor
24
+ * @extends Panoramax.components.core.Basic
25
+ * @fires Panoramax.components.core.Basic#select
26
+ * @fires Panoramax.components.core.Basic#ready
27
+ * @fires Panoramax.components.core.Basic#broken
28
+ * @property {Panoramax.components.ui.Loader} loader The loader screen
29
+ * @property {Panoramax.utils.API} api The API manager
30
+ * @property {Panoramax.components.ui.Map} map The MapLibre GL map itself
31
+ * @property {Panoramax.components.ui.Photo} psv The Photo Sphere Viewer component itself
32
+ * @example
33
+ * ```html
34
+ * <pnx-editor
35
+ * endpoint="https://panoramax.openstreetmap.fr/"
36
+ * style="width: 300px; height: 250px"
37
+ * />
38
+ * ```
39
+ */
40
+ export default class Editor extends Basic {
41
+ /**
42
+ * Component properties. All of [Basic properties](#Panoramax.components.core.Basic+properties) are available as well.
43
+ * @memberof Panoramax.components.core.Editor#
44
+ * @mixes Panoramax.components.core.Basic#properties
45
+ * @type {Object}
46
+ * @property {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md))
47
+ * @property {string} [picture] The picture ID to display
48
+ * @property {string} [sequence] The sequence ID of the picture displayed
49
+ * @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))
50
+ * @property {string|object} [mapstyle] The map's MapLibre style. This can be an a JSON object conforming to the schema described in the [MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/), or a URL string pointing to one. Defaults to OSM vector tiles.
51
+ * @property {string} [lang] To override language used for labels. Defaults to using user's preferred languages.
52
+ * @property {object} [raster] The MapLibre raster source for aerial background. This must be a JSON object following [MapLibre raster source definition](https://maplibre.org/maplibre-style-spec/sources/#raster).
53
+ * @property {string} [background=streets] Choose default map background to display (streets or aerial, if raster aerial background available). Defaults to street.
54
+ */
55
+ static properties = {
56
+ raster: {converter: Basic.GetJSONConverter()},
57
+ background: {type: String},
58
+ ...Basic.properties
59
+ };
60
+
61
+ constructor() {
62
+ super();
63
+
64
+ this.raster = null;
65
+ this.background = "streets";
66
+ this.users = []; // Avoid default map data showing up
67
+
68
+ // Create sub-containers
69
+ this._psvContainer = document.createElement("div");
70
+ this._mapContainer = document.createElement("div");
71
+
72
+ this.onceAPIReady().then(() => {
73
+ this.loader.setAttribute("value", 30);
74
+
75
+ // Check sequence ID is set
76
+ if(!this.sequence) { this.loader.dismiss({}, "No sequence is selected"); }
77
+
78
+ // Events
79
+ this.addEventListener("select", this._onSelect.bind(this));
80
+
81
+ this._initPSV();
82
+ this._initMap();
83
+ });
84
+ }
85
+
86
+ getClassName() {
87
+ return "Editor";
88
+ }
89
+
90
+ onceReady() {
91
+ if(this.map && this.psv && this.map.loaded?.()) {
92
+ return Promise.resolve();
93
+ }
94
+ else {
95
+ return new Promise(resolve => setTimeout(resolve, 100)).then(this.onceReady.bind(this));
96
+ }
97
+ }
98
+
99
+ connectedCallback() {
100
+ if(Array.isArray(this.users) && this.users.length > 0) {
101
+ console.warn("Parameters users can't be changed in Editor, only selected sequence can be visible");
102
+ this.users = [];
103
+ }
104
+ super.connectedCallback();
105
+ }
106
+
107
+ attributeChangedCallback(name, old, value) {
108
+ if(name === "users" && Array.isArray(value) && value.length > 0) {
109
+ console.warn("Parameters users can't be changed in Editor, only selected sequence can be visible");
110
+ }
111
+ else {
112
+ super.attributeChangedCallback(name, old, value);
113
+ }
114
+ }
115
+
116
+ /** @private */
117
+ render() {
118
+ return [this.loader, this._psvContainer, this._mapContainer];
119
+ }
120
+
121
+ getSubComponentsNames() {
122
+ return super.getSubComponentsNames().concat(["map", "psv"]);
123
+ }
124
+
125
+ /** @private */
126
+ _initPSV() {
127
+ try {
128
+ this.psv = new Photo(this, this._psvContainer);
129
+ this.psv._myVTour.datasource.nodeResolver = this._getNode.bind(this);
130
+ }
131
+ catch(e) {
132
+ let err = !PSSystem.isWebGLSupported ? this._t.pnx.error_webgl : this._t.pnx.error_psv;
133
+ this.loader.dismiss(e, err);
134
+ }
135
+ }
136
+
137
+ /** @private */
138
+ _initMap() {
139
+ try {
140
+ this.map = new Map(this, this._mapContainer, {
141
+ raster: this.raster,
142
+ background: this.background,
143
+ supplementaryStyle: this._createMapStyle(),
144
+ zoom: 15, // Hack to avoid _initMapPosition call
145
+ });
146
+ linkMapAndPhoto(this);
147
+ this.loader.setAttribute("value", 50);
148
+ this._loadSequence();
149
+ this.map.once("load", () => {
150
+ if(this.map.hasTwoBackgrounds()) { this._addMapBackgroundWidget(); }
151
+ this._bindPicturesEvents();
152
+ });
153
+
154
+ // Override picMarker setRotation for heading preview
155
+ const oldRot = this.map._picMarker.setRotation.bind(this.map._picMarker);
156
+ this.map._picMarker.setRotation = h => {
157
+ h = this._lastRelHeading === undefined ? h : h + this._lastRelHeading - this.psv.getPictureRelativeHeading();
158
+ return oldRot(h);
159
+ };
160
+ }
161
+ catch(e) {
162
+ this.loader.dismiss(e, this._t.pnx.error_psv);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Create style for GeoJSON sequence data.
168
+ * @private
169
+ */
170
+ _createMapStyle() {
171
+ return {
172
+ sources: {
173
+ geovisio_editor_sequences: {
174
+ type: "geojson",
175
+ data: {"type": "FeatureCollection", "features": [] }
176
+ }
177
+ },
178
+ layers: [
179
+ {
180
+ "id": "geovisio_editor_sequences",
181
+ "type": "line",
182
+ "source": "geovisio_editor_sequences",
183
+ "layout": {
184
+ ...VECTOR_STYLES.SEQUENCES.layout
185
+ },
186
+ "paint": {
187
+ ...VECTOR_STYLES.SEQUENCES.paint
188
+ },
189
+ },
190
+ {
191
+ "id": "geovisio_editor_pictures",
192
+ "type": "circle",
193
+ "source": "geovisio_editor_sequences",
194
+ "layout": {
195
+ ...VECTOR_STYLES.PICTURES.layout
196
+ },
197
+ "paint": {
198
+ ...VECTOR_STYLES.PICTURES.paint
199
+ },
200
+ }
201
+ ]
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Creates events handlers on pictures layer
207
+ * @private
208
+ */
209
+ _bindPicturesEvents() {
210
+ // Pictures events
211
+ this.map.on("mousemove", "geovisio_editor_pictures", () => {
212
+ this.map.getCanvas().style.cursor = "pointer";
213
+ });
214
+
215
+ this.map.on("mouseleave", "geovisio_editor_pictures", () => {
216
+ this.map.getCanvas().style.cursor = "";
217
+ });
218
+
219
+ this.map.on("click", "geovisio_editor_pictures", this.map._onPictureClick.bind(this.map));
220
+ }
221
+
222
+ /**
223
+ * Displays currently selected sequence on map
224
+ * @private
225
+ */
226
+ _loadSequence() {
227
+ this.loader.setAttribute("value", 60);
228
+ return this.api.getSequenceItems(this.sequence).then(seq => {
229
+ this.loader.setAttribute("value", 80);
230
+
231
+ // Hide loader after source load
232
+ this.map.once("sourcedata", () => {
233
+ this.map.setPaintProperty("geovisio_editor_sequences", "line-color", this.map._getLayerColorStyle("sequences"));
234
+ this.map.setPaintProperty("geovisio_editor_pictures", "circle-color", this.map._getLayerColorStyle("pictures"));
235
+ this.map.setLayoutProperty("geovisio_editor_sequences", "visibility", "visible");
236
+ this.map.setLayoutProperty("geovisio_editor_pictures", "visibility", "visible");
237
+ this.map.once("styledata", () => this.loader.dismiss());
238
+ });
239
+
240
+ // Create data source
241
+ this._sequenceData = seq.features;
242
+ this.map.getSource("geovisio_editor_sequences").setData({
243
+ "type": "FeatureCollection",
244
+ "features": [
245
+ {
246
+ "type": "Feature",
247
+ "properties": {
248
+ "id": this.sequence,
249
+ },
250
+ "geometry":
251
+ {
252
+ "type": "LineString",
253
+ "coordinates": seq.features.map(p => p.geometry.coordinates)
254
+ }
255
+ },
256
+ ...seq.features.map(f => {
257
+ f.properties.id = f.id;
258
+ f.properties.sequences = [this.sequence];
259
+ return f;
260
+ })
261
+ ]
262
+ });
263
+
264
+ // Select picture if any
265
+ if(this.picture) {
266
+ const pic = seq.features.find(p => p.id === this.picture);
267
+ if(pic) {
268
+ this.select(this.sequence, this.picture, true);
269
+ this.map.jumpTo({ center: pic.geometry.coordinates, zoom: 18 });
270
+ }
271
+ else {
272
+ console.log("Picture with ID", pic, "was not found");
273
+ }
274
+ }
275
+ // Show area of sequence otherwise
276
+ else {
277
+ const bbox = [
278
+ ...seq.features[0].geometry.coordinates,
279
+ ...seq.features[0].geometry.coordinates
280
+ ];
281
+
282
+ for(let i=1; i < seq.features.length; i++) {
283
+ const c = seq.features[i].geometry.coordinates;
284
+ if(c[0] < bbox[0]) { bbox[0] = c[0]; }
285
+ if(c[1] < bbox[1]) { bbox[1] = c[1]; }
286
+ if(c[0] > bbox[2]) { bbox[2] = c[0]; }
287
+ if(c[1] > bbox[3]) { bbox[3] = c[1]; }
288
+ }
289
+
290
+ this.map.fitBounds(bbox, {animate: false});
291
+ }
292
+ }).catch(e => this.loader.dismiss(e, this._t.pnx.error_api));
293
+ }
294
+
295
+ /**
296
+ * Get the PSV node for wanted picture.
297
+ *
298
+ * @param {string} picId The picture ID
299
+ * @returns The PSV node
300
+ * @private
301
+ */
302
+ _getNode(picId) {
303
+ const f = this._sequenceData.find(f => f.properties.id === picId);
304
+ const n = f ? apiFeatureToPSVNode(f, this._t, this._isInternetFast) : null;
305
+ if(n) { delete n.links; }
306
+ return n;
307
+ }
308
+
309
+ /**
310
+ * Creates the widget to switch between aerial and streets imagery
311
+ * @private
312
+ */
313
+ _addMapBackgroundWidget() {
314
+ // Container
315
+ const pnlLayers = createWebComp("pnx-map-background", {_parent: this, size: "sm"});
316
+ this._mapContainer.appendChild(pnlLayers);
317
+ }
318
+
319
+ /**
320
+ * Preview on map how the new relative heading would reflect on all pictures.
321
+ * This doesn't change anything on API-side, it's just a preview.
322
+ * @memberof Panoramax.components.core.Editor#
323
+ * @param {number} [relHeading] The new relative heading compared to sequence path. In degrees, between -180 and 180 (0 = front, -90 = left, 90 = right). Set to null to remove preview.
324
+ */
325
+ previewSequenceHeadingChange(relHeading) {
326
+ const layerExists = this.map.getLayer(LAYER_HEADING_ID) !== undefined;
327
+ this.map._picMarkerPreview.remove();
328
+
329
+ // If no value set, remove layer
330
+ if(relHeading === undefined) {
331
+ delete this._lastRelHeading;
332
+ if(layerExists) {
333
+ this.map.setLayoutProperty(LAYER_HEADING_ID, "visibility", "none");
334
+ }
335
+ // Update selected picture marker
336
+ if(this.picture) {
337
+ this.map._picMarker.setRotation(this.psv.getXY().x);
338
+ }
339
+ return;
340
+ }
341
+
342
+ this._lastRelHeading = relHeading;
343
+
344
+ // Create preview layer
345
+ if(!layerExists) {
346
+ this.map.addLayer({
347
+ "id": LAYER_HEADING_ID,
348
+ "type": "symbol",
349
+ "source": "geovisio_editor_sequences",
350
+ "layout": {
351
+ "icon-image": "pnx-marker",
352
+ "icon-overlap": "always",
353
+ "icon-size": 0.8,
354
+ },
355
+ });
356
+ }
357
+
358
+ // Change heading
359
+ const currentRelHeading = - this.psv.getPictureRelativeHeading();
360
+ this.map.setLayoutProperty(LAYER_HEADING_ID, "visibility", "visible");
361
+ this.map.setLayoutProperty(
362
+ LAYER_HEADING_ID,
363
+ "icon-rotate",
364
+ ["+", ["get", "view:azimuth"], currentRelHeading, relHeading ]
365
+ );
366
+
367
+ // Skip selected picture and linestring geom
368
+ const filters = [["==", ["geometry-type"], "Point"]];
369
+ if(this.picture) { filters.push(["!=", ["get", "id"], this.picture]); }
370
+ this.map.setFilter(LAYER_HEADING_ID, ["all", ...filters]);
371
+
372
+ // Update selected picture marker
373
+ if(this.picture) {
374
+ this.map._picMarker.setRotation(this.psv.getXY().x);
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Event handler for picture loading
380
+ * @private
381
+ */
382
+ _onSelect() {
383
+ // Update preview of heading change
384
+ if(this._lastRelHeading !== undefined) {
385
+ this.previewSequenceHeadingChange(this._lastRelHeading);
386
+ }
387
+ }
388
+ }
389
+
390
+ customElements.define("pnx-editor", Editor);
@@ -0,0 +1,48 @@
1
+ /* Maximized components */
2
+ pnx-photo-viewer .pnx-psv {
3
+ position: absolute;
4
+ inset: 0;
5
+ z-index: 0;
6
+ }
7
+
8
+ /* No PSV loader */
9
+ pnx-photo-viewer .psv-loader {
10
+ display: none;
11
+ }
12
+
13
+ /* Cornered grid layout */
14
+ pnx-photo-viewer pnx-cornered-grid::part(corner-top-left),
15
+ pnx-photo-viewer pnx-cornered-grid::part(corner-top),
16
+ pnx-photo-viewer pnx-cornered-grid::part(corner-top-right),
17
+ pnx-photo-viewer pnx-cornered-grid::part(corner-bottom-left),
18
+ pnx-photo-viewer pnx-cornered-grid::part(corner-bottom),
19
+ pnx-photo-viewer pnx-cornered-grid::part(corner-bottom-right) {
20
+ gap: 10px;
21
+ padding: 10px;
22
+ }
23
+
24
+ @media screen and (max-width: 576px) {
25
+ pnx-photo-viewer pnx-cornered-grid::part(corner-top-right) {
26
+ flex-direction: column;
27
+ align-items: flex-end;
28
+ justify-content: flex-start;
29
+ }
30
+
31
+ pnx-photo-viewer pnx-cornered-grid::part(corner-top-left) {
32
+ flex-direction: column;
33
+ align-items: flex-start;
34
+ justify-content: flex-start;
35
+ }
36
+ }
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
+ }
48
+ }