C'est la suite du
  #30DayMapChallenge, et la deuxième carte que je devais réaliser est celle du jour 12, sur le
  thème space and time (temps et espace).
  Je trouve que la manière organique dont l'occupation de l'espace évolue avec
  le temps est fascinante, que ce soit sur des périodes de dizaines, centaines,
  milliers, millions d'années ou avec le rythme des saisons, sous l'influence de
  l'anthropisation ou au gré d'événements naturels, tous ces facteurs étant
  intimement liés.
  
  Pour l'Arctique, cette évolution bien sûr dramatique. Mais en observant ses
  variations d'étendue, je ne peux m'empêcher de trouver une certaine poésie à
  cette image d'un cœur qui bat au fil des saisons mais qui s'affaiblit d'année
  en année.
  Ou, pour pouvoir faire référence au titre d'un des épisodes d'un célèbre jeu
  vidéo où un type en tunique verte détruit des poteries pour sauver la
  princesse, nous pouvons aussi utiliser l'image d'un poumon qui
  respire.  
L'application
Et voici l'application que toutes ces réflexions m'ont inspiré : Breath of the Arctic. N'hésitez pas à cliquer sur le lien pour la consulter en pleine page pour un meilleur confort visuel. Cette application en projection polaire représente les variations d'étendue de l'Arctique, c'est-à -dire des parties de l'océan ayant gelé pour former une "mer de glace", mois par mois de la fin de l'année 1978 à nos jours. La ligne discontinue blanche montre la superficie maximale enregistrée en mars 1979.
  Les données proviennent du
  National Snow and Ice Data Center
  (NSIDC) et sont accessibles
  depuis le Living Atlas d'ArcGIS. 
Le code
  Nous allons maintenant regarder ensemble le code permettant de faire
  fonctionner l'application. Celle-ci a été crée grâce à l'API JavaScript d'ArcGIS. Comme d'habitude, vous pouvez recréer cette application de votre côté grâce
  au tutoriel, mais également retrouver le code complet
  sur mon Github
  ou le tester interactivement avec
  ce Codepen. Si vous sentez que le niveau de ce tutoriel est un peu trop élevé pour vous
  et que les notions sont expliquées trop rapidement, je vous conseille
  d'explorer
  cette série
  qui prend le temps d'expliquer pas à pas les notions fondamentales. Cela étant
  dit, c'est parti pour le code !
  Le code HTML est extrêmement simple, avec un appel à l'API JavaScript
   
https://js.arcgis.com/4.30/ ainsi qu'à son style
  https://js.arcgis.com/4.30/esri/themes/dark/main.css, que nous
  allons utiliser ici en mode sombre (dark). Je référence également ma propre
  feuille de style et mon propre script que j'ai séparés du HTML. Dans le corps
  du HTML, j'insère une balise <div id = "full"> qui
  encapsule toutes mes autres balises, une balise <div id = "dayeDisplay>
  qui accueillera la date d'enregistrement de la donnée et une balise 
  <viewDiv> qui contiendra la vue de ma carte. 
  <html lang="en"> <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>
    Breath of the Arctic
  </title>
  <link rel="stylesheet" href="style/style.css" />
  <link rel="stylesheet" href="https://js.arcgis.com/4.30/esri/themes/dark/main.css" />
  <script src="https://js.arcgis.com/4.30/"></script>
  <script src="app/main.js"></script>
  <script type="module" src="https://js.arcgis.com/calcite-components/2.1.0/calcite.esm.js"></script>
</head>
<body >
  <div id="full">
    <div id="dateDisplay">
      <h3>-/-</h3>
    </div>
    <div id="viewDiv"></div>
  </div>
</body>
</html>
    Côté CSS, je m'assure simplement que la taille de la
    
  
  <viewDiv> prendra l'entièreté de l'écran et que la date
    s'affichera avec un style sympa quelle que soit la taille de l'écran.html,
body,
#viewDiv {
  padding: 0;
  margin: 0;
  height: 100%;
  width: 100%;
  position: absolute;
  background-color: "#212526";
}
h3 {
  z-index: 200;
  padding-top: 1%;
  font-weight: normal;
  font-size: 170%;
  font-family: "Avenir Next", "Avenir", "Helvetica Neue", sans-serif;
  position: absolute;
  z-index: 9;
  text-align: center;
  width: 100%;
  height: 10%;
  margin: auto;
  user-select: none;
}
#dateDisplay {
  z-index: 150;
  font-weight: normal;
  position: absolute;
  font-size: 120%;
  font-family: "Avenir Next", "Avenir", "Helvetica Neue", sans-serif;
  position: absolute;
  user-select: none;
  padding-top: 1.6%;
}
@media screen and (min-width: 500px) {
  #dateDisplay {
    right: 1%;
  }
}
@media screen and (max-width: 500px) {
  #dateDisplay {
    width: 100%;
    text-align: center;
    top: 5%;
  }
}
    Il est maintenant temps de faire appel à l'API JavaScript pour insérer notre
    carte !  Comme d'habitude, je commence par charger les modules qui me
    seront utiles dans le require (ici,
    WebMap,
    MapView, FeatureLayer, GraphicsLayer et
    Graphic), puis je déclare la fonction qui contiendra toutes les instructions
    utiles à l'affichage de ma carte et je lui passe en arguments chacune de ces
    classes dans le même ordre que dans le require. 
    
  require([
  "esri/WebMap",
  "esri/views/MapView",
  "esri/layers/FeatureLayer",
  "esri/layers/GraphicsLayer",
  "esri/Graphic"
], function (WebMap, MapView, FeatureLayer, GraphicsLayer, Graphic) {
//le reste du code ira ici
});
    La première étape consiste ensuite à appeler une
    WebMap
    à l'intérieur de mon application. Contrairement à une simple Map qui doit
    être construite de zéro dans le code, la WebMap va se baser sur une carte
    construite grâce au MapViewer dans ArcGIS Online ou ArcGIS Enterprise. Cette
    approche permet de faire gagner un temps considérable de développement, en
    étant capable de configurer les couches et leur symbologie, le fond de
    carte, le système de coordonnées, mais aussi d'éventuels géosignets etc.
    sans aucune ligne de code. Si la carte est mise à jour, cela se répercutera
    également sur l'application sans avoir à maintenir le code. Ici, j'ai donc
    préparé ma carte dans le MapViewer avec 4 couches dont j'ai configuré la
    symbologie : les pays du monde pour le fond de carte, l'étendue maximale
    enregistrée pour l'Arctique (que vous voyez apparaître en pointillés
    blancs), la couche contenant tous les enregistrements d'étendue de
    l'Arctique depuis 1978 (qui pour l'instant est cachée mais dont nous nous
    servirons dans le code), et une couche de dessin qui est simplement un
    cercle blanc dont j'ai modifié la symbologie et qui me permet de créer
    l'effet de halo que vous voyez autour du pôle Nord. 
    
    J'ajoute donc simplement cette WebMap à mon code en indiquant son id, que
    vous pouvez retrouver facilement dans l'url de la page de l'item. (exemple
    ici :
    https://esrifrance.maps.arcgis.com/home/item.html?id=360827c4ab4f4aad85b771bd453a7254).
    Vous pouvez directement utiliser la même carte que moi, car je l'ai partagée
    en public.
  
  const map = new WebMap({
  portalItem: {
    id: "360827c4ab4f4aad85b771bd453a7254"
  }
});
    Je crée ensuite une vue sur ma carte grâce à la
    MapView, en indiquant le
    centre
    (en long/lat) ainsi que le niveau de zoom. Ici, je rajoute également des
    contraintes
    afin d'empêcher l’utilisateur final de modifier le niveau de
    zoom. Je
    retire
    également les éléments d'interface utilisateur (UI) intégrés par défaut à la MapView pour épurer l'application.
  
  const view = new MapView({
  container: "viewDiv",
  map: map,
  center: [2277430.5171051705, 2076536.5900727776],
  zoom: 4,
  constraints: {
    maxZoom: 4,
    minZoom: 4
  }
});
view.ui.remove(["zoom"]);
    Pour la suite, je veux m'assurer que la carte et ses couches soient
    entièrement chargées avant de les manipuler. J'utilise pour cela une
    instruction
  
   map.when(() => { ... }) à l'intérieur de
    laquelle je placerai toute la suite de mon code.
    J'accède ensuite à la couche contenant l'historique d'étendue de l'Arctique.
    Le calque étant en 3ème position de la carte, je le retrouve à l'index 2 en
    accédant aux
    layers
    de la map et je le stocke à l'intérieur de la variable
    
  arcticExtentLayer.  
    const arcticExtentLayer = map.layers.items[2];
  arcticExtentLayer.visible = false;
    Je crée maintenant
    une couche graphique (
  GraphicsLayer)
    que j'ajoute à la carte. Pour l'instant, cette couche est vide mais elle me
    servira à afficher dynamiquement une à une les différentes étendues de
    l'Arctique depuis 1978.
    const graphicsLayer = new GraphicsLayer();
  map.add(graphicsLayer);
    Avec
    la méthode 
    
  queryFeatures(), je viens interroger la couche arcticExtentLayer. La query va
    interroger la couche et en retourne la géométrie et les attributs de chacune
    des entités sous la forme d'un tableau de
    Graphics
    contenu dans un
    FeatureSet, auquel on accède grâce à la méthode .then(). Pour la suite,
    nous travaillerons à l'intérieur du .then() jusqu'à la fin
    du tutoriel.arcticExtentLayer.queryFeatures().then((results) => { //le reste du code ira ici });
    Chaque objet  est ensuite accessible en parourant
    
  results.features grâce à la méthode .map(). Nous
    allons retourner un
    Graphic
    pour chacune des entités de la couche, et les stocker dans un tableau que
    nous appelons features. Pour construire les Graphics, nous
    renseignons les propriétés
    geometry
    et
    attributes
    en nous servant des informations renvoyées par la query, et nous définissons
    à la main la
    symbologie, ici un polygone bleu clair avec un contour bleu vif. 
  const features = results.features.map((feature) => {
  return new Graphic({
    geometry: feature.geometry,
    attributes: feature.attributes,
    symbol: {
      type: "simple-fill",
      color: [203, 242, 242, 0.3],
      outline: { color: [133, 242, 242], width: 1 }
    }
  });
});
    Nous allons enfin créer une fonction qui nous permet d'afficher un à un les
    graphiques créés ci-dessus. Pour cela, nous initialisons une variable
    
  index à 0 qui nous permettra d'appeler un à un les graphiques
    stockés dans le tableau features. Nous créons ensuite la
    fonction displayFeature(). Celle-ci commence par
    retirer
    tous les graphiques potentiellement présents à l'écran pour s'assurer que
    nous affichons les étendues de l'Arctique une par une. Nous appelons ensuite
    le graphique correspondant à l'index actuellement parcouru (celui-ci
    s'incrémente de 1 à chaque passage dans la fonction afin de parcourir tous
    les graphiques un par un), et nous ajoutons ce graphique à la carte. 
  
    Afin d'indiquer à l'utilisateur de quand date l'étendue actuellement
    affichée à l'écran, la fonction récupère également les informations de mois
    et d'année contenues dans les attributs du graphique et les injecte dans le
    HTML. Enfin, afin de souligner les changements d'années, les années paires
    et impaires sont affichées dans des couleurs différentes.
  
  let index = 0;
function displayFeature() {
  graphicsLayer.removeAll();  // Supprime les graphiques précédents
  const currentFeature = features[index]; // Récupère la fonctionnalité actuelle
  graphicsLayer.add(currentFeature); // Ajoute le graphique à la couche
  // Extraction et affichage des informations temporelles
  const month = currentFeature.attributes["Rec_Month"];
  const year = currentFeature.attributes["Rec_Year"];
  dateDisplay.innerHTML = `${month}/${year}`;
  // Modification de la couleur de la date en fonction de l'année (paire ou impaire)
  if (year % 2 === 0) {
    dateDisplay.style.color = "rgb(108, 166, 166)"; // Années paires
  } else {
    dateDisplay.style.color = "rgb(150, 212, 212)"; // Années impaires
  }
  // Incrémentation de l'index pour passer à la fonctionnalité suivante
  index = (index + 1) % features.length;
}
    Afin, nous appelons la fonction tous les 100 millisecondes
    
  setInterval(). Cela crée une animation en affichant une
    fonctionnalité à la fois dans graphicsLayer, donnant
    l’impression de visualiser les données géospatiales de manière continue.
  setInterval(displayFeature, 100);
    Voici le code JS complet que vous devriez obtenir : 
  
  require([
  "esri/WebMap",
  "esri/views/MapView",
  "esri/layers/FeatureLayer",
  "esri/layers/GraphicsLayer",
  "esri/Graphic"
], function (WebMap, MapView, FeatureLayer, GraphicsLayer, Graphic) {
  const map = new WebMap({
    portalItem: {
      id: "360827c4ab4f4aad85b771bd453a7254"
    }
  });
  const view = new MapView({
    container: "viewDiv",
    map: map,
    center: [2277430.5171051705, 2076536.5900727776],
    zoom: 4,
    constraints: {
      maxZoom: 4,
      minZoom: 4
    }
  });
  view.ui.remove(["zoom"]);
  map.when(() => {
    const arcticExtentLayer = map.layers.items[2];
    arcticExtentLayer.visible = false;
    const graphicsLayer = new GraphicsLayer();
    map.add(graphicsLayer);
    arcticExtentLayer.queryFeatures().then((results) => {
      const features = results.features.map((feature) => {
        return new Graphic({
          geometry: feature.geometry,
          attributes: feature.attributes,
          symbol: {
            type: "simple-fill",
            color: [203, 242, 242, 0.3],
            outline: { color: [133, 242, 242], width: 1 }
          }
        });
      });
      let index = 0;
      let previousYear = null;
      function displayFeature() {
        graphicsLayer.removeAll();
        const currentFeature = features[index];
        graphicsLayer.add(currentFeature);
        // Récupérez les informations de date et mettez à jour l'affichage
        const month = currentFeature.attributes["Rec_Month"];
        const year = currentFeature.attributes["Rec_Year"];
        dateDisplay.innerHTML = `${month}/${year}`;
        if (year % 2 === 0) {
          dateDisplay.style.color = "rgb(108, 166, 166)"; // Années paires en bleu foncé
        } else {
          dateDisplay.style.color = "rgb(150, 212, 212)"; // Années impaires en bleu clair
        }
        index = (index + 1) % features.length;
      }
      setInterval(displayFeature, 100); // Mise à jour toutes les 100 ms
    });
  });
});
    La partie cartographique est terminée ! De mon côté, j'ai enrichi
    l'application grâce à un loader en utilisant des éléments de Calcite, comme
    nous l'avions vu dans
    ce tutoriel. J'ai également rajouté un titre, des crédits et une fenêtre informative
    quand l'utilisateur clique sur "En savoir +" en ajoutant un peu de HTML et
    de CSS.  Nous verrons cela en détails d'ici la fin de l'année dans un
    tutoriel consacré aux composants. En attendant, n'hésitez à nouveau pas à
    consulter le code complet
    sur Github
    ou le
    sur Codepen afin d'essayer d'en faire de même ! 
Si cet article vous a plus, n'hésitez pas à retrouver les tutoriels de 
mes deux autres créations cartographiques pour ce challenge : la carte d'élévation de la France en hexagones, et une carte d'isohypses pour représenter les concentrations des photos que j'ai prises dans ma ville.
  



 
 
 
 
Aucun commentaire:
Enregistrer un commentaire