IGNF / geoportal-extensions

French Geoportal Extensions for well-known javascript mapping libraries (Leaflet and OpenLayers)
https://ignf.github.io/geoportal-extensions/
Other
64 stars 33 forks source link

Widget pour l'export des tracés (itineraire, isochrone ou croquis) pour OpenLayers #357

Closed lowzonenose closed 1 year ago

lowzonenose commented 1 year ago

Export des tracés du type :

Avec possibilité de choisir le format de sortie :

Exemples d’implémentation :

var route = new ol.control.Route();
map.addControl(route);

var exportRoute = new ol.control.Export({});
exportRoute.setControl(route);
exportRoute.setTarget(document.getElementById("btnExportRoute"));
exportRoute.setFormat("geojson");
exportRoute.setName("export-route");
exportRoute.setTitle("Exporter Iti");
exportRoute.setMenu(true);
exportRoute.render();
var iso = new ol.control.Isocurve();
map.addControl(iso);

 var exportIso = new ol.control.Export({
    control: iso,
    target: null,
    format: "kml",
    name: "export-iso",
    title : "Exporter",
    menu: false,
    onExport : function (content) {
        console.log(content);
    }
});
exportIso.render();
exportIso.on("export:compute", (e) => { console.log("Export Iso", e); });
var drawing = new ol.control.Drawing();
map.addControl(drawing);

var exportDrawing = new ol.control.Export({ control: drawing });
exportDrawing.render();
var measureProfil = new ol.control.ElevationPath();
map.addControl(measureProfil);
var exportProfil = new ol.control.Export({
      control: measureProfil
});
exportProfil.render();

image image

:warning:

Le widget doit être pluggable dans le widget Export.

Les widgets pluggable doivent implémenter les méthodes publiques suivantes :

RoadMap

lowzonenose commented 1 year ago

Ajout d'un menu de sélection du format d'export : image

Activation du menu : export.setMenu(true); ou var export = new ol.control.Export({ menu : true });

L'affichage du menu est activer avec l'icone « ☰ » ou « trigramme du ciel » et en survolant le bouton.

lowzonenose commented 1 year ago

Ex. d'export en GeoJSON avec la configuration du calcul embarquée pour les calcul d'iti, iso et alti. Le tag est préfixé : geoportail:compute pour les besoins du Portail.

(extrait jsdoc)

    /**
     * Response to the export of the route calculation
     * 
     * @example
     * // GeoJSON format
     * {
     *   "type":"FeatureCollection",
     *   "features":[...],
     *   "geoportail:compute":{
     *     "points":[ [2.588024210134887, 48.84192678293002 ] ],
     *     "transport":"Voiture",
     *     "exclusions":[...],
     *     "computation":"fastest",
     *     "results":{ <!-- Service --> }
     * }
     * @see {@link https://ignf.github.io/geoportal-access-lib/latest/jsdoc/Gp.Services.RouteResponse.html|Service}
     */

     /**
     * Response to the export of the isochron calculation
     * 
     * @example
     * // GeoJSON format
     * {
     *    "type":"FeatureCollection",
     *    "features":[...],
     *    "geoportail:compute":{
     *       "transport":"Pieton",
     *       "computation":"time",
     *       "exclusions":[
     *         
     *       ],
     *       "direction":"departure",
     *       "point":[ 2.587835382718464, 48.84192678293002 ],
     *       "results":{
     *          "message":"",
     *          "id":"",
     *          "location":{
     *             "x":"2.587835382718464",
     *             "y":"48.84192678293002"
     *          },
     *          "srs":"EPSG:4326",
     *          "geometry":{
     *             "type":"Polygon",
     *             "coordinates":[[...]]
     *          },
     *         "time":180,
     *         "distance":""
     *      }
     *    }
     * }
     * @see {@link https://ignf.github.io/geoportal-access-lib/latest/jsdoc/Gp.Services.IsoCurveResponse.html|Service}
     */

     /**
     * Response to the export of the profile calculation
     * 
     * @example
     * // GeoJSON format
     * {
     *  "type":"FeatureCollection",
     *   "features":[
     *      {
     *         "type":"Feature",
     *        "geometry":{
     *            "type":"LineString",
     *            "coordinates":[...]
     *         },
     *         "properties":null
     *      }
     *   ],
     *   "geoportail:compute":{
     *      "greaterSlope":76,
     *      "meanSlope":7,
     *      "distancePlus":84,
     *      "distanceMinus":48,
     *     "ascendingElevation":5,
     *     "descendingElevation":-4,
     *      "altMin":"92,04",
     *     "altMax":"96,71",
     *      "distance":163,
     *      "unit":"m",
     *      "points":[
     *        {
     *            "z":95.68,
     *           "lon":2.5874,
     *            "lat":48.8419,
     *            "acc":2.5,
     *            "dist":0,
     *            "slope":0
     *         }
     *      ]
     *   }
     *}
     * @see {@link https://ignf.github.io/geoportal-access-lib/latest/jsdoc/Gp.Services.AltiResponse.html|Service}
     */
lowzonenose commented 1 year ago

Widget Export

Le developpement d'un widget d'export qui peut se plugger sur un controle existant afin d'exporter le calcul dans un format donné. L'export doit poceder toutes les informations necessaire à la reconstruction du traitement.

Liste des widgets de calcul :

Liste des formats d'export vecteurs :

Que doit on exporter ?

tracé + metadonnées du contrôle et du calcul

Comment packager l'export ?

Incorporer les metadonnées dans une balise du format demandé si le format le permet.

Etat de l'existant

Les developpements sur les couches dites "compute" sur le Portail permettent déjà de récuperer ces informations via des méthodes des widgets afin d'exporter et de reconstruire le tracé et le calcul (geometrie + configuration).

Les méthodes publiques des widgets sont :

Le widget "Export" utilise la méthode getLayer() pour récuperer les features directement, puis les transforme au format demandé. Pour les metadonnées du calcul, on utilise aussi la méthode getData().

Etat des informations disponibles issues pour chaque controle

Les informations exportables doivent permettre de reconstruire le calcul. Grâce à ces informations, il ne sera pas necessaire de realiser un nouveau calcul sur un service lors d'un reimport du fichier.

A minima, il faut dans l'export :

Route

  1. la geometrie
// ex. de tronçon
{
  type : "Feature",
  geometry : o.geometry,
  properties : {
   popupContent : "(" + id + ") distance : " + this._convertDistance(o.distance) + " / temps : " + this._convertSecondsToTime(o.duration)
  },
  id : id
}
  1. les metadonnées

NB: les données sont brutes du service

/* cf. service iti */
{
  totalTime, totalDistance, bbox, routeGeometry,
  routeInstructions : [{duration, distance, code, instruction, bbox, geometry}]
}
{
  transport : "",
  computation : "",
  exclusions : [],
  points : [[lon, lat]],
  results : { /* service */ }
}

/!\ les instructions du service ne sont pas forcement en accord avec les instructions des tronçons car une simplification est realisée

ex. fusion des instructions identique (ex. plusieurs fois "tout droit")

Isochrone

  1. la geometrie
  1. les metadonnées

NB: les données sont brutes du service

{ /* cf. service isochrone */ }
{
  transport : 
  computation : 
  exclusions : 
  direction : 
  point : 
  results : { /* service */ }
}

Profile

  1. la geometrie
  1. les metadonnées
{
     greaterSlope // pente max
     meanSlope  // pente moyenne
     distancePlus // distance cumulée positive
     distanceMinus // distance cumulée négative
     ascendingElevation // dénivelé cumulée positive
     descendingElevation // dénivelé cumulée négative
     altMin // altitude min
     altMax // altitude max
     distance // distance totale
     unit : // unité des mesures de distance
     points : // elevations
}

Pour info

L'ouverture du profile est déclenché par la fin de saisie. La reconstruction du contrôle est à reflechir...

Drawing

NB1:

Ce n'est pas un outil de calcul donc sans meta informations de calcul...

NB2:

Ce widget possède son propre outil d'export.

Mais, il peut être surchargé par le widget "Export" en desactivant l'outil interne :

var drawing = new ol.control.Drawing({
   tools : {
      export : false
    }
});
  1. la geometrie
  1. les metadonnées : RAS

Measures

TODO...

Possibilité d'embarquer les info pour chaque format

Possibilité pour chaque format d'embarquer des metadonnées dans une balise etendue

GeoJSON

L'ajout de la balise "properties" à la racine n'est pas autorisé par la norme :

ex.

{
  "type": "FeatureCollection",
  "properties": {},
  "features": []
}

mais, il est possible d'y ajouter des "Foreign Members" à la racine ou dans chaque feature : cf. https://www.rfc-editor.org/rfc/rfc7946.html#section-6

ex.

{
  "type": "FeatureCollection",
  "geoportail:compute": {...},
  "features": [{
    "type": "Feature",
    "id": "f1",
    "geometry": {...},
    "properties": {...},
    "title": "Example Feature"
  }]
}

L'implementation d'OpenLayers ne permet pas d'ecrire à la racine. Seules les properties d'une feature sont retranscrites dans le fichier.

Comment mettre en place une balise geoportail:compute à la racine du fichier ?

mettre en place une surcharge sur GeoJSONExtended

GPX

cf. https://www.topografix.com/gpx.asp

Optionnellement, des extensions (​) permettant d'ajouter librement des éléments XML définis dans un autre espace de noms (namespace) afin d'étendre les capacités du fichier.

On utilise déjà ce mécanisme pour les styles embarqués :

<extensions>
        <marker-size>medium</marker-size>
        <marker-symbol></marker-symbol>
        <marker-color>#ffffff</marker-color>
</extensions>

Comment mettre en place une balise geoportail:compute à la racine du fichier ?

mettre en place une surcharge sur GPXExtended

KML

On utilise déjà ce mécanisme avec les styles embarqués.

On peut prévoir ce même mécanisme avec un prefixage :

ex.

<ExtendedData xmlns:gpp="http://geoportail.gouv.fr/schemas">
      <gpp:number>14</gpp:number>
      <gpp:parkingSpaces>2</gpp:parkingSpaces>
      <gpp:tentSites>4</gpp:tentSites>
</ExtendedData>

Comment mettre en place une balise geoportail:compute à la racine du fichier ?

mettre en place une surcharge sur KMLExtended

lowzonenose commented 1 year ago

Plusieurs possibilités de plugger le widget Export :

  1. appel de map.addControl(export)
    
    var profil = new ol.control.ElevationPath();
    map.addControl(profil);

var exportProfil = new ol.control.Export({ control: profil }); exportProfil.on("export:compute", (e) => { console.log("Export Profil", e); }); map.addControl(measureProfil);


2. en option du contrôle
```js
var profil = new ol.control.ElevationPath({ export : true  });
profil.on("export:compute", (e) => { console.log("Export Profil", e); });
map.addControl(profil);

NB: l'event export:compute est propagé via le contrôle

  1. appel directement de render()
    
    var profil = new ol.control.ElevationPath();
    map.addControl(profil);

var exportProfil = new ol.control.Export({ control: profil }); exportProfil.on("export:compute", (e) => { console.log("Export Profil", e); }); exportProfil.render(); ``

azarz commented 1 year ago

PI : dans Leaflet j'ai bricolé un truc dans un projet perso qui fait un truc similaire : https://github.com/azarz/cartofeln/blob/develop/src/js/index.js#L98

elias75015 commented 1 year ago

Pouvoir ajouter le control d'export avec ses options directement via les options des widgets pluggables (iti/iso/alti/drawing) pourrait etre interessant.

 var profil = new ol.control.ElevationPath({
    export : exportOptions
});