CEREMA JOP 2024 Accessibilité
  • Contexte
  • Carte interactive
  • Etat des lieux
    • Etablissements recevant du public
    • Voirie
    • Transports en commun
  • Télécharger les données
Carte interactive
import { aq, op } from '@uwdata/arquero' // le dplyr ou pandas du javascript

L = globalThis.L
viewof mySite = Inputs.input()

// on a récupéré des string, il faut les parser...
communes = JSON.parse(communesString)
sites = JSON.parse(sitesString)
sites_mask = JSON.parse(sites_maskString)
/*sitesFiltered = bertin.properties.filter({
  geojson: sites,
  expression: `sites_olymp == '${sites_olymp}'`
})*/

// Ici on fabrique notre geoJSON filtré avec les viewof
sitesFiltered = {return {
  type: "FeatureCollection",
  features: sites.features.filter(feature => 
      sites_olymp.includes(feature.properties.sites_olymp)
      && suivi.includes(feature.properties["Suivi"])
  )
}};

//sitesFiltered
osm = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
    attribution: "© OpenStreetMap contributors"
});

ortho = L.tileLayer("https://data.geopf.fr/wmts?&REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE=normal&TILEMATRIXSET=PM&FORMAT=image/jpeg&LAYER=ORTHOIMAGERY.ORTHOPHOTOS&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}", {
    attribution: "© IGN",
    tileSize: 256,
    maxZoom: 19
});
_communes = L.geoJSON(communes,{
  style: {
    color: "purple",
    weight: 2,
    fillOpacity: 0
  }
});//.addTo(map);
_sites = L.geoJSON(sites, {
      onEachFeature: function (feature, layer) {
          layer.bindPopup(`
                          <strong>${feature.properties.nom}</strong><br>
                          ${feature.properties.sites_olymp||''}<br>
                          ${feature.properties.sports}<br>
                          `);
      }
    });//.addTo(map);

/*_sites.on('click', function(e) {
    mutable mySite = e.layer.feature.properties;
    // console.log('ID cliqué :', e.layer.feature.properties);
});*/

// Quand on clique sur un site, on modifie la valeur du viewof et on propage l'info
/*_sites.on('click', function(e) {
    //mutable mySite = e.layer.feature.properties;
    //alert(e.layer.feature.properties.fid);
    viewof mySite.value = e.layer.feature.properties;
    viewof mySite.dispatchEvent(new Event("input", {bubbles: true}));
    // console.log('ID cliqué :', e.layer.feature.properties);
});
*/
// Création d'un viewof et bind à notre variable réactive
viewof clickMap = {
  // Création d'un div pour afficher les informations
  const element = html`<div>Cliquer sur un site pour voir les informations ici</div>`;
  // Valeur initiale
  element.value = null;
  // Ajout de l'événement de clic sur la couche Leaflet
  _sites.on('click', function(e) {
    // Met à jour la valeur de viewof
    element.value = e.layer.feature.properties;
    element.dispatchEvent(new Event("input", {bubbles: true}));

    // Mise à jour du contenu visuel du div
    //div.textContent = `${JSON.stringify(div.value)}`;
  });
  // Retourne le div comme élément DOM
  return element;
}
Inputs.bind(viewof clickMap, viewof mySite)
_markers = L.markerClusterGroup();
_markers.addLayer(_sites);
// bloc pour faire vivre la couche des sites en fonction des actions utilisateurs
// Vérifie si _sites existe déjà, si oui, on vide les markers et on met les nouveaux du geJSON filtrés
{
  if (_sites) {
    _sites.clearLayers(); // Vide tous les marqueurs de la couche existante
    _sites.addData(sitesFiltered); // Ajoute les nouvelles données
    _markers.clearLayers();
    _markers.addLayer(_sites);
  }
}
// Fabrication de la MAP leaflet
// bien comprendre cet exemple pour pouvoir accéder à l'objet map dans les autres chuncks, c'est franchement pas intuitif comme syntaxe
// https://observablehq.com/@mbostock/mapbox-fly-to

viewof map = {
  // You'll often see Leaflet examples initializing a map like L.map('map'),
  // which tells the library to look for a div with the id 'map' on the page.
  // In Observable, we instead create a div from scratch in this cell, so it's
  // completely self-contained.
  // const container = DOM.element('div', { style: `width:${width*90/100}px;height:${width/1.6}px` });
  const container = DOM.element('div', { style: `height:70vh;` });

  let resolve;
  container.value = new Promise(_ => resolve = _);

  // Note that I'm yielding the container pretty early here: this allows the
  // div to be placed on the page. This is important, because Leaflet uses
  // the div's .offsetWidth and .offsetHeight to size the map. If I were
  // to only return the container at the end of this method, Leaflet might
  // get the wrong idea about the map's size.
  yield container;
  
  // Now we create a map object and add a layer to it.
  const map = L.map(container);
  map.setView([46.827638, 2.203749], 6);

  // Ajouter OSM par défaut
  osm.addTo(map);
  //_sites.addTo(map);
  _communes.addTo(map);
  map.addLayer(_markers);

  // Contrôle des couches
  const baseMaps = {
    "OpenStreetMap": osm,
    "Orthophotos": ortho
  };
  const overlayMaps = {
    //"sites": _sites,
    "sites": _markers,
    "communes": _communes
  };
  const layerControl = L.control.layers(baseMaps, overlayMaps).addTo(map);

  resolve(map); // Expose the Map instance as the view’s value.
  invalidation.then(() => map.remove()); // faire un ménage propre si le chunck est recalculé
}

//console.log(viewof map);
//console.log(map);
  • Mise en accessibilité
  • Données détaillées
  • Miniature
md`*Sélectionner un site sur la carte interactive*  `
md`
### **${mySite.nom}** (mis en service en ${mySite["Date de construction / Année de mise en service"]})  
*[TODO : Description de l’équipement par le Cerema (“analyse”) ]*  
  
**Utilisation du site pendant les Jeux** : ${mySite["sites_olymp"]}  
  
**Épreuves ou sports accueillis**: 
`
{
  if (mySite["Olympique"]){
    return md`![olympique](images/icon_olympics.svg) **Olympique** : ${mySite["Olympique"]}  `
  }else{return md``}
}
{
  if (mySite["Paralympique"]){
    return md`![paralympique](images/icon_paralympics.svg) **Paralympique** : ${mySite["Paralympique"]}     `
  }else{return md``}
}
html`<br>`
{
  if (mySite["Pérennité des interventions réalisées pour les JOP"]){
    return md`**Pérennité** des interventions réalisées pour les JOP : ${mySite["Pérennité des interventions réalisées pour les JOP"]}     `
  }else{return md``}
}
html`<br>`
md`
### **<u>Infos travaux</u>**
`
{
  if (mySite["Intervention / Travaux d'accessibilité sur l'ERP"]){
    return md`Intervention / Travaux d'accessibilité sur l'**ERP** : ${mySite["Intervention / Travaux d'accessibilité sur l'ERP"]}     `
  }else{return md``}
}
mySitelong = aq.from([mySite])
              .select("Abords immédiats, cheminement extérieur propre au site",
                      "Stationnement pour public PMR propre au site",
                      "Entrée principale",
                      "Zone d'accueil",
                      "Rampe",
                      "Ascenseur",
                      "Élévateur",
                      "Places spectateurs UFR",
                      "Places spectateurs faciles d'accès",
                      "Sanitaires",
                      "Vestiaires",
                      "Terrain de sport / Bassin",
                      "Signalétique propre au site")
              .fold(aq.all())
              .filter(d => d.value=='Oui')
              .select('key')
              .rename({key:"Travaux ERP effectués"})

Inputs.table(mySitelong)
html`<br>`
md`**Plus d’infos sur :**  `
{
  if (mySite["url_acces_libre"]){
    return html`
    <a href=${mySite["url_acces_libre"]} target="_blank">
      Prendre connaissance des données disponibles sur AccesLibre
    </a>
    `
  }else{return md``}
}
{
  if (mySite["Url_data_es (tableau)"]){
    return html`
    <a href=${mySite["Url_data_es (tableau)"]} target="_blank">
      Prendre connaissance des données disponibles sur dataES (base nationale des équipements sportifs)
    </a>
    `
  }else{return md``}
}
{
  if (mySite["lien_solideo"]){
    return html`
    <a href=${mySite["lien_solideo"]} target="_blank">
      + d'infos sur le site de la société de livraison des ouvrages olympiques (SOLIDEO)
    </a>
    `
  }else{return md``}
}
{
  if (mySite["lien_paris_2024"]){
    return html`
    <a href=${mySite["lien_paris_2024"]} target="_blank">
      + d'infos sur le site PARIS 2024
    </a>
    `
  }else{return md``}
}
mySitelong2 = aq.from([mySite])
              .fold(aq.all())
              .rename({key:"Libellé", value:"Valeur"})

Inputs.table(mySitelong2,{rows: 100,layout: "auto"} )
siteMaskGeo = bertin.properties.filter({
                  geojson: sites_mask,
                  expression: `fid == ${mySite.fid}` 
              })
          
bertin.draw({
  params: { projection:"Mercator", margin: 50, width: 500},
  layers: [
    {
      type: "layer",
      geojson: siteMaskGeo,
      tooltip: ["$fid","$nom"],
      fillOpacity: 0
    },
    /*{
      type:"tiles",
      style:"openstreetmap",
      clip: siteMaskGeo
    },*/
    {
      type: "tiles",
      opacity: 1,
      zoomDelta: 2,
      style: "worldimagery",
      clip: siteMaskGeo
    },
    { type: "shadow", geojson: siteMaskGeo, dx: 5, dy: 5 }

  ]
})
bertin = require("bertin")

// sitesTable est la version Table du geojson
sitesTable = bertin.properties.table(sites)
communesTable = bertin.properties.table(communes)
viewof _flyToCommune = Inputs.select([{"NOM":"Sélectionner une commune", bbox_js:"[[51.20, -4.85], [42.03, 8.73]]"},...communesTable], {value:null, label :"Commune",  format: d => d["NOM"]})
//JSON.parse(_flyToCommune.bbox_js)

// viewof _flyToSite = Inputs.select([{nom:"Sélectionner un site", fid:null},...sitesTable], {value:10, label :"Site",  format: d => d.nom})
//JSON.parse(_flyToCommune.bbox_js)
Inputs.bind(
  Inputs.select([{nom:"Sélectionner un site", fid:null},...sitesTable], {label :"Site",  format: d => d.nom}),
  viewof mySite
)
viewof sites_olymp = Inputs.checkbox(sitesTable.map(d=>d.sites_olymp), {label:"Type de site",unique:true, sort:true, value:[...new Set(sitesTable.map(d=>d.sites_olymp))]})

viewof suivi = Inputs.checkbox(sitesTable.map(d=>d["Suivi"]), {label:"Suivi",unique:true, sort:true, value:[...new Set(sitesTable.map(d=>d["Suivi"]))]})
// Le flyTo bounds (on le met à part pour éviter l'affichage de la fonction)
map.flyToBounds(JSON.parse(_flyToCommune.bbox_js), {padding: [25, 25], duration:1})
// Le flyTo bounds (on le met à part pour éviter l'affichage de la fonction)
map.flyTo(JSON.parse(mySite.coord_js), 16, {duration:1});