Skip to content

Commit 97cd932

Browse files
authored
feat(Panoramax): ajout de la fonctionnalité de partage d'URL pour le viewer (#581)
1 parent f2efa61 commit 97cd932

9 files changed

Lines changed: 316 additions & 98 deletions

File tree

DRAFT_CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ __DATE__
1515

1616
*[Added]
1717

18+
- Panoramax : Ajout de la fonctionnalité de partage d'URL pour le visualiseur d'images (#581)
19+
1820
* 🔨 [Changed]
1921

2022
- Tooltips : les tooltips au survol des boutons ne peuvent pas être survolées (#571)

doc/DOCUMENTATION.md

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,80 @@
2121
- [Navigateurs supportés](#navigateurs-supportés)
2222
- [Fonctionnalités](#fonctionnalités)
2323
- [Systèmes de coordonnées](#systèmes-de-coordonnées)
24-
- [Affichage des couches WMTS Géoplateforme](#WMTS)
25-
- [Affichage des couches WMS Géoplateforme](#WMS)
26-
- [Affichage d'une couche Vecteur Tuilé Géoplateforme](#VT)
27-
- [Affichage dynamique des attributions](#attributions)
28-
- [Widget de gestion d'empilement des couches](#layerswitcher)
29-
- [Barre de recherche utilisant le service de géocodage IGN](#geocode)
30-
- [Obtention d'une adresse, d'un nom de lieu, ... au clic sur la carte](#reverse)
31-
- [Calculs d'itinéraires à partir du service de la Géoplateforme](#route)
32-
- [Calculs d'isochrones / isodistances à partir du service de la Géoplateforme](#isocurve)
33-
- [Coordonnées et altitude en un point de la carte à l'aide du service d'altimétrie de la Géoplateforme](#mp)
34-
- [Outils de croquis](#drawing)
35-
- [Import de couches](#layerimport)
36-
- [Profil altimétrique d'un traçé à l'aide du service d'altimétrie de la Géoplateforme](#ep)
37-
- [Outils de mesures](#measure)
38-
- [Accès aux informations attributaires des couches](#getfeatureinfo)
39-
- [Widget d'export](#export)
40-
- [Widget de catalogue de couche](#catalog)
41-
- [Widget de legendes](#legends)
42-
- [Widget de centrage sur territoire](#territories)
43-
- [Widget de mini carte](#overviewMap)
44-
- [Widget de zoom](#zoom)
45-
- [Widget de plein écran](#fullscreen)
24+
- [Affichage des couches WMTS Géoplateforme](#affichage-des-couches-wmts-géoplateforme)
25+
- [Utilisation d'un layer WMTS Géoplateforme](#utilisation-dun-layer-wmts-géoplateforme)
26+
- [Exemple d'utilisation](#exemple-dutilisation)
27+
- [Affichage en Lambert 93 (EPSG:2154)](#affichage-en-lambert-93-epsg2154)
28+
- [Utilisation d'une source WMTS Géoplateforme](#utilisation-dune-source-wmts-géoplateforme)
29+
- [Exemple d'utilisation](#exemple-dutilisation-1)
30+
- [Affichage en Lambert 93 (EPSG:2154)](#affichage-en-lambert-93-epsg2154-1)
31+
- [Affichage des couches WMS Géoplateforme](#affichage-des-couches-wms-géoplateforme)
32+
- [Utilisation d'un layer WMS Géoplateforme](#utilisation-dun-layer-wms-géoplateforme)
33+
- [Exemple d'utilisation](#exemple-dutilisation-2)
34+
- [Utilisation d'une source WMS Géoplateforme](#utilisation-dune-source-wms-géoplateforme)
35+
- [Exemple d'utilisation](#exemple-dutilisation-3)
36+
- [Affichage d'une couche Vecteur Tuilé Géoplateforme](#affichage-dune-couche-vecteur-tuilé-géoplateforme)
37+
- [Widget de gestion d'empilement des couches](#widget-de-gestion-dempilement-des-couches)
38+
- [Exemples d'utilisation](#exemples-dutilisation)
39+
- [Utilisation simple](#utilisation-simple)
40+
- [Barre de recherche](#barre-de-recherche)
41+
- [Exemples d'utilisation](#exemples-dutilisation-1)
42+
- [Utilisation simple](#utilisation-simple-1)
43+
- [Calculs d'itinéraires](#calculs-ditinéraires)
44+
- [Exemples d'utilisation](#exemples-dutilisation-2)
45+
- [Utilisation simple](#utilisation-simple-2)
46+
- [Calculs d'isochrones / isodistances](#calculs-disochrones--isodistances)
47+
- [Exemples d'utilisation](#exemples-dutilisation-3)
48+
- [Utilisation simple](#utilisation-simple-3)
49+
- [Coordonnées et altitude en un point de la carte](#coordonnées-et-altitude-en-un-point-de-la-carte)
50+
- [Exemples d'utilisation](#exemples-dutilisation-4)
51+
- [Utilisation simple](#utilisation-simple-4)
52+
- [Affichage dynamique des attributions](#affichage-dynamique-des-attributions)
53+
- [Exemples d'utilisation](#exemples-dutilisation-5)
54+
- [Utilisation simple](#utilisation-simple-5)
55+
- [Adresse ou lieu en un point de la carte](#adresse-ou-lieu-en-un-point-de-la-carte)
56+
- [Exemples d'utilisation](#exemples-dutilisation-6)
57+
- [Utilisation simple](#utilisation-simple-6)
58+
- [Outils de croquis](#outils-de-croquis)
59+
- [Exemples d'utilisation](#exemples-dutilisation-7)
60+
- [Utilisation simple](#utilisation-simple-7)
61+
- [Widget d'import de couches](#widget-dimport-de-couches)
62+
- [Exemples d'utilisation](#exemples-dutilisation-8)
63+
- [Utilisation simple](#utilisation-simple-8)
64+
- [Profil altimétrique le long d'un traçé](#profil-altimétrique-le-long-dun-traçé)
65+
- [Exemples d'utilisation](#exemples-dutilisation-9)
66+
- [Utilisation simple](#utilisation-simple-9)
67+
- [Outils de mesures](#outils-de-mesures)
68+
- [Exemples d'utilisation](#exemples-dutilisation-10)
69+
- [Utilisation simple](#utilisation-simple-10)
70+
- [Accès aux informations attributaires des couches](#accès-aux-informations-attributaires-des-couches)
71+
- [Exemples d'utilisation](#exemples-dutilisation-11)
72+
- [Utilisation simple pour une seule couche](#utilisation-simple-pour-une-seule-couche)
73+
- [Widget d'export](#widget-dexport)
74+
- [Exemples d'utilisation](#exemples-dutilisation-12)
75+
- [Utilisation via les setters](#utilisation-via-les-setters)
76+
- [Utilisation via les options](#utilisation-via-les-options)
77+
- [Utilisation directement dans le contrôle associé](#utilisation-directement-dans-le-contrôle-associé)
78+
- [widget de catalogue de couche](#widget-de-catalogue-de-couche)
79+
- [Les options](#les-options)
80+
- [Les évenements](#les-évenements)
81+
- [Exemples d'utilisation](#exemples-dutilisation-13)
82+
- [Constituer le fichier de configuration des couches](#constituer-le-fichier-de-configuration-des-couches)
83+
- [Spécification du ficher de configuration](#spécification-du-ficher-de-configuration)
84+
- [Widget des légendes](#widget-des-légendes)
85+
- [Les événements](#les-événements)
86+
- [Comment obtenir la légende d'une couche ?](#comment-obtenir-la-légende-dune-couche-)
87+
- [Exemples d'utilisation](#exemples-dutilisation-14)
88+
- [Widget de centrage sur territoires](#widget-de-centrage-sur-territoires)
89+
- [Exemples d'utilisation](#exemples-dutilisation-15)
90+
- [Widget de mini carte](#widget-de-mini-carte)
91+
- [Exemples d'utilisation](#exemples-dutilisation-16)
92+
- [Widget de zoom](#widget-de-zoom)
93+
- [Exemples d'utilisation](#exemples-dutilisation-17)
94+
- [Widget de plein écran](#widget-de-plein-écran)
95+
- [Exemples d'utilisation](#exemples-dutilisation-18)
96+
- [Widget Panoramax](#widget-panoramax)
97+
- [Exemples d'utilisation](#exemples-dutilisation-19)
4698

4799
Les fonctionnalités proposées par l'extension Géoplateforme pour OpenLayers sont à utiliser en complément de la bibliothèque [OpenLayers dans ses versions 8 et
48100
supérieures](https://openlayers.org/)
@@ -2103,3 +2155,36 @@ map.addControl(fullscreen);
21032155
```
21042156
21052157
<p align="right">(<a href="#readme-top">back to top</a>)</p>
2158+
2159+
<a id="panoramax"></a>
2160+
2161+
### Widget Panoramax
2162+
2163+
Ce widget affiche les couvertures Panoramax sur la carte et permet de visualiser les photos associées. Il repose sur le web component `<pnx-photo-viewer>` de `@panoramax/web-viewer`, qui doit être chargé avec sa feuille de style avant l'extension.
2164+
2165+
#### Exemples d'utilisation
2166+
2167+
```html
2168+
<link rel="stylesheet" href="photoviewer.css" />
2169+
<script src="photoviewer.js"></script>
2170+
```
2171+
2172+
```js
2173+
var panoramax = new ol.control.Panoramax({
2174+
position: "bottom-left",
2175+
visualizationWindow: {
2176+
size: "fullscreen-map"
2177+
},
2178+
viewer: {
2179+
share: {
2180+
url: "https://cartes.gouv.fr/explorer-les-cartes/",
2181+
type: "geoplateforme"
2182+
}
2183+
}
2184+
});
2185+
map.addControl(panoramax);
2186+
```
2187+
2188+
La configuration des couches, interactions, filtres, modes de fenêtre, événements et liens de partage est décrite dans la [note du widget Panoramax](NOTE-PANORAMAX.md).
2189+
2190+
<p align="right">(<a href="#readme-top">back to top</a>)</p>

doc/NOTE-PANORAMAX.md

Lines changed: 91 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,118 @@
11
# Fonctionnement du widget **Panoramax**
22

3-
---
3+
## Architecture et cycle de vie
4+
5+
`ol.control.Panoramax` étend `ol.control.Control`. Son implémentation se trouve dans `src/packages/Controls/Panoramax/` :
6+
7+
- `Panoramax.js` pilote les couches OpenLayers, le viewer et les interactions ;
8+
- `PanoramaxDOM.js` construit les panneaux et boutons ;
9+
- `PictureLegendWidget.js` fournit la légende, le géocodage inverse et le lien de partage ;
10+
- `PnxMiniMapWidget.js` ajoute une mini-carte au viewer.
11+
12+
À la construction, le contrôle initialise ses options et son DOM. Lors de l'ouverture, il charge le groupe de couches Panoramax, le fond optionnel, le panneau d'options, la fenêtre de visualisation et le composant `<pnx-photo-viewer>`. Le viewer est créé une seule fois par instance ; son cycle de vie est nettoyé lors d'un retrait de la carte afin de permettre un `map.removeControl()` suivi d'un `map.addControl()`.
13+
14+
`collapsed: false` ouvre le contrôle dès son attachement. Avec `auto: true` (valeur par défaut), les écouteurs de clic et de survol sont ajoutés automatiquement à la carte.
15+
16+
## Configuration utile
17+
18+
```js
19+
var panoramax = new ol.control.Panoramax({
20+
collapsed: true,
21+
auto: true,
22+
hover: true,
23+
position: "bottom-left",
24+
layer: {
25+
url: "https://api.panoramax.xyz/api/map/style.json",
26+
name: "Panoramax"
27+
},
28+
background: {
29+
active: false
30+
},
31+
buttonsWindow: {
32+
filters: {
33+
display: true,
34+
exclusive: false,
35+
content: { types: true, dates: true, periodes: true }
36+
}
37+
},
38+
visualizationWindow: {
39+
size: "fullscreen-map"
40+
},
41+
viewer: {
42+
endpoint: "https://explore.panoramax.fr/api",
43+
share: {
44+
url: "https://cartes.gouv.fr/explorer-les-cartes/",
45+
type: "geoplateforme"
46+
},
47+
pnxOptions: {
48+
psvOptions: {}
49+
}
50+
}
51+
});
52+
53+
map.addControl(panoramax);
54+
```
455

5-
## Architecture générale
56+
Les cibles expérimentales `buttonsWindow.target` et `visualizationWindow.target` acceptent un `HTMLElement`, un identifiant ou un sélecteur CSS. L'option `viewer.pnxOptions.psvOptions` est affectée à la propriété `psv-options` du web component ; ne pas la transmettre avec `setAttribute`.
657

7-
Le widget est une classe `Panoramax extends Control` (OpenLayers) composée de
8-
deux fichiers :
58+
## Interactions avec la carte
959

10-
- Panoramax.js — logique principale (~2800 lignes)
11-
- PanoramaxDOM.js — génération du DOM
60+
| Couche | Comportement par défaut au clic |
61+
|---|---|
62+
| `grid` | Zoom sur la position sélectionnée |
63+
| `sequences` | Zoom ou recentrage vers le niveau 17 |
64+
| `pictures` | Ouvre l'image dans le viewer |
1265

13-
---
66+
Les interactions se configurent avec `interactions.grid`, `interactions.sequences` et `interactions.pictures`, chacun possédant `active` et `actions`. Le survol affiche une prévisualisation lorsque `hover: true`.
1467

15-
## Cycle de vie
68+
## Ouverture programmée
1669

17-
### 1. Construction
70+
Une image peut être ouverte depuis une URL ou une action externe en définissant, dans cet ordre, les propriétés OpenLayers `sequence`, `picture` et `display` :
1871

72+
```js
73+
panoramax.setCollapsed(false);
74+
panoramax.set("sequence", sequenceId);
75+
panoramax.set("picture", pictureId);
76+
panoramax.set("display", true);
1977
```
20-
constructor → initialize() → initContainer()
21-
```
22-
23-
- `initialize()` : stocke les options, crée les propriétés d'état (`collapsed`, `hover`, `auto`, références DOM, listeners…)
24-
- `initContainer()` : construit tout le DOM — deux panneaux principaux :
25-
- **`panelPanoramaxViewerContainer`** : le visualiseur de photos
26-
- **`panelPanoramaxButtonsContainer`** : les boutons de contrôle (filtres, contributions, fond de carte…)
27-
28-
### 2. Attachement à la carte (`setMap`)
29-
30-
- Active le mode **draggable** si besoin
31-
- Déclenche l'ouverture si `collapsed: false`
32-
- Appelle `addEventsListeners(map)` si `auto: true` (écoute `click` et `pointermove`)
33-
34-
### 3. Ouverture du panneau (`onShowPanoramaxClick`)
3578

36-
Appelle `load()` qui enchaîne de façon asynchrone :
79+
Si le viewer n'est pas encore prêt, le contrôle attend l'événement `pnx:ready` avant de sélectionner l'image. Pour fermer le viewer sans fermer le contrôle, utiliser `panoramax.set("display", false)`.
3780

38-
1. `setLayerGroup()` — crée un `LayerGroup` OL pour regrouper les couches
39-
2. `setBackground()` — charge une couche de fond (style Mapbox Vector)
40-
3. `setLayer()` — charge la couche Panoramax (TMS vecteur `MapboxVectorLayer`)
41-
4. `initButtons()` — affiche le panneau des boutons
42-
5. `initVisualizationWindow()``setSizeWindow()` — applique la taille (small/medium/large/fullscreen/fullscreen-map)
43-
6. `initPhotoViewer()` — crée le web component `<pnx-photo-viewer>` et ses widgets
81+
## Viewer et partage
4482

45-
### 4. Fermeture (`reset`)
83+
Le widget repose sur `<pnx-photo-viewer>` de `@panoramax/web-viewer`. Les widgets optionnels sont `btnBack`, `btnClose`, `btnZoom`, `btnFullscreen`, `cmpPictureLegend` et `cmpMinimap`. Au signal `ready` du viewer, les widgets natifs Player, annotations et légende basse sont retirés au profit des composants intégrés au contrôle.
4684

47-
Supprime les couches, réinitialise le viewer, les boutons, les overlays de prévisualisation.
85+
`viewer.share` configure le lien affiché dans la légende personnalisée :
4886

49-
---
50-
51-
## Interactions carte
52-
53-
| Événement | Comportement |
87+
| `type` | URL produite |
5488
|---|---|
55-
| `click` sur `pictures` | Ouvre le viewer avec `displayPhotoViewer(sequenceId, pictureId)` |
56-
| `click` sur `grid` | Zoom +4 niveaux |
57-
| `click` sur `sequences` | Zoom +2 niveaux |
58-
| `pointermove` (debounce 300ms) | Affiche une popup de prévisualisation (`displayPreview`) si `hover: true` |
59-
60-
---
89+
| `panoramax` (défaut) | URL Explore Panoramax avec `pic`, `seq` et la position courante |
90+
| `geoplateforme` | URL `.../photo/{sequence}/{picture}/{lat},{lon}/{zoom}` |
6191

62-
## Viewer de photos
92+
`viewer.share.url` permet de remplacer la base utilisée pour le type choisi. Les identifiants et les coordonnées sont encodés lors de la construction du lien.
6393

64-
Basé sur le web component `<pnx-photo-viewer>` de `@panoramax/web-viewer`. Des widgets personnalisés y sont injectés via des slots :
94+
## Filtres
6595

66-
- `pnx-button` (retour, fermeture, plein écran) → slots `top-left`/`top-right`/`bottom-right`
67-
- `pnx-widget-zoom`
68-
- `pnx-picture-legend`
96+
Les filtres modifient le style Mapbox de la couche puis appliquent le style mis à jour avec `applyStyle()` : type d'image, intervalle de dates et période relative. Le bouton de réinitialisation restaure le style initial de la couche.
6997

70-
Au `ready`, certains widgets natifs sont supprimés (`pnx-widget-player`, `pnx-annotations-switch`, `pnx-bottom-drawer`).
98+
`buttonsWindow.filters.exclusive` contrôle leur combinaison : à `true` (défaut), l'activation d'un filtre désactive les autres ; à `false`, les filtres actifs sont cumulés.
7199

72-
---
100+
## Événements publics
73101

74-
## Filtres (couche Mapbox)
75-
76-
Les filtres modifient directement le JSON de style Mapbox de la couche, puis rappellent `applyStyle()` de `ol-mapbox-style` :
77-
- **Type** : filtre `["==", ["get", "type"], "flat"|"equirectangular"]` sur les couches `pictures` et `sequences`
78-
- **Dates** : filtre `[">=", "ts", ...]` / `["<=", "ts", ...]`
79-
- **Période** : calcule un intervalle de dates avec `date-fns/subMonths`
80-
- **Reset** : réapplique `originalStyleLayerPanoramax` (snapshot du style initial)
81-
82-
> ⚠️ Limites connues : les filtres ne sont **pas cumulatifs** (chaque filtre écrase le précédent).
102+
| Événement | Déclenchement |
103+
|---|---|
104+
| `pnx:opened` / `pnx:closed` | Ouverture ou fermeture du contrôle |
105+
| `pnx:ready` | Viewer initialisé et prêt à être utilisé |
106+
| `pnx:fullscreen` | Changement du mode plein écran |
107+
| `pnx:data:clicked` / `pnx:data:hovered` | Interaction avec une entité Panoramax |
108+
| `pnx:filter:init`, `pnx:filter:dates`, `pnx:filter:periode`, `pnx:filter:type`, `pnx:filter:render` | Initialisation ou application d'un filtre |
83109

84-
---
110+
Les changements des propriétés `picture`, `sequence` et `display` émettent respectivement `change:picture`, `change:sequence` et `change:display`.
85111

86-
## Modes de fenêtre (`setSizeWindow`)
112+
## Modes de fenêtre
87113

88114
| Mode | Comportement |
89115
|---|---|
90-
| `small/medium/large` | Classes CSS fixes, `stopMapViewportSync()` |
91-
| `fullscreen` | `<dialog>` en position fixe 100vw×100vh |
92-
| `fullscreen-map` | Synchronise position/taille avec `map.getViewport().getBoundingClientRect()` via `startMapViewportSync()` (écoute `resize`, `scroll`, `change:size`) |
116+
| `small`, `medium`, `large` | Taille fixe via classe CSS |
117+
| `fullscreen` | `<dialog>` fixe sur toute la fenêtre (`100dvw` x `100dvh`) |
118+
| `fullscreen-map` | Fenêtre calée sur `map.getViewport()` et resynchronisée lors de `resize`, `scroll` et `change:size` |

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "geopf-extensions-openlayers",
33
"description": "French Geoportal Extensions for OpenLayers libraries",
4-
"version": "1.0.0-beta.13-580",
5-
"date": "31/08/2026",
4+
"version": "1.0.0-beta.13-581",
5+
"date": "03/09/2026",
66
"module": "src/index.js",
77
"main": "src/index.js",
88
"types": "src/index.d.ts",

samples-src/pages/tests/Panoramax/pages-ol-panoramax-modules-dsfr-v4.4.0.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ <h2>Ajout du widget Panoramax, avec les options par défaut</h2>
114114
},
115115
visualizationWindow : {
116116
size : "fullscreen-map"
117+
},
118+
viewer : {
119+
share : {
120+
url : "https://localhost:5173/cartes.gouv.fr-entree-carto/",
121+
type : "geoplateforme"
122+
}
117123
}
118124
};
119125
panoramax = new ol.control.Panoramax(options);

src/packages/CSS/Controls/Panoramax/DSFRpanoramaxStyle.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@
266266
height: 24px;
267267
}
268268

269+
.pnx-share-copy-icon {
270+
-webkit-mask: url("img/dsfr/copy.svg") center no-repeat;
271+
mask: url("img/dsfr/copy.svg") center no-repeat;
272+
}
273+
269274
/* popup */
270275
.pnx-popup-content {
271276
bottom: 20px;
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)