@panoramax/web-viewer 4.0.1 → 4.0.2-develop-9b499e28
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/CHANGELOG.md +31 -3
- package/build/index.css +1 -1
- package/build/index.css.map +1 -1
- package/build/index.js +150 -51
- package/build/index.js.map +1 -1
- package/config/jest/mocks.js +2 -1
- package/docs/03_URL_settings.md +1 -1
- package/docs/09_Develop.md +5 -1
- package/docs/reference/components/core/Viewer.md +1 -1
- package/docs/reference/components/ui/CopyButton.md +1 -0
- package/docs/reference/components/ui/Map.md +13 -0
- package/docs/reference/components/ui/MapMore.md +13 -0
- package/docs/reference/components/ui/Photo.md +1 -1
- package/docs/reference/components/ui/widgets/CopyCoordinates.md +32 -0
- package/docs/reference/components/ui/widgets/GeoSearch.md +5 -1
- package/docs/reference/utils/API.md +1 -1
- package/docs/reference.md +1 -0
- package/docs/tutorials/migrate_v4.md +1 -1
- package/docs/tutorials/synced_coverage.md +1 -1
- package/mkdocs.yml +1 -0
- package/package.json +1 -1
- package/src/components/core/CoverageMap.js +2 -2
- package/src/components/core/PhotoViewer.js +5 -1
- package/src/components/core/Viewer.js +10 -5
- package/src/components/menus/PictureLegend.js +7 -4
- package/src/components/menus/PictureMetadata.js +23 -2
- package/src/components/styles.js +61 -0
- package/src/components/ui/ButtonGroup.css +2 -0
- package/src/components/ui/CopyButton.js +3 -1
- package/src/components/ui/Map.js +35 -4
- package/src/components/ui/Photo.js +4 -2
- package/src/components/ui/TogglableGroup.js +1 -1
- package/src/components/ui/widgets/CopyCoordinates.js +75 -0
- package/src/components/ui/widgets/GeoSearch.js +13 -5
- package/src/components/ui/widgets/Legend.js +1 -1
- package/src/components/ui/widgets/OSMEditors.js +2 -2
- package/src/components/ui/widgets/PictureLegendActions.js +1 -1
- package/src/components/ui/widgets/Player.js +1 -0
- package/src/components/ui/widgets/index.js +1 -0
- package/src/translations/en.json +6 -2
- package/src/translations/fr.json +6 -2
- package/src/translations/it.json +3 -1
- package/src/translations/ti.json +9 -0
- package/src/utils/API.js +1 -1
- package/src/utils/InitParameters.js +2 -2
- package/src/utils/geocoder.js +137 -83
- package/src/utils/index.js +2 -1
- package/src/utils/picture.js +6 -1
- package/src/utils/services.js +57 -0
- package/src/utils/utils.js +18 -5
- package/tests/components/ui/Map.test.js +7 -3
- package/tests/data/Map_geocoder_nominatim.json +25 -40
- package/tests/utils/InitParameters.test.js +15 -15
- package/tests/utils/__snapshots__/geocoder.test.js.snap +5 -16
- package/tests/utils/geocoder.test.js +2 -2
- package/tests/utils/utils.test.js +136 -109
package/config/jest/mocks.js
CHANGED
|
@@ -97,9 +97,10 @@ jest.mock("maplibre-gl", () => ({
|
|
|
97
97
|
addControl() {;}
|
|
98
98
|
addSource() {;}
|
|
99
99
|
addLayer() {;}
|
|
100
|
-
getLayer() {;}
|
|
100
|
+
getLayer(l) { return {id: l}; }
|
|
101
101
|
setLayoutProperty() {;}
|
|
102
102
|
setPaintProperty() {;}
|
|
103
|
+
loaded() { return true; }
|
|
103
104
|
getStyle() {
|
|
104
105
|
return {
|
|
105
106
|
layers: [],
|
package/docs/03_URL_settings.md
CHANGED
|
@@ -31,7 +31,7 @@ By default, picture is shown wide.
|
|
|
31
31
|
|
|
32
32
|
### :simple-speedtest: `speed`: sequence play speed
|
|
33
33
|
|
|
34
|
-
The duration of stay on a picture during sequence play (excluding image
|
|
34
|
+
The duration of stay on a picture during sequence play (excluding image downloading time), in milliseconds. Authorized values are between 0 and 3000. Example:
|
|
35
35
|
|
|
36
36
|
```urlencoded
|
|
37
37
|
speed=1000
|
package/docs/09_Develop.md
CHANGED
|
@@ -14,7 +14,7 @@ The current code is split between various elements:
|
|
|
14
14
|
|
|
15
15
|
- __Core components__: a single functional entry, like [Viewer](./reference/components/core/Viewer.md) (map + picture), [Photo Viewer](./reference/components/core/PhotoViewer.md) (picture only), [Coverage Map](./reference/components/core/CoverageMap.md) or [Editor](./reference/components/core/Editor.md). They share parts of code in [Basic](./reference/components/core/Basic.md) class. They specialized the behaviour of components depending on the needs.
|
|
16
16
|
- __UI components, menus & widgets__: reusable web components, like [Map](./reference/components/ui/Map.md), [Photo](./reference/components/ui/Photo.md) or [Loader](./reference/components/ui/Loader.md). They are used in some views depending of the context.
|
|
17
|
-
- __Utils__: utility functions,
|
|
17
|
+
- __Utils__: utility functions, split into various files for clarity.
|
|
18
18
|
|
|
19
19
|

|
|
20
20
|
|
|
@@ -54,6 +54,10 @@ This allows a flexible way to interact with viewer for users. Prioritization of
|
|
|
54
54
|
|
|
55
55
|
This means that, when developing, if you want to check if your attributes are well-defined, you may want to get rid of URL search parameters, as well as remove the `pnx-map-parameters` local storage item. Otherwise, they may not be read as they are lower priority than others.
|
|
56
56
|
|
|
57
|
+
### Third-party services URL
|
|
58
|
+
|
|
59
|
+
All third-party services URL (like geocoding API, OSM iD editor) are grouped into a dedicated `src/utils/services.js` file. You can easily change them to deploy a custom version of the viewer.
|
|
60
|
+
|
|
57
61
|
## Testing
|
|
58
62
|
|
|
59
63
|
We're trying to make Panoramax as reliable and secure as possible. To ensure this, we rely heavily on code testing. A variety of testing tools is made available:
|
|
@@ -114,7 +114,7 @@ Component properties. All of [Basic properties](Basic.md/#Panoramax.components.c
|
|
|
114
114
|
| [psv] | <code>object</code> | | [Any option to pass to Photo component](../ui/Photo.md/#Panoramax.components.ui.Photo) as an object.<br />Example: `psv="{'transitionDuration': 500, 'picturesNavigation': 'pic'}"` |
|
|
115
115
|
| [url-parameters] | <code>string</code> | <code>true</code> | Should the component add and update URL query parameters to save viewer state ? |
|
|
116
116
|
| [focus] | <code>string</code> | <code>"pic"</code> | The component showing up as main component (pic, map) |
|
|
117
|
-
| [geocoder] | <code>string</code> | <code>"nominatim"</code> | The geocoder engine to use (nominatim, ban) |
|
|
117
|
+
| [geocoder] | <code>string</code> | <code>"nominatim"</code> | The geocoder engine to use (nominatim, ban, or URL to a standard [GeocodeJSON-compliant](https://github.com/geocoders/geocodejson-spec/blob/master/draft/README.md) API) |
|
|
118
118
|
| [widgets] | <code>string</code> | <code>true</code> | Use default set of widgets ? Set to false to avoid any widget to show up, and use slots to populate as you like. |
|
|
119
119
|
| [picture] | <code>string</code> | | The picture ID to display |
|
|
120
120
|
| [sequence] | <code>string</code> | | The sequence ID of the picture displayed |
|
|
@@ -35,4 +35,5 @@ Component properties.
|
|
|
35
35
|
| [kind] | <code>string</code> | <code>"full"</code> | The style variation of the button (full, outline, flat, superflat, inline, superinline) |
|
|
36
36
|
| [size] | <code>string</code> | <code>"md"</code> | The size of the button (sm, md, l, xl, xxl) |
|
|
37
37
|
| [unstyled] | <code>boolean</code> | <code>false</code> | Disable all styling (for list group integration) |
|
|
38
|
+
| [title] | <code>string</code> | | Tooltip text displayed when hovering over the button |
|
|
38
39
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* [.getBackground()](#Panoramax.components.ui.Map+getBackground) ⇒ <code>string</code>
|
|
15
15
|
* [.setBackground(bg)](#Panoramax.components.ui.Map+setBackground)
|
|
16
16
|
* [.getVisibleUsers()](#Panoramax.components.ui.Map+getVisibleUsers) ⇒ <code>Array.<string></code>
|
|
17
|
+
* [.onceLayerReady(layerId)](#Panoramax.components.ui.Map+onceLayerReady) ⇒ <code>Promise</code>
|
|
17
18
|
* [.setVisibleUsers(visibleIds)](#Panoramax.components.ui.Map+setVisibleUsers)
|
|
18
19
|
* [.filterUserLayersContent(dataType, filter)](#Panoramax.components.ui.Map+filterUserLayersContent)
|
|
19
20
|
* [.displayPictureMarker(lon, lat, heading, [skipCenter])](#Panoramax.components.ui.Map+displayPictureMarker)
|
|
@@ -109,6 +110,18 @@ Get the currently visible users
|
|
|
109
110
|
|
|
110
111
|
**Kind**: instance method of [<code>Map</code>](#Panoramax.components.ui.Map)
|
|
111
112
|
**Returns**: <code>Array.<string></code> - List of visible users
|
|
113
|
+
<a name="Panoramax.components.ui.Map+onceLayerReady"></a>
|
|
114
|
+
|
|
115
|
+
### map.onceLayerReady(layerId) ⇒ <code>Promise</code>
|
|
116
|
+
Wait for a given map layer to be really available.
|
|
117
|
+
|
|
118
|
+
**Kind**: instance method of [<code>Map</code>](#Panoramax.components.ui.Map)
|
|
119
|
+
**Fulfil**: <code>null</code> When layer is ready.
|
|
120
|
+
|
|
121
|
+
| Param | Type | Description |
|
|
122
|
+
| --- | --- | --- |
|
|
123
|
+
| layerId | <code>string</code> | the layer ID |
|
|
124
|
+
|
|
112
125
|
<a name="Panoramax.components.ui.Map+setVisibleUsers"></a>
|
|
113
126
|
|
|
114
127
|
### map.setVisibleUsers(visibleIds)
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* [.getBackground()](Map.md/#Panoramax.components.ui.Map+getBackground) ⇒ <code>string</code>
|
|
15
15
|
* [.setBackground(bg)](Map.md/#Panoramax.components.ui.Map+setBackground)
|
|
16
16
|
* [.getVisibleUsers()](Map.md/#Panoramax.components.ui.Map+getVisibleUsers) ⇒ <code>Array.<string></code>
|
|
17
|
+
* [.onceLayerReady(layerId)](Map.md/#Panoramax.components.ui.Map+onceLayerReady) ⇒ <code>Promise</code>
|
|
17
18
|
* [.setVisibleUsers(visibleIds)](Map.md/#Panoramax.components.ui.Map+setVisibleUsers)
|
|
18
19
|
* [.filterUserLayersContent(dataType, filter)](Map.md/#Panoramax.components.ui.Map+filterUserLayersContent)
|
|
19
20
|
* [.displayPictureMarker(lon, lat, heading, [skipCenter])](#Panoramax.components.ui.Map+displayPictureMarker)
|
|
@@ -109,6 +110,18 @@ Get the currently visible users
|
|
|
109
110
|
|
|
110
111
|
**Kind**: instance method of [<code>MapMore</code>](#Panoramax.components.ui.MapMore)
|
|
111
112
|
**Returns**: <code>Array.<string></code> - List of visible users
|
|
113
|
+
<a name="Panoramax.components.ui.Map+onceLayerReady"></a>
|
|
114
|
+
|
|
115
|
+
### mapMore.onceLayerReady(layerId) ⇒ <code>Promise</code>
|
|
116
|
+
Wait for a given map layer to be really available.
|
|
117
|
+
|
|
118
|
+
**Kind**: instance method of [<code>MapMore</code>](#Panoramax.components.ui.MapMore)
|
|
119
|
+
**Fulfil**: <code>null</code> When layer is ready.
|
|
120
|
+
|
|
121
|
+
| Param | Type | Description |
|
|
122
|
+
| --- | --- | --- |
|
|
123
|
+
| layerId | <code>string</code> | the layer ID |
|
|
124
|
+
|
|
112
125
|
<a name="Panoramax.components.ui.Map+setVisibleUsers"></a>
|
|
113
126
|
|
|
114
127
|
### mapMore.setVisibleUsers(visibleIds)
|
|
@@ -289,7 +289,7 @@ Event for picture preview
|
|
|
289
289
|
| --- | --- | --- |
|
|
290
290
|
| detail.picId | <code>string</code> | The picture ID |
|
|
291
291
|
| detail.coordinates | <code>Array.<number></code> | [x,y] coordinates |
|
|
292
|
-
| detail.direction | <code>number</code> | The
|
|
292
|
+
| detail.direction | <code>number</code> | The theoretical picture orientation |
|
|
293
293
|
|
|
294
294
|
<a name="Panoramax.components.ui.Photo+event_picture-preview-stopped"></a>
|
|
295
295
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<a name="Panoramax.components.ui.widgets.CopyCoordinates"></a>
|
|
2
|
+
|
|
3
|
+
## Panoramax.components.ui.widgets.CopyCoordinates ⇐ <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
4
|
+
**Kind**: static class of <code>Panoramax.components.ui.widgets</code>
|
|
5
|
+
**Extends**: <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
6
|
+
**Element**: pnx-copy-coordinates
|
|
7
|
+
|
|
8
|
+
* [.CopyCoordinates](#Panoramax.components.ui.widgets.CopyCoordinates) ⇐ <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
9
|
+
* [new CopyCoordinates()](#new_Panoramax.components.ui.widgets.CopyCoordinates_new)
|
|
10
|
+
* [.properties](#Panoramax.components.ui.widgets.CopyCoordinates+properties) : <code>Object</code>
|
|
11
|
+
|
|
12
|
+
<a name="new_Panoramax.components.ui.widgets.CopyCoordinates_new"></a>
|
|
13
|
+
|
|
14
|
+
### new CopyCoordinates()
|
|
15
|
+
Copy Coordinates button allows easy copy of several format of map coordinates.
|
|
16
|
+
|
|
17
|
+
**Example**
|
|
18
|
+
```html
|
|
19
|
+
<pnx-copy-coordinates gps=${[-1.7, 48.6]} _parent=${viewer} />
|
|
20
|
+
```
|
|
21
|
+
<a name="Panoramax.components.ui.widgets.CopyCoordinates+properties"></a>
|
|
22
|
+
|
|
23
|
+
### copyCoordinates.properties : <code>Object</code>
|
|
24
|
+
Component properties.
|
|
25
|
+
|
|
26
|
+
**Kind**: instance property of [<code>CopyCoordinates</code>](#Panoramax.components.ui.widgets.CopyCoordinates)
|
|
27
|
+
**Properties**
|
|
28
|
+
|
|
29
|
+
| Name | Type | Description |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| gps | <code>Array.<number></code> | GPS/map coordinates, as [lon, lat] |
|
|
32
|
+
|
|
@@ -16,7 +16,11 @@ Ready-to-use geocoder search bar.
|
|
|
16
16
|
|
|
17
17
|
**Example**
|
|
18
18
|
```html
|
|
19
|
+
<!-- Default geocoder -->
|
|
19
20
|
<pnx-widget-geosearch _parent=${viewer} />
|
|
21
|
+
|
|
22
|
+
<!-- Custom-URL geocoder -->
|
|
23
|
+
<pnx-widget-geosearch geocoder="https://photon.komoot.io/api" _parent=${viewer} />
|
|
20
24
|
```
|
|
21
25
|
<a name="Panoramax.components.ui.widgets.GeoSearch+properties"></a>
|
|
22
26
|
|
|
@@ -28,5 +32,5 @@ Component properties.
|
|
|
28
32
|
|
|
29
33
|
| Name | Type | Default | Description |
|
|
30
34
|
| --- | --- | --- | --- |
|
|
31
|
-
| [geocoder] | <code>string</code> | <code>"nominatim"</code> | The geocoder engine to use (nominatim, ban) |
|
|
35
|
+
| [geocoder] | <code>string</code> | <code>"nominatim"</code> | The geocoder engine to use (nominatim, ban, or URL to a standard [GeocodeJSON-compliant](https://github.com/geocoders/geocodejson-spec/blob/master/draft/README.md) API) |
|
|
32
36
|
|
|
@@ -39,7 +39,7 @@ API contains various utility functions to communicate with Panoramax/STAC API
|
|
|
39
39
|
|
|
40
40
|
| Param | Type | Default | Description |
|
|
41
41
|
| --- | --- | --- | --- |
|
|
42
|
-
| endpoint | <code>string</code> | | The endpoint. It corresponds to the <a href="https://github.com/radiantearth/stac-api-spec/blob/main/overview.md#example-landing-page">STAC landing page</a>, with all links describing the API
|
|
42
|
+
| endpoint | <code>string</code> | | The endpoint. It corresponds to the <a href="https://github.com/radiantearth/stac-api-spec/blob/main/overview.md#example-landing-page">STAC landing page</a>, with all links describing the API capabilities. |
|
|
43
43
|
| [options] | <code>object</code> | | Options |
|
|
44
44
|
| [options.style] | <code>string</code> \| <code>object</code> | | General map style |
|
|
45
45
|
| [options.tiles] | <code>string</code> | | API route serving pictures & sequences vector tiles |
|
package/docs/reference.md
CHANGED
|
@@ -61,6 +61,7 @@ Basic UI components:
|
|
|
61
61
|
|
|
62
62
|
More complex UI components (but not menus):
|
|
63
63
|
|
|
64
|
+
- [CopyCoordinates](./reference/components/ui/widgets/CopyCoordinates.md) : a copy-to-clipboard button for coordinates, with many format options.
|
|
64
65
|
- [GeoSearch](./reference/components/ui/widgets/GeoSearch.md) : a geocoder search bar with GPS location tool.
|
|
65
66
|
- [Legend](./reference/components/ui/widgets/Legend.md) : a togglable map/picture legend.
|
|
66
67
|
- [MapFiltersButton](./reference/components/ui/widgets/MapFiltersButton.md) : a togglable map filters button & menu.
|
|
@@ -68,7 +68,7 @@ Many stuff was moved around, and have a bit different naming. Main classes shoul
|
|
|
68
68
|
|
|
69
69
|
A new main component is available, named __Photo Viewer__ (`<pnx-photo-viewer>`) for showing up only picture (without map).
|
|
70
70
|
|
|
71
|
-
And source code is
|
|
71
|
+
And source code is split into more packages:
|
|
72
72
|
|
|
73
73
|
* `Panoramax.components` : everything you can see graphically
|
|
74
74
|
* `.core` : Viewer, Editor, Coverage Map and Basic (common code)
|
|
@@ -32,7 +32,7 @@ coverage.addEventListener("ready", () => {
|
|
|
32
32
|
console.log("Selected sequence", e.detail.seqId, "picture", e.detail.picId);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
// You can also
|
|
35
|
+
// You can also programmatically change selection on map
|
|
36
36
|
coverage.select(
|
|
37
37
|
"c463d190-06b0-47fb-98a8-b4a775a39ad6", // A sequence ID
|
|
38
38
|
"bdea1eb4-4496-46da-a4d5-b22b16e75fa8" // A picture ID (can be null if unknown)
|
package/mkdocs.yml
CHANGED
|
@@ -77,6 +77,7 @@ nav:
|
|
|
77
77
|
- ShareMenu: 'reference/components/menus/ShareMenu.md'
|
|
78
78
|
- ui:
|
|
79
79
|
- widgets:
|
|
80
|
+
- CopyCoordinates: 'reference/components/ui/widgets/CopyCoordinates.md'
|
|
80
81
|
- GeoSearch: 'reference/components/ui/widgets/GeoSearch.md'
|
|
81
82
|
- Legend: 'reference/components/ui/widgets/Legend.md'
|
|
82
83
|
- MapFiltersButton: 'reference/components/ui/widgets/MapFiltersButton.md'
|
package/package.json
CHANGED
|
@@ -108,8 +108,8 @@ export default class CoverageMap extends Basic {
|
|
|
108
108
|
this.map.on("picture-click", e => this.select(e.seqId, e.picId));
|
|
109
109
|
this.map.on("sequence-click", e => this.select(e.seqId));
|
|
110
110
|
|
|
111
|
-
this.map.waitForEnoughMapLoaded().then(() => {
|
|
112
|
-
alterMapState(this.map, this._initParams.getMapPostInit());
|
|
111
|
+
this.map.waitForEnoughMapLoaded().then(async () => {
|
|
112
|
+
await alterMapState(this.map, this._initParams.getMapPostInit());
|
|
113
113
|
this.map.reloadLayersStyles();
|
|
114
114
|
this.loader.dismiss();
|
|
115
115
|
});
|
|
@@ -323,7 +323,11 @@ export default class PhotoViewer extends Basic {
|
|
|
323
323
|
for(let cn of this.grid.childNodes) {
|
|
324
324
|
if(cn.getAttribute("slot") !== "bg") {
|
|
325
325
|
cn.addEventListener("focusin", () => keytonone());
|
|
326
|
-
cn.addEventListener("focusout", () =>
|
|
326
|
+
cn.addEventListener("focusout", () => {
|
|
327
|
+
if(this.popup.getAttribute("visible") === null) {
|
|
328
|
+
keytopsv();
|
|
329
|
+
}
|
|
330
|
+
});
|
|
327
331
|
}
|
|
328
332
|
}
|
|
329
333
|
}
|
|
@@ -95,7 +95,7 @@ export default class Viewer extends PhotoViewer {
|
|
|
95
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
96
|
* @property {string} [url-parameters=true] Should the component add and update URL query parameters to save viewer state ?
|
|
97
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)
|
|
98
|
+
* @property {string} [geocoder=nominatim] The geocoder engine to use (nominatim, ban, or URL to a standard [GeocodeJSON-compliant](https://github.com/geocoders/geocodejson-spec/blob/master/draft/README.md) API)
|
|
99
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
100
|
* @property {string} [picture] The picture ID to display
|
|
101
101
|
* @property {string} [sequence] The sequence ID of the picture displayed
|
|
@@ -294,7 +294,7 @@ export default class Viewer extends PhotoViewer {
|
|
|
294
294
|
});
|
|
295
295
|
});
|
|
296
296
|
|
|
297
|
-
alterMapState(this.map, this._initParams.getMapPostInit());
|
|
297
|
+
await alterMapState(this.map, this._initParams.getMapPostInit());
|
|
298
298
|
initMapKeyboardHandler(this);
|
|
299
299
|
linkMapAndPhoto(this);
|
|
300
300
|
}
|
|
@@ -336,11 +336,11 @@ export default class Viewer extends PhotoViewer {
|
|
|
336
336
|
};
|
|
337
337
|
const keytopsv = () => {
|
|
338
338
|
this.psv.startKeyboardControl();
|
|
339
|
-
this.map
|
|
339
|
+
this.map.keyboard.disable();
|
|
340
340
|
};
|
|
341
341
|
const keytonone = () => {
|
|
342
342
|
this.psv.stopKeyboardControl();
|
|
343
|
-
this.map
|
|
343
|
+
this.map.keyboard.disable();
|
|
344
344
|
};
|
|
345
345
|
const keytofocused = () => {
|
|
346
346
|
if(this.map && this.isMapWide()) { keytomap(); }
|
|
@@ -350,6 +350,7 @@ export default class Viewer extends PhotoViewer {
|
|
|
350
350
|
// General focus change
|
|
351
351
|
this.addEventListener("focus-changed", e => {
|
|
352
352
|
if(e.detail.focus === "map") { keytomap(); }
|
|
353
|
+
if(this.popup.getAttribute("visible")) { keytonone(); }
|
|
353
354
|
else { keytopsv(); }
|
|
354
355
|
});
|
|
355
356
|
|
|
@@ -361,7 +362,11 @@ export default class Viewer extends PhotoViewer {
|
|
|
361
362
|
for(let cn of this.grid.childNodes) {
|
|
362
363
|
if(cn.getAttribute("slot") !== "bg") {
|
|
363
364
|
cn.addEventListener("focusin", () => keytonone());
|
|
364
|
-
cn.addEventListener("focusout", () =>
|
|
365
|
+
cn.addEventListener("focusout", () => {
|
|
366
|
+
if(this.popup.getAttribute("visible") === null) {
|
|
367
|
+
keytofocused();
|
|
368
|
+
}
|
|
369
|
+
});
|
|
365
370
|
}
|
|
366
371
|
}
|
|
367
372
|
}
|
|
@@ -145,6 +145,9 @@ export default class PictureLegend extends LitElement {
|
|
|
145
145
|
this._parent.psv.addEventListener("picture-loaded", () => {
|
|
146
146
|
this._onPicChange(this._parent.psv.getPictureMetadata());
|
|
147
147
|
});
|
|
148
|
+
this._parent.psv.addEventListener("sequence-stopped", () => {
|
|
149
|
+
this._onPicChange(this._parent.psv.getPictureMetadata());
|
|
150
|
+
});
|
|
148
151
|
});
|
|
149
152
|
}
|
|
150
153
|
|
|
@@ -154,12 +157,12 @@ export default class PictureLegend extends LitElement {
|
|
|
154
157
|
this._caption = picMeta?.caption;
|
|
155
158
|
|
|
156
159
|
if(picMeta) {
|
|
157
|
-
const coordsHash = `${picMeta.gps[0]}/${picMeta.gps[1]}`;
|
|
160
|
+
const coordsHash = `${picMeta.gps[0].toFixed(4)}/${picMeta.gps[1].toFixed(4)}`;
|
|
158
161
|
if(this._prevSearches[coordsHash]) {
|
|
159
162
|
this._addr = this._prevSearches[coordsHash];
|
|
160
163
|
}
|
|
161
|
-
else {
|
|
162
|
-
this.
|
|
164
|
+
else if(!this._parent.psv._sequencePlaying) {
|
|
165
|
+
this._addr = "";
|
|
163
166
|
this._addrTimer1 = setTimeout(() => {
|
|
164
167
|
reverseGeocodingNominatim(picMeta.gps[1], picMeta.gps[0])
|
|
165
168
|
.then(addr => {
|
|
@@ -167,7 +170,7 @@ export default class PictureLegend extends LitElement {
|
|
|
167
170
|
this._addr = addr;
|
|
168
171
|
this._prevSearches[coordsHash] = addr;
|
|
169
172
|
});
|
|
170
|
-
},
|
|
173
|
+
}, 500);
|
|
171
174
|
}
|
|
172
175
|
}
|
|
173
176
|
else {
|
|
@@ -146,8 +146,18 @@ export default class PictureMetadata extends LitElement {
|
|
|
146
146
|
// Location tab
|
|
147
147
|
const orientation = this._meta?.properties?.["view:azimuth"] !== undefined && `${this._meta.properties["view:azimuth"]}°`;
|
|
148
148
|
const locationData = [
|
|
149
|
-
{
|
|
150
|
-
|
|
149
|
+
{
|
|
150
|
+
title: this._parent?._t.pnx.metadata_location_coordinates,
|
|
151
|
+
content: html`
|
|
152
|
+
${this._meta.gps[0]}, ${this._meta.gps[1]}
|
|
153
|
+
<pnx-copy-coordinates
|
|
154
|
+
._parent=${this._parent}
|
|
155
|
+
.gps=${this._meta.gps}
|
|
156
|
+
style="margin-left: 10px"
|
|
157
|
+
></pnx-copy-coordinates>
|
|
158
|
+
`,
|
|
159
|
+
style: "width: 100%"
|
|
160
|
+
},
|
|
151
161
|
{ title: this._parent?._t.pnx.metadata_location_orientation, content: orientation || missing() },
|
|
152
162
|
{ title: this._parent?._t.pnx.metadata_location_precision, content: getGPSPrecision(this._meta) || missing() },
|
|
153
163
|
];
|
|
@@ -211,6 +221,17 @@ export default class PictureMetadata extends LitElement {
|
|
|
211
221
|
style: value.length > 30 ? "width: 100%" : undefined
|
|
212
222
|
};
|
|
213
223
|
});
|
|
224
|
+
exifData.unshift({
|
|
225
|
+
content: html`
|
|
226
|
+
<pnx-link-button
|
|
227
|
+
size="sm"
|
|
228
|
+
target="_blank"
|
|
229
|
+
href="https://exiv2.org/metadata.html"
|
|
230
|
+
title=${this._parent?._t.pnx.metadata_exif_doc_title}
|
|
231
|
+
>${fa(faInfoCircle)} ${this._parent?._t.pnx.metadata_exif_doc}</pnx-link-button>
|
|
232
|
+
`,
|
|
233
|
+
style: "width: 100%"
|
|
234
|
+
});
|
|
214
235
|
|
|
215
236
|
// General metadata
|
|
216
237
|
const overview = [
|
package/src/components/styles.js
CHANGED
|
@@ -274,6 +274,67 @@ export const btn = css`
|
|
|
274
274
|
}
|
|
275
275
|
`;
|
|
276
276
|
|
|
277
|
+
// Button group
|
|
278
|
+
export const btngroup = css`
|
|
279
|
+
pnx-button-group > pnx-button {
|
|
280
|
+
display: inline-flex;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
pnx-button-group > pnx-button::part(btn) {
|
|
284
|
+
height: unset;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Togglable in group */
|
|
288
|
+
pnx-button-group > pnx-togglable-group > pnx-button {
|
|
289
|
+
width: 100%;
|
|
290
|
+
height: 100%;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/* Row */
|
|
294
|
+
pnx-button-group[dir="row"] > :not(:first-child):not(:last-child)::part(btn),
|
|
295
|
+
pnx-button-group[dir="row"] > :not(:first-child):not(:last-child) > ::part(btn) {
|
|
296
|
+
border-radius: 0;
|
|
297
|
+
border-left: none;
|
|
298
|
+
border-right: none;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
pnx-button-group[dir="row"] > :first-child::part(btn),
|
|
302
|
+
pnx-button-group[dir="row"] > :first-child > ::part(btn) {
|
|
303
|
+
border-top-right-radius: 0;
|
|
304
|
+
border-bottom-right-radius: 0;
|
|
305
|
+
border-right: none;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
pnx-button-group[dir="row"] > :last-child::part(btn),
|
|
309
|
+
pnx-button-group[dir="row"] > :last-child > ::part(btn) {
|
|
310
|
+
border-top-left-radius: 0;
|
|
311
|
+
border-bottom-left-radius: 0;
|
|
312
|
+
border-left: none;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/* Column */
|
|
316
|
+
pnx-button-group[dir="column"] > :not(:first-child):not(:last-child)::part(btn),
|
|
317
|
+
pnx-button-group[dir="column"] > :not(:first-child):not(:last-child) > ::part(btn) {
|
|
318
|
+
border-radius: 0;
|
|
319
|
+
border-top: none;
|
|
320
|
+
border-bottom: none;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
pnx-button-group[dir="column"] > :first-child::part(btn),
|
|
324
|
+
pnx-button-group[dir="column"] > :first-child > ::part(btn) {
|
|
325
|
+
border-bottom-right-radius: 0;
|
|
326
|
+
border-bottom-left-radius: 0;
|
|
327
|
+
border-bottom: none;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
pnx-button-group[dir="column"] > :last-child::part(btn),
|
|
331
|
+
pnx-button-group[dir="column"] > :last-child > ::part(btn) {
|
|
332
|
+
border-top-left-radius: 0;
|
|
333
|
+
border-top-right-radius: 0;
|
|
334
|
+
border-top: none;
|
|
335
|
+
}
|
|
336
|
+
`;
|
|
337
|
+
|
|
277
338
|
// Titles
|
|
278
339
|
export const titles = css`
|
|
279
340
|
h1, h2, h3, h4, h5, h6 {
|
|
@@ -41,6 +41,7 @@ export default class CopyButton extends LitElement {
|
|
|
41
41
|
* @property {string} [kind=full] The style variation of the button (full, outline, flat, superflat, inline, superinline)
|
|
42
42
|
* @property {string} [size=md] The size of the button (sm, md, l, xl, xxl)
|
|
43
43
|
* @property {boolean} [unstyled=false] Disable all styling (for list group integration)
|
|
44
|
+
* @property {string} [title] Tooltip text displayed when hovering over the button
|
|
44
45
|
*/
|
|
45
46
|
static properties = {
|
|
46
47
|
text: {type: String},
|
|
@@ -48,6 +49,7 @@ export default class CopyButton extends LitElement {
|
|
|
48
49
|
kind: {type: String},
|
|
49
50
|
size: {type: String},
|
|
50
51
|
unstyled: {type: Boolean},
|
|
52
|
+
title: { type: String },
|
|
51
53
|
_active: {state: true, type: Boolean},
|
|
52
54
|
};
|
|
53
55
|
|
|
@@ -94,7 +96,7 @@ export default class CopyButton extends LitElement {
|
|
|
94
96
|
[`pnx-btn-${this.kind}`]: !this.unstyled,
|
|
95
97
|
[`pnx-btn-${this.size}`]: !this.unstyled,
|
|
96
98
|
};
|
|
97
|
-
return html`<button class=${classMap(classes)} part="btn">
|
|
99
|
+
return html`<button title=${this.title} class=${classMap(classes)} part="btn">
|
|
98
100
|
${this._active ?
|
|
99
101
|
html`${this._t?.pnx.copied || ""} ${fa(faCheck)}` :
|
|
100
102
|
html`<slot>${fa(faCopy)} ${this._t?.pnx.copy || ""}</slot>`
|
package/src/components/ui/Map.js
CHANGED
|
@@ -326,10 +326,29 @@ export default class Map extends maplibregl.Map {
|
|
|
326
326
|
*/
|
|
327
327
|
getVisibleUsers() {
|
|
328
328
|
return [...this._userLayers].filter(l => (
|
|
329
|
-
this.
|
|
329
|
+
this.getLayer(getUserLayerId(l, "pictures"))
|
|
330
|
+
&& this.getLayoutProperty(getUserLayerId(l, "pictures"), "visibility") === "visible"
|
|
330
331
|
));
|
|
331
332
|
}
|
|
332
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Wait for a given map layer to be really available.
|
|
336
|
+
* @param {string} layerId the layer ID
|
|
337
|
+
* @returns {Promise}
|
|
338
|
+
* @fulfil {null} When layer is ready.
|
|
339
|
+
* @memberof Panoramax.components.ui.Map#
|
|
340
|
+
*/
|
|
341
|
+
onceLayerReady(layerId) {
|
|
342
|
+
if(this.getLayer(layerId)) {
|
|
343
|
+
return Promise.resolve();
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
return new Promise(resolve => {
|
|
347
|
+
setTimeout(resolve, 250);
|
|
348
|
+
}).then(() => this.onceLayerReady(layerId));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
333
352
|
/**
|
|
334
353
|
* Make given user layers visible on map, and hide all others (if any)
|
|
335
354
|
* @memberof Panoramax.components.ui.Map#
|
|
@@ -343,7 +362,10 @@ export default class Map extends maplibregl.Map {
|
|
|
343
362
|
await Promise.all(
|
|
344
363
|
visibleIds
|
|
345
364
|
.filter(id => id != "" && !this._userLayers.has(id))
|
|
346
|
-
.map(id =>
|
|
365
|
+
.map(id => {
|
|
366
|
+
this._createPicturesTilesLayer(id);
|
|
367
|
+
return this.onceLayerReady(getUserLayerId(id, "pictures"));
|
|
368
|
+
})
|
|
347
369
|
);
|
|
348
370
|
|
|
349
371
|
// Switch visibility
|
|
@@ -375,6 +397,10 @@ export default class Map extends maplibregl.Map {
|
|
|
375
397
|
*/
|
|
376
398
|
filterUserLayersContent(dataType, filter) {
|
|
377
399
|
[...this._userLayers].forEach(l => {
|
|
400
|
+
if(!this.getLayer(getUserLayerId(l, dataType))) {
|
|
401
|
+
console.warn("Layer", getUserLayerId(l, dataType), "not ready");
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
378
404
|
this.setFilter(getUserLayerId(l, dataType), filter);
|
|
379
405
|
if(dataType === "sequences" && this.getLayer(getUserLayerId(l, "sequences_plus"))) {
|
|
380
406
|
this.setFilter(getUserLayerId(l, "sequences_plus"), filter);
|
|
@@ -428,11 +454,16 @@ export default class Map extends maplibregl.Map {
|
|
|
428
454
|
reloadLayersStyles() {
|
|
429
455
|
const updateStyle = (layer, style) => {
|
|
430
456
|
[...this._userLayers].forEach(l => {
|
|
457
|
+
const layerId = getUserLayerId(l, layer);
|
|
458
|
+
if(!this.getLayer(layerId)) {
|
|
459
|
+
console.warn("Layer", layerId, "not ready");
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
431
462
|
for(let p in style.layout) {
|
|
432
|
-
this.setLayoutProperty(
|
|
463
|
+
this.setLayoutProperty(layerId, p, style.layout[p]);
|
|
433
464
|
}
|
|
434
465
|
for(let p in style.paint) {
|
|
435
|
-
this.setPaintProperty(
|
|
466
|
+
this.setPaintProperty(layerId, p, style.paint[p]);
|
|
436
467
|
}
|
|
437
468
|
});
|
|
438
469
|
};
|
|
@@ -266,7 +266,9 @@ export default class Photo extends PSViewer {
|
|
|
266
266
|
}
|
|
267
267
|
// Different sequence -> Point to center + no animation
|
|
268
268
|
else {
|
|
269
|
-
nodeTransition = forwardNoAnim
|
|
269
|
+
nodeTransition = Object.assign(forwardNoAnim, {
|
|
270
|
+
rotateTo: { pitch: 0, yaw: 0 },
|
|
271
|
+
});
|
|
270
272
|
}
|
|
271
273
|
}
|
|
272
274
|
|
|
@@ -338,7 +340,7 @@ export default class Photo extends PSViewer {
|
|
|
338
340
|
* @type {CustomEvent}
|
|
339
341
|
* @property {string} detail.picId The picture ID
|
|
340
342
|
* @property {number[]} detail.coordinates [x,y] coordinates
|
|
341
|
-
* @property {number} detail.direction The
|
|
343
|
+
* @property {number} detail.direction The theoretical picture orientation
|
|
342
344
|
*/
|
|
343
345
|
const event = new CustomEvent("picture-preview-started", { detail: {
|
|
344
346
|
picId: fromLink.nodeId,
|
|
@@ -145,7 +145,7 @@ export default class TogglableGroup extends LitElement {
|
|
|
145
145
|
"pnx-padded": this.padded !== "false",
|
|
146
146
|
};
|
|
147
147
|
|
|
148
|
-
return html`<div class="container">
|
|
148
|
+
return html`<div class="container" @click=${e => e.stopPropagation()}>
|
|
149
149
|
<slot name="button" @slotchange=${this.handleButtonSlotChange}></slot>
|
|
150
150
|
<div class=${classMap(panelClasses)} part="menu">
|
|
151
151
|
<slot></slot>
|