@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.
- package/.gitlab-ci.yml +13 -6
- package/CHANGELOG.md +53 -1
- package/CODE_OF_CONDUCT.md +1 -1
- package/README.md +1 -1
- package/build/editor.html +10 -1
- package/build/index.css +12 -12
- package/build/index.css.map +1 -1
- package/build/index.html +1 -1
- package/build/index.js +2126 -14
- package/build/index.js.map +1 -1
- package/build/map.html +1 -1
- package/build/photo.html +1 -0
- package/build/static/media/atkinson-hyperlegible-next-latin-400-normal..woff +0 -0
- package/build/static/media/atkinson-hyperlegible-next-latin-400-normal..woff2 +0 -0
- package/build/static/media/atkinson-hyperlegible-next-latin-ext-400-normal..woff +0 -0
- package/build/static/media/atkinson-hyperlegible-next-latin-ext-400-normal..woff2 +0 -0
- package/build/viewer.html +12 -1
- package/build/widgets.html +1 -0
- package/config/jest/mocks.js +201 -0
- package/config/paths.js +2 -0
- package/config/webpack.config.js +52 -0
- package/docs/03_URL_settings.md +14 -16
- package/docs/05_Compatibility.md +59 -76
- package/docs/09_Develop.md +46 -11
- package/docs/90_Releases.md +2 -2
- package/docs/images/class_diagram.drawio +60 -45
- package/docs/images/class_diagram.jpg +0 -0
- package/docs/images/screenshot.jpg +0 -0
- package/docs/index.md +135 -0
- package/docs/reference/components/core/Basic.md +196 -0
- package/docs/reference/components/core/CoverageMap.md +210 -0
- package/docs/reference/components/core/Editor.md +224 -0
- package/docs/reference/components/core/PhotoViewer.md +307 -0
- package/docs/reference/components/core/Viewer.md +350 -0
- package/docs/reference/components/layout/BottomDrawer.md +35 -0
- package/docs/reference/components/layout/CorneredGrid.md +29 -0
- package/docs/reference/components/layout/Mini.md +45 -0
- package/docs/reference/components/layout/Tabs.md +45 -0
- package/docs/reference/components/menus/MapBackground.md +32 -0
- package/docs/reference/components/menus/MapFilters.md +15 -0
- package/docs/reference/components/menus/MapLayers.md +15 -0
- package/docs/reference/components/menus/MapLegend.md +15 -0
- package/docs/reference/components/menus/PictureLegend.md +16 -0
- package/docs/reference/components/menus/PictureMetadata.md +15 -0
- package/docs/reference/components/menus/PlayerOptions.md +15 -0
- package/docs/reference/components/menus/QualityScoreDoc.md +15 -0
- package/docs/reference/components/menus/ReportForm.md +15 -0
- package/docs/reference/components/menus/ShareMenu.md +15 -0
- package/docs/reference/components/ui/Button.md +40 -0
- package/docs/reference/components/ui/ButtonGroup.md +36 -0
- package/docs/reference/components/ui/CopyButton.md +38 -0
- package/docs/reference/components/ui/Grade.md +32 -0
- package/docs/reference/components/ui/LinkButton.md +45 -0
- package/docs/reference/components/ui/ListGroup.md +22 -0
- package/docs/reference/components/ui/Loader.md +56 -0
- package/docs/reference/components/ui/Map.md +239 -0
- package/docs/reference/components/ui/MapMore.md +256 -0
- package/docs/reference/components/ui/Photo.md +385 -0
- package/docs/reference/components/ui/Popup.md +56 -0
- package/docs/reference/components/ui/ProgressBar.md +32 -0
- package/docs/reference/components/ui/QualityScore.md +45 -0
- package/docs/reference/components/ui/SearchBar.md +63 -0
- package/docs/reference/components/ui/TogglableGroup.md +39 -0
- package/docs/reference/components/ui/widgets/GeoSearch.md +32 -0
- package/docs/reference/components/ui/widgets/Legend.md +49 -0
- package/docs/reference/components/ui/widgets/MapFiltersButton.md +33 -0
- package/docs/reference/components/ui/widgets/MapLayersButton.md +15 -0
- package/docs/reference/components/ui/widgets/OSMEditors.md +15 -0
- package/docs/reference/components/ui/widgets/PictureLegendActions.md +32 -0
- package/docs/reference/components/ui/widgets/Player.md +33 -0
- package/docs/reference/components/ui/widgets/Zoom.md +15 -0
- package/docs/reference/utils/API.md +334 -0
- package/docs/reference/utils/InitParameters.md +68 -0
- package/docs/reference/utils/URLHandler.md +107 -0
- package/docs/reference.md +79 -0
- package/docs/shortcuts.md +11 -0
- package/docs/tutorials/aerial_imagery.md +19 -0
- package/docs/tutorials/authentication.md +10 -0
- package/docs/tutorials/custom_widgets.md +59 -0
- package/docs/tutorials/map_style.md +39 -0
- package/docs/tutorials/migrate_v4.md +153 -0
- package/docs/tutorials/synced_coverage.md +43 -0
- package/mkdocs.yml +66 -5
- package/package.json +22 -17
- package/public/editor.html +21 -29
- package/public/index.html +17 -12
- package/public/map.html +19 -18
- package/public/photo.html +55 -0
- package/public/viewer.html +22 -26
- package/public/widgets.html +306 -0
- package/scripts/doc.js +79 -0
- package/src/components/core/Basic.css +48 -0
- package/src/components/core/Basic.js +349 -0
- package/src/components/core/CoverageMap.css +9 -0
- package/src/components/core/CoverageMap.js +139 -0
- package/src/components/core/Editor.css +23 -0
- package/src/components/core/Editor.js +390 -0
- package/src/components/core/PhotoViewer.css +48 -0
- package/src/components/core/PhotoViewer.js +499 -0
- package/src/components/core/Viewer.css +98 -0
- package/src/components/core/Viewer.js +564 -0
- package/src/components/core/index.js +12 -0
- package/src/components/index.js +13 -0
- package/src/components/layout/BottomDrawer.js +257 -0
- package/src/components/layout/CorneredGrid.js +112 -0
- package/src/components/layout/Mini.js +117 -0
- package/src/components/layout/Tabs.js +133 -0
- package/src/components/layout/index.js +9 -0
- package/src/components/menus/MapBackground.js +106 -0
- package/src/components/menus/MapFilters.js +400 -0
- package/src/components/menus/MapLayers.js +143 -0
- package/src/components/menus/MapLegend.js +34 -0
- package/src/components/menus/PictureLegend.js +257 -0
- package/src/components/menus/PictureMetadata.js +317 -0
- package/src/components/menus/PlayerOptions.js +95 -0
- package/src/components/menus/QualityScoreDoc.js +36 -0
- package/src/components/menus/ReportForm.js +133 -0
- package/src/components/menus/Share.js +100 -0
- package/src/components/menus/index.js +15 -0
- package/src/components/styles.js +383 -0
- package/src/components/ui/Button.js +77 -0
- package/src/components/ui/ButtonGroup.css +57 -0
- package/src/components/ui/ButtonGroup.js +68 -0
- package/src/components/ui/CopyButton.js +106 -0
- package/src/components/ui/Grade.js +54 -0
- package/src/components/ui/LinkButton.js +67 -0
- package/src/components/ui/ListGroup.js +66 -0
- package/src/components/ui/Loader.js +203 -0
- package/src/components/{Map.css → ui/Map.css} +5 -17
- package/src/components/{Map.js → ui/Map.js} +148 -156
- package/src/components/ui/MapMore.js +324 -0
- package/src/components/{Photo.css → ui/Photo.css} +6 -6
- package/src/components/{Photo.js → ui/Photo.js} +313 -101
- package/src/components/ui/Popup.js +145 -0
- package/src/components/ui/ProgressBar.js +104 -0
- package/src/components/ui/QualityScore.js +147 -0
- package/src/components/ui/SearchBar.js +367 -0
- package/src/components/ui/TogglableGroup.js +157 -0
- package/src/components/ui/index.js +22 -0
- package/src/components/ui/widgets/GeoSearch.css +21 -0
- package/src/components/ui/widgets/GeoSearch.js +139 -0
- package/src/components/ui/widgets/Legend.js +113 -0
- package/src/components/ui/widgets/MapFiltersButton.js +104 -0
- package/src/components/ui/widgets/MapLayersButton.js +79 -0
- package/src/components/ui/widgets/OSMEditors.js +155 -0
- package/src/components/ui/widgets/PictureLegendActions.js +117 -0
- package/src/components/ui/widgets/Player.css +7 -0
- package/src/components/ui/widgets/Player.js +151 -0
- package/src/components/ui/widgets/Zoom.js +82 -0
- package/src/components/ui/widgets/index.js +13 -0
- package/src/img/loader_base.jpg +0 -0
- package/src/img/panoramax.svg +13 -0
- package/src/img/switch_big.svg +20 -10
- package/src/index.js +7 -9
- package/src/translations/br.json +1 -0
- package/src/translations/da.json +38 -15
- package/src/translations/de.json +5 -3
- package/src/translations/en.json +35 -15
- package/src/translations/eo.json +38 -15
- package/src/translations/es.json +1 -1
- package/src/translations/fr.json +36 -16
- package/src/translations/hu.json +1 -1
- package/src/translations/it.json +39 -16
- package/src/translations/ja.json +182 -1
- package/src/translations/nl.json +106 -6
- package/src/translations/pl.json +1 -1
- package/src/translations/sv.json +182 -0
- package/src/translations/zh_Hant.json +35 -14
- package/src/utils/API.js +109 -49
- package/src/utils/InitParameters.js +388 -0
- package/src/utils/PhotoAdapter.js +1 -0
- package/src/utils/URLHandler.js +362 -0
- package/src/utils/geocoder.js +152 -0
- package/src/utils/{I18n.js → i18n.js} +7 -3
- package/src/utils/index.js +11 -0
- package/src/utils/{Map.js → map.js} +256 -77
- package/src/utils/picture.js +442 -0
- package/src/utils/utils.js +324 -0
- package/src/utils/widgets.js +55 -0
- package/tests/components/core/Basic.test.js +121 -0
- package/tests/components/core/BasicMock.js +25 -0
- package/tests/components/core/CoverageMap.test.js +20 -0
- package/tests/components/core/Editor.test.js +20 -0
- package/tests/components/core/PhotoViewer.test.js +57 -0
- package/tests/components/core/Viewer.test.js +84 -0
- package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +73 -0
- package/tests/components/core/__snapshots__/Viewer.test.js.snap +145 -0
- package/tests/components/ui/CopyButton.test.js +52 -0
- package/tests/components/ui/Loader.test.js +55 -0
- package/tests/components/{Map.test.js → ui/Map.test.js} +73 -61
- package/tests/components/{Photo.test.js → ui/Photo.test.js} +97 -63
- package/tests/components/ui/Popup.test.js +26 -0
- package/tests/components/ui/QualityScore.test.js +18 -0
- package/tests/components/ui/SearchBar.test.js +110 -0
- package/tests/components/ui/__snapshots__/CopyButton.test.js.snap +33 -0
- package/tests/components/ui/__snapshots__/Loader.test.js.snap +56 -0
- package/tests/components/{__snapshots__ → ui/__snapshots__}/Map.test.js.snap +11 -38
- package/tests/components/{__snapshots__ → ui/__snapshots__}/Photo.test.js.snap +70 -6
- package/tests/components/ui/__snapshots__/Popup.test.js.snap +29 -0
- package/tests/components/ui/__snapshots__/QualityScore.test.js.snap +11 -0
- package/tests/components/ui/__snapshots__/SearchBar.test.js.snap +65 -0
- package/tests/utils/API.test.js +83 -83
- package/tests/utils/InitParameters.test.js +499 -0
- package/tests/utils/URLHandler.test.js +401 -0
- package/tests/utils/__snapshots__/API.test.js.snap +10 -0
- package/tests/utils/__snapshots__/URLHandler.test.js.snap +21 -0
- package/tests/utils/__snapshots__/{Map.test.js.snap → geocoder.test.js.snap} +1 -1
- package/tests/utils/__snapshots__/map.test.js.snap +11 -0
- package/tests/utils/__snapshots__/picture.test.js.snap +327 -0
- package/tests/utils/__snapshots__/widgets.test.js.snap +19 -0
- package/tests/utils/geocoder.test.js +37 -0
- package/tests/utils/{I18n.test.js → i18n.test.js} +8 -8
- package/tests/utils/map.test.js +126 -0
- package/tests/utils/picture.test.js +745 -0
- package/tests/utils/utils.test.js +288 -0
- package/tests/utils/widgets.test.js +31 -0
- package/docs/01_Start.md +0 -149
- package/docs/02_Usage.md +0 -831
- package/docs/04_Advanced_examples.md +0 -216
- package/src/Editor.css +0 -37
- package/src/Editor.js +0 -361
- package/src/StandaloneMap.js +0 -114
- package/src/Viewer.css +0 -203
- package/src/Viewer.js +0 -1246
- package/src/components/CoreView.css +0 -70
- package/src/components/CoreView.js +0 -175
- package/src/components/Loader.css +0 -74
- package/src/components/Loader.js +0 -120
- package/src/img/loader_hd.jpg +0 -0
- package/src/utils/Exif.js +0 -193
- package/src/utils/Utils.js +0 -631
- package/src/utils/Widgets.js +0 -562
- package/src/viewer/URLHash.js +0 -469
- package/src/viewer/Widgets.css +0 -880
- package/src/viewer/Widgets.js +0 -1470
- package/tests/Editor.test.js +0 -126
- package/tests/StandaloneMap.test.js +0 -45
- package/tests/Viewer.test.js +0 -366
- package/tests/__snapshots__/Editor.test.js.snap +0 -298
- package/tests/__snapshots__/StandaloneMap.test.js.snap +0 -30
- package/tests/__snapshots__/Viewer.test.js.snap +0 -195
- package/tests/components/CoreView.test.js +0 -92
- package/tests/components/Loader.test.js +0 -38
- package/tests/components/__snapshots__/Loader.test.js.snap +0 -15
- package/tests/utils/Exif.test.js +0 -124
- package/tests/utils/Map.test.js +0 -113
- package/tests/utils/Utils.test.js +0 -300
- package/tests/utils/Widgets.test.js +0 -107
- package/tests/utils/__snapshots__/Exif.test.js.snap +0 -43
- package/tests/utils/__snapshots__/Utils.test.js.snap +0 -41
- package/tests/utils/__snapshots__/Widgets.test.js.snap +0 -44
- package/tests/viewer/URLHash.test.js +0 -559
- package/tests/viewer/Widgets.test.js +0 -127
- package/tests/viewer/__snapshots__/URLHash.test.js.snap +0 -108
- package/tests/viewer/__snapshots__/Widgets.test.js.snap +0 -403
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
|
|
3
|
+
import "./Viewer.css";
|
|
4
|
+
import { linkMapAndPhoto, saveMapParamsToLocalStorage, getMapParamsFromLocalStorage } from "../../utils/map";
|
|
5
|
+
import PhotoViewer from "./PhotoViewer";
|
|
6
|
+
import Basic from "./Basic";
|
|
7
|
+
import MapMore from "../ui/MapMore";
|
|
8
|
+
import { initMapKeyboardHandler } from "../../utils/map";
|
|
9
|
+
import { isNullId } from "../../utils/utils";
|
|
10
|
+
import { createWebComp } from "../../utils/widgets";
|
|
11
|
+
import { fa } from "../../utils/widgets";
|
|
12
|
+
import { faPanorama } from "@fortawesome/free-solid-svg-icons/faPanorama";
|
|
13
|
+
import { faMap } from "@fortawesome/free-solid-svg-icons/faMap";
|
|
14
|
+
import { querySelectorDeep } from "query-selector-shadow-dom";
|
|
15
|
+
import { default as InitParameters, alterMapState, alterViewerState } from "../../utils/InitParameters";
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export const PSV_ZOOM_DELTA = 20;
|
|
19
|
+
const PSV_MOVE_DELTA = Math.PI / 6;
|
|
20
|
+
const MAP_MOVE_DELTA = 100;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Viewer is the main component of Panoramax JS library, showing pictures and map.
|
|
25
|
+
*
|
|
26
|
+
* This component has a [CorneredGrid](#Panoramax.components.layout.CorneredGrid) layout, you can use directly any slot element to pass custom widgets.
|
|
27
|
+
*
|
|
28
|
+
* If you need a viewer without map, checkout [Photo Viewer component](#Panoramax.components.core.PhotoViewer).
|
|
29
|
+
*
|
|
30
|
+
* Make sure to set width/height through CSS for proper display.
|
|
31
|
+
* @class Panoramax.components.core.Viewer
|
|
32
|
+
* @element pnx-viewer
|
|
33
|
+
* @extends Panoramax.components.core.PhotoViewer
|
|
34
|
+
* @property {Panoramax.components.ui.Loader} loader The loader screen
|
|
35
|
+
* @property {Panoramax.utils.API} api The API manager
|
|
36
|
+
* @property {Panoramax.components.ui.MapMore} map The MapLibre GL map itself
|
|
37
|
+
* @property {Panoramax.components.ui.Photo} psv The Photo Sphere Viewer component itself
|
|
38
|
+
* @property {Panoramax.components.layout.CorneredGrid} grid The grid layout manager
|
|
39
|
+
* @property {Panoramax.components.layout.Mini} mini The reduced/collapsed map/photo component
|
|
40
|
+
* @property {Panoramax.components.ui.Popup} popup The popup container
|
|
41
|
+
* @property {Panoramax.utils.URLHandler} urlHandler The URL query parameters manager
|
|
42
|
+
* @fires Panoramax.components.core.Basic#select
|
|
43
|
+
* @fires Panoramax.components.core.Basic#ready
|
|
44
|
+
* @fires Panoramax.components.core.Basic#broken
|
|
45
|
+
* @fires Panoramax.components.core.Viewer#focus-changed
|
|
46
|
+
* @slot `top-left` The top-left corner
|
|
47
|
+
* @slot `top` The top middle corner
|
|
48
|
+
* @slot `top-right` The top-right corner
|
|
49
|
+
* @slot `bottom-left` The bottom-left corner
|
|
50
|
+
* @slot `bottom` The bottom middle corner
|
|
51
|
+
* @slot `bottom-right` The bottom-right corner
|
|
52
|
+
* @slot `editors` External links to map editors, or any tool that may be helpful. Defaults to OSM tools (iD & JOSM).
|
|
53
|
+
* @example
|
|
54
|
+
* ```html
|
|
55
|
+
* <!-- Basic example -->
|
|
56
|
+
* <pnx-viewer
|
|
57
|
+
* endpoint="https://panoramax.openstreetmap.fr/"
|
|
58
|
+
* style="width: 300px; height: 250px"
|
|
59
|
+
* />
|
|
60
|
+
*
|
|
61
|
+
* <!-- With slotted widgets -->
|
|
62
|
+
* <pnx-viewer
|
|
63
|
+
* endpoint="https://panoramax.openstreetmap.fr/"
|
|
64
|
+
* style="width: 300px; height: 250px"
|
|
65
|
+
* >
|
|
66
|
+
* <p slot="top-right">My custom text</p>
|
|
67
|
+
* <p slot="editors"><a href="https://my.own.tool/">Edit in my own tool</a></p>
|
|
68
|
+
* </pnx-viewer>
|
|
69
|
+
*
|
|
70
|
+
* <!-- With only your custom widgets -->
|
|
71
|
+
* <pnx-viewer
|
|
72
|
+
* endpoint="https://panoramax.openstreetmap.fr/"
|
|
73
|
+
* style="width: 300px; height: 250px"
|
|
74
|
+
* widgets="false"
|
|
75
|
+
* >
|
|
76
|
+
* <p slot="top-right">My custom text</p>
|
|
77
|
+
* </pnx-viewer>
|
|
78
|
+
*
|
|
79
|
+
* <!-- With map options -->
|
|
80
|
+
* <pnx-viewer
|
|
81
|
+
* endpoint="https://panoramax.openstreetmap.fr/"
|
|
82
|
+
* style="width: 300px; height: 250px"
|
|
83
|
+
* map="{'maxZoom': 15, 'background': 'aerial', 'raster': '...'}"
|
|
84
|
+
* />
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export default class Viewer extends PhotoViewer {
|
|
88
|
+
/**
|
|
89
|
+
* Component properties. All of [Basic properties](#Panoramax.components.core.Basic+properties) are available as well.
|
|
90
|
+
* @memberof Panoramax.components.core.Viewer#
|
|
91
|
+
* @mixes Panoramax.components.core.PhotoViewer#properties
|
|
92
|
+
* @type {Object}
|
|
93
|
+
* @property {string} endpoint URL to API to use (must be a [STAC API](https://github.com/radiantearth/stac-api-spec/blob/main/overview.md))
|
|
94
|
+
* @property {object} [map] An object with [any map option available in Map or MapMore class](#Panoramax.components.ui.MapMore).<br />Example: `map="{'background': 'aerial', 'theme': 'age'}"`
|
|
95
|
+
* @property {object} [psv] [Any option to pass to Photo component](#Panoramax.components.ui.Photo) as an object.<br />Example: `psv="{'transitionDuration': 500, 'picturesNavigation': 'pic'}"`
|
|
96
|
+
* @property {string} [url-parameters=true] Should the component add and update URL query parameters to save viewer state ?
|
|
97
|
+
* @property {string} [focus=pic] The component showing up as main component (pic, map)
|
|
98
|
+
* @property {string} [geocoder=nominatim] The geocoder engine to use (nominatim, ban)
|
|
99
|
+
* @property {string} [widgets=true] Use default set of widgets ? Set to false to avoid any widget to show up, and use slots to populate as you like.
|
|
100
|
+
* @property {string} [picture] The picture ID to display
|
|
101
|
+
* @property {string} [sequence] The sequence ID of the picture displayed
|
|
102
|
+
* @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))
|
|
103
|
+
* @property {string[]} [users=[geovisio]] List of users IDs to use for map display (defaults to general map, identified as "geovisio")
|
|
104
|
+
* @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.
|
|
105
|
+
* @property {string} [lang] To override language used for labels. Defaults to using user's preferred languages.
|
|
106
|
+
*/
|
|
107
|
+
static properties = {
|
|
108
|
+
map: {converter: PhotoViewer.GetJSONConverter()},
|
|
109
|
+
focus: {type: String, reflect: true},
|
|
110
|
+
geocoder: {type: String},
|
|
111
|
+
...PhotoViewer.properties
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
constructor() {
|
|
115
|
+
super();
|
|
116
|
+
|
|
117
|
+
// Defaults
|
|
118
|
+
this.map = true;
|
|
119
|
+
this.geocoder = this.getAttribute("geocoder") || "nominatim";
|
|
120
|
+
|
|
121
|
+
// Init DOM containers
|
|
122
|
+
this.mini = createWebComp("pnx-mini", {
|
|
123
|
+
slot: "bottom-left",
|
|
124
|
+
_parent: this,
|
|
125
|
+
onexpand: this._onMiniExpand.bind(this),
|
|
126
|
+
collapsed: isNullId(this.picture) ? true : undefined
|
|
127
|
+
});
|
|
128
|
+
this.mini.addEventListener("expand", this._toggleFocus.bind(this));
|
|
129
|
+
this.grid.appendChild(this.mini);
|
|
130
|
+
this.mapContainer = document.createElement("div");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** @private */
|
|
134
|
+
_createInitParamsHandler() {
|
|
135
|
+
this._initParams = new InitParameters(
|
|
136
|
+
InitParameters.GetComponentProperties(Viewer, this),
|
|
137
|
+
Object.assign({}, this.urlHandler?.currentURLParams(), this.urlHandler?.currentURLParams(true)),
|
|
138
|
+
{ map: getMapParamsFromLocalStorage() },
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** @private */
|
|
143
|
+
_initWidgets() {
|
|
144
|
+
if(this._initParams.getParentPostInit().widgets !== "false") {
|
|
145
|
+
this.grid.appendChild(createWebComp("pnx-widget-zoom", {
|
|
146
|
+
slot: this.isWidthSmall() ? "top-left" : "bottom-right",
|
|
147
|
+
class: this.isWidthSmall() ? "pnx-only-map pnx-print-hidden" : "pnx-print-hidden",
|
|
148
|
+
_parent: this
|
|
149
|
+
}));
|
|
150
|
+
|
|
151
|
+
if(!this.isWidthSmall()) {
|
|
152
|
+
this.legend = createWebComp("pnx-widget-legend", {
|
|
153
|
+
slot: this.isWidthSmall() ? "top" : "top-left",
|
|
154
|
+
_parent: this,
|
|
155
|
+
focus: this._initParams.getParentPostInit().focus,
|
|
156
|
+
picture: this._initParams.getParentPostInit().picture,
|
|
157
|
+
});
|
|
158
|
+
this.grid.appendChild(this.legend);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.legend = createWebComp("pnx-picture-legend", { _parent: this });
|
|
162
|
+
this.bottomDrawer = createWebComp("pnx-bottom-drawer", {
|
|
163
|
+
slot: "bottom",
|
|
164
|
+
_parent: this,
|
|
165
|
+
class: this._initParams.getParentPostInit().picture ? undefined: "pnx-hidden",
|
|
166
|
+
});
|
|
167
|
+
this.bottomDrawer.appendChild(this.legend);
|
|
168
|
+
this.grid.appendChild(this.bottomDrawer);
|
|
169
|
+
this.addEventListener("select", e => {
|
|
170
|
+
if(isNullId(e.detail.picId)) { this.bottomDrawer.classList.add("pnx-hidden"); }
|
|
171
|
+
else { this.bottomDrawer.classList.remove("pnx-hidden"); }
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.grid.appendChild(createWebComp("pnx-widget-player", {
|
|
176
|
+
slot: "top",
|
|
177
|
+
_parent: this,
|
|
178
|
+
class: "pnx-only-psv pnx-print-hidden",
|
|
179
|
+
size: this.isHeightSmall() ? "md": "xl",
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
this.grid.appendChild(createWebComp("pnx-widget-geosearch", {
|
|
183
|
+
slot: this.isWidthSmall() ? "top-right" : "top-left",
|
|
184
|
+
_parent: this,
|
|
185
|
+
class: "pnx-only-map pnx-print-hidden",
|
|
186
|
+
geocoder: this._initParams.getParentPostInit().geocoder,
|
|
187
|
+
}));
|
|
188
|
+
this.grid.appendChild(createWebComp("pnx-widget-mapfilters", {
|
|
189
|
+
slot: this.isWidthSmall() ? "top-right" : "top-left",
|
|
190
|
+
_parent: this,
|
|
191
|
+
"user-search": this.api._endpoints.user_search !== null && this.api._endpoints.user_tiles !== null,
|
|
192
|
+
"quality-score": this.map?._hasQualityScore?.() || false,
|
|
193
|
+
class: "pnx-only-map pnx-print-hidden",
|
|
194
|
+
}));
|
|
195
|
+
this.grid.appendChild(createWebComp("pnx-widget-maplayers", { slot: "top-right", _parent: this, class: "pnx-only-map pnx-print-hidden" }));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
getClassName() {
|
|
200
|
+
return "Viewer";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
getSubComponentsNames() {
|
|
204
|
+
return super.getSubComponentsNames().concat(["mini", "map"]);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Waits for Viewer to be completely ready (map & PSV loaded, first picture also if one is wanted)
|
|
209
|
+
* @returns {Promise} When viewer is ready
|
|
210
|
+
* @memberof Panoramax.components.core.Viewer#
|
|
211
|
+
*/
|
|
212
|
+
onceReady() {
|
|
213
|
+
return Promise.all([this.oncePSVReady(), this.onceMapReady()])
|
|
214
|
+
.then(() => {
|
|
215
|
+
if(this._initParams.getParentPostInit().picture && !this.psv.getPictureMetadata()) { return this.onceFirstPicLoaded(); }
|
|
216
|
+
else { return Promise.resolve(); }
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** @private */
|
|
221
|
+
attributeChangedCallback(name, old, value) {
|
|
222
|
+
super.attributeChangedCallback(name, old, value);
|
|
223
|
+
|
|
224
|
+
if(name === "picture") {
|
|
225
|
+
this.legend?.setAttribute?.("picture", value);
|
|
226
|
+
|
|
227
|
+
// First pic load : show map in mini component
|
|
228
|
+
if(isNullId(old) && !isNullId(value)) {
|
|
229
|
+
this.mini.removeAttribute("collapsed");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Unselect -> show map wide instead
|
|
233
|
+
if(isNullId(value)) {
|
|
234
|
+
if(this.map && this.isMapWide()) { this.mini.classList.add("pnx-hidden"); }
|
|
235
|
+
else if(this.map && !this.isMapWide()) { this._setFocus("map"); }
|
|
236
|
+
}
|
|
237
|
+
// Select after none selected -> show pic wide
|
|
238
|
+
else {
|
|
239
|
+
this.mini.classList.remove("pnx-hidden");
|
|
240
|
+
if(isNullId(old)) {
|
|
241
|
+
this._setFocus("pic");
|
|
242
|
+
if(this.bottomDrawer?.getAttribute?.("openness") === "closed") {
|
|
243
|
+
this.bottomDrawer.setAttribute("openness", "half-opened");
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if(name === "focus") {
|
|
250
|
+
this._setFocus(value);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Waiting for map to be available.
|
|
256
|
+
* @returns {Promise} When map is ready to use
|
|
257
|
+
* @memberof Panoramax.components.core.Viewer#
|
|
258
|
+
*/
|
|
259
|
+
onceMapReady() {
|
|
260
|
+
if(!this.map) { return Promise.resolve(); }
|
|
261
|
+
|
|
262
|
+
let waiter;
|
|
263
|
+
return new Promise(resolve => {
|
|
264
|
+
waiter = setInterval(() => {
|
|
265
|
+
if(typeof this.map === "object") {
|
|
266
|
+
if(this.map?.loaded?.()) {
|
|
267
|
+
clearInterval(waiter);
|
|
268
|
+
resolve();
|
|
269
|
+
}
|
|
270
|
+
else if(this.map?.once) {
|
|
271
|
+
this.map.once("render", () => {
|
|
272
|
+
clearInterval(waiter);
|
|
273
|
+
resolve();
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}, 250);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Inits MapLibre GL component
|
|
283
|
+
*
|
|
284
|
+
* @private
|
|
285
|
+
* @returns {Promise} Resolves when map is ready
|
|
286
|
+
*/
|
|
287
|
+
async _initMap() {
|
|
288
|
+
await new Promise(resolve => {
|
|
289
|
+
this.map = new MapMore(this, this.mapContainer, this._initParams.getMapInit());
|
|
290
|
+
saveMapParamsToLocalStorage(this.map);
|
|
291
|
+
this.map.once("users-changed", () => {
|
|
292
|
+
this.loader.setAttribute("value", 75);
|
|
293
|
+
resolve();
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
alterMapState(this.map, this._initParams.getMapPostInit());
|
|
298
|
+
initMapKeyboardHandler(this);
|
|
299
|
+
linkMapAndPhoto(this);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** @private */
|
|
303
|
+
async _postAPIInit() {
|
|
304
|
+
this.loader.setAttribute("value", 30);
|
|
305
|
+
this._createInitParamsHandler();
|
|
306
|
+
|
|
307
|
+
const myPostInitParams = this._initParams.getParentPostInit();
|
|
308
|
+
|
|
309
|
+
this._initPSV();
|
|
310
|
+
await this._initMap();
|
|
311
|
+
this._initWidgets();
|
|
312
|
+
|
|
313
|
+
// Re-launch slot move (for those depending on widgets)
|
|
314
|
+
this._moveChildToGrid();
|
|
315
|
+
|
|
316
|
+
alterViewerState(this, myPostInitParams);
|
|
317
|
+
this._handleKeyboardManagement();
|
|
318
|
+
|
|
319
|
+
if(myPostInitParams.picture) {
|
|
320
|
+
this.psv.addEventListener("picture-loaded", () => {
|
|
321
|
+
alterViewerState(this, myPostInitParams); // Do it again for forcing focus
|
|
322
|
+
this.loader.dismiss();
|
|
323
|
+
}, {once: true});
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
this.loader.dismiss();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** @private */
|
|
331
|
+
_handleKeyboardManagement() {
|
|
332
|
+
// Switchers
|
|
333
|
+
const keytomap = () => {
|
|
334
|
+
this.psv.stopKeyboardControl();
|
|
335
|
+
this.map.keyboard.enable();
|
|
336
|
+
};
|
|
337
|
+
const keytopsv = () => {
|
|
338
|
+
this.psv.startKeyboardControl();
|
|
339
|
+
this.map?.keyboard?.disable();
|
|
340
|
+
};
|
|
341
|
+
const keytonone = () => {
|
|
342
|
+
this.psv.stopKeyboardControl();
|
|
343
|
+
this.map?.keyboard?.disable();
|
|
344
|
+
};
|
|
345
|
+
const keytofocused = () => {
|
|
346
|
+
if(this.map && this.isMapWide()) { keytomap(); }
|
|
347
|
+
else { keytopsv(); }
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// General focus change
|
|
351
|
+
this.addEventListener("focus-changed", e => {
|
|
352
|
+
if(e.detail.focus === "map") { keytomap(); }
|
|
353
|
+
else { keytopsv(); }
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// Popup
|
|
357
|
+
this.popup.addEventListener("open", () => keytonone());
|
|
358
|
+
this.popup.addEventListener("close", () => keytofocused());
|
|
359
|
+
|
|
360
|
+
// Widgets
|
|
361
|
+
for(let cn of this.grid.childNodes) {
|
|
362
|
+
if(cn.getAttribute("slot") !== "bg") {
|
|
363
|
+
cn.addEventListener("focusin", () => keytonone());
|
|
364
|
+
cn.addEventListener("focusout", () => keytofocused());
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Move the view of main component to its center.
|
|
371
|
+
* For map, center view on selected picture.
|
|
372
|
+
* For picture, center view on image center.
|
|
373
|
+
* @memberof Panoramax.components.core.Viewer#
|
|
374
|
+
*/
|
|
375
|
+
moveCenter() {
|
|
376
|
+
const meta = this.psv.getPictureMetadata();
|
|
377
|
+
if(!meta) { return; }
|
|
378
|
+
|
|
379
|
+
if(this.map && this.isMapWide()) {
|
|
380
|
+
this.map.flyTo({ center: meta.gps, zoom: 20 });
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
super.moveCenter();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Moves map or picture viewer to given direction.
|
|
389
|
+
* @param {string} dir Direction to move to (up, left, down, right)
|
|
390
|
+
* @private
|
|
391
|
+
*/
|
|
392
|
+
_moveToDirection(dir) {
|
|
393
|
+
if(this.map && this.isMapWide()) {
|
|
394
|
+
let pan;
|
|
395
|
+
switch(dir) {
|
|
396
|
+
case "up":
|
|
397
|
+
pan = [0, -MAP_MOVE_DELTA];
|
|
398
|
+
break;
|
|
399
|
+
case "left":
|
|
400
|
+
pan = [-MAP_MOVE_DELTA, 0];
|
|
401
|
+
break;
|
|
402
|
+
case "down":
|
|
403
|
+
pan = [0, MAP_MOVE_DELTA];
|
|
404
|
+
break;
|
|
405
|
+
case "right":
|
|
406
|
+
pan = [MAP_MOVE_DELTA, 0];
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
this.map.panBy(pan);
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
super._moveToDirection(dir);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Is the map shown as main element instead of viewer (wide map mode) ?
|
|
418
|
+
* @memberof Panoramax.components.core.Viewer#
|
|
419
|
+
* @returns {boolean} True if map is wider than viewer
|
|
420
|
+
*/
|
|
421
|
+
isMapWide() {
|
|
422
|
+
return this.mapContainer.parentNode == this.grid;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Change the viewer focus (either on picture or map)
|
|
427
|
+
* @memberof Panoramax.components.core.Viewer#
|
|
428
|
+
* @param {string} focus The object to focus on (map, pic)
|
|
429
|
+
* @param {boolean} [skipEvent=false] True to not send focus-changed event
|
|
430
|
+
* @param {boolean} [skipDupCheck=false] True to avoid duplicate calls check
|
|
431
|
+
* @private
|
|
432
|
+
*/
|
|
433
|
+
_setFocus(focus, skipEvent = false, skipDupCheck = false) {
|
|
434
|
+
if(focus === "map" && !this.map) { throw new Error("Map is not enabled"); }
|
|
435
|
+
if(!["map", "pic"].includes(focus)) { throw new Error("Invalid focus value (should be pic or map)"); }
|
|
436
|
+
this.focus = focus;
|
|
437
|
+
|
|
438
|
+
if(!skipDupCheck && (
|
|
439
|
+
(focus === "map" && this.map && this.isMapWide())
|
|
440
|
+
|| (focus === "pic" && (!this.map || !this.isMapWide()))
|
|
441
|
+
)) { return; }
|
|
442
|
+
|
|
443
|
+
if(focus === "map") {
|
|
444
|
+
// Remove PSV from grid
|
|
445
|
+
if(this.psvContainer.parentNode == this.grid) {
|
|
446
|
+
this.grid.removeChild(this.psvContainer);
|
|
447
|
+
this.psvContainer.removeAttribute("slot");
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Remove map from mini
|
|
451
|
+
if(this.mapContainer.parentNode == this.mini) {
|
|
452
|
+
this.mini.removeChild(this.mapContainer);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Add map to grid
|
|
456
|
+
this.mapContainer.setAttribute("slot", "bg");
|
|
457
|
+
this.grid.appendChild(this.mapContainer);
|
|
458
|
+
|
|
459
|
+
// Add PSV to mini
|
|
460
|
+
this.mini.appendChild(this.psvContainer);
|
|
461
|
+
this.mini.icon = fa(faPanorama);
|
|
462
|
+
|
|
463
|
+
// Hide mini icon if no picture selected
|
|
464
|
+
if(isNullId(this.picture)) { this.mini.classList.add("pnx-hidden"); }
|
|
465
|
+
else { this.mini.classList.remove("pnx-hidden"); }
|
|
466
|
+
|
|
467
|
+
this.map.getCanvas().focus();
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// Remove map from grid
|
|
471
|
+
if(this.mapContainer.parentNode == this.grid) {
|
|
472
|
+
this.grid.removeChild(this.mapContainer);
|
|
473
|
+
this.mapContainer.removeAttribute("slot");
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Remove PSV from mini
|
|
477
|
+
if(this.psvContainer.parentNode == this.mini) {
|
|
478
|
+
this.mini.removeChild(this.psvContainer);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Add PSV to grid
|
|
482
|
+
this.psvContainer.setAttribute("slot", "bg");
|
|
483
|
+
this.grid.appendChild(this.psvContainer);
|
|
484
|
+
|
|
485
|
+
// Add map to mini
|
|
486
|
+
this.mini.classList.remove("pnx-hidden");
|
|
487
|
+
this.mini.appendChild(this.mapContainer);
|
|
488
|
+
this.mini.icon = fa(faMap);
|
|
489
|
+
|
|
490
|
+
this.psvContainer.focus();
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
this?.map?.resize?.();
|
|
494
|
+
this.psv.autoSize();
|
|
495
|
+
this.psv.forceRefresh();
|
|
496
|
+
this.legend?.setAttribute?.("focus", this.focus);
|
|
497
|
+
|
|
498
|
+
if(!skipEvent) {
|
|
499
|
+
/**
|
|
500
|
+
* Event for focus change (either map or picture is shown wide)
|
|
501
|
+
* @event Panoramax.components.core.Viewer#focus-changed
|
|
502
|
+
* @type {CustomEvent}
|
|
503
|
+
* @property {string} detail.focus Component now focused on (map, pic)
|
|
504
|
+
*/
|
|
505
|
+
const event = new CustomEvent("focus-changed", { detail: { focus } });
|
|
506
|
+
this.dispatchEvent(event);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Toggle the viewer focus (either on picture or map)
|
|
512
|
+
* @memberof Panoramax.components.core.Viewer#
|
|
513
|
+
* @private
|
|
514
|
+
*/
|
|
515
|
+
_toggleFocus() {
|
|
516
|
+
this._setFocus(this.isMapWide() ? "pic" : "map");
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** @private */
|
|
520
|
+
_onMiniExpand() {
|
|
521
|
+
this.map.resize();
|
|
522
|
+
this.psv.autoSize();
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Send viewer new map filters values.
|
|
527
|
+
* @private
|
|
528
|
+
*/
|
|
529
|
+
_onMapFiltersChange() {
|
|
530
|
+
const mapFiltersMenu = querySelectorDeep("#pnx-map-filters-menu");
|
|
531
|
+
const fMinDate = mapFiltersMenu?.shadowRoot.getElementById("pnx-filter-date-from");
|
|
532
|
+
const fMaxDate = mapFiltersMenu?.shadowRoot.getElementById("pnx-filter-date-end");
|
|
533
|
+
const fTypes = mapFiltersMenu?.shadowRoot.querySelectorAll("input[name='pnx-filter-type']");
|
|
534
|
+
const fMapTheme = querySelectorDeep("#pnx-map-theme");
|
|
535
|
+
|
|
536
|
+
let type = "";
|
|
537
|
+
for(let fTypeId = 0 ; fTypeId < fTypes.length; fTypeId++) {
|
|
538
|
+
const fType = fTypes[fTypeId];
|
|
539
|
+
if(fType.checked) {
|
|
540
|
+
type = fType.value;
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
let qualityscore = [];
|
|
546
|
+
if(this.map?._hasQualityScore()) {
|
|
547
|
+
const fScore = mapFiltersMenu?.shadowRoot.getElementById("pnx-filter-qualityscore");
|
|
548
|
+
qualityscore = (fScore?.grade || "").split(",").map(v => parseInt(v)).filter(v => !isNaN(v));
|
|
549
|
+
if(qualityscore.length == 5) { qualityscore = []; }
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const values = {
|
|
553
|
+
minDate: fMinDate?.value,
|
|
554
|
+
maxDate: fMaxDate?.value,
|
|
555
|
+
pic_type: type,
|
|
556
|
+
theme: fMapTheme?.value,
|
|
557
|
+
qualityscore,
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
this.map.setFilters(values);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
customElements.define("pnx-viewer", Viewer);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* eslint-disable import/no-unused-modules */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Core graphical components
|
|
5
|
+
* @module Panoramax:components:core
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {default as Basic} from "./Basic";
|
|
9
|
+
export {default as CoverageMap} from "./CoverageMap";
|
|
10
|
+
export {default as Editor} from "./Editor";
|
|
11
|
+
export {default as Viewer} from "./Viewer";
|
|
12
|
+
export {default as PhotoViewer} from "./PhotoViewer";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* eslint-disable import/no-unused-modules */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Graphical components
|
|
5
|
+
* @module Panoramax:components
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as core from "./core";
|
|
9
|
+
import * as layout from "./layout";
|
|
10
|
+
import * as menus from "./menus";
|
|
11
|
+
import * as ui from "./ui";
|
|
12
|
+
|
|
13
|
+
export {core, layout, menus, ui};
|