Rechercher dans le blog

Un mardi, une appli #21 : les Sept Sommets



Bonjour à tous !

Comme promis dans l’article de la semaine dernière sur les nouveautés de la version 4.25 de l’ArcGIS API for JavaScript, je vous propose aujourd’hui un nouveau numéro de la série Un mardi, une appli.

J’ai découvert cette très belle application permettant d’explorer le point le plus profond de chaque océan, « The Five Deeps », développée par Raluca Nicola d’Esri dont je vous conseille fortement de découvrir le travail (et dont certaines applications ont déjà été examinées sur ce blog, par exemple ici).

Nous allons nous inspirer de cette application pour créer ensemble son homologue présentant les points culminants de chacun des continents, que nous nommerons  « Les Sept Sommets».


L'appli

Les Septs Sommets (Seven Summits) sont un challenge mythique de l’alpinisme consistant à gravir le sommet de chacun des sept continents : le Mont Vinson (Antarctique), le Kilimandjaro (Afrique), l’Aconcagua (Amérique du Sud), l’Everest (Asie), le Denali aussi appelé McKinley (Amérique du Nord), l’Elbrouz (Europe) et le Puncak Jaya aussi connu sous le nom de Pyramide de Carstensz (Océanie).  

En 3D, l’application permet de parcourir chacun de ces points culminants sous la forme de points d’intérêt interrogeables.

Le code

L’application se base sur l’API JavaScript d’ArcGIS, et vous pouvez en retrouver le code commenté sur mon Github.

Configuration de la carte et de la scène 3D

Nous commençons par créer la carte, qui utilisera en tant que fond de carte deux couches de tuile qui seront mélangées avec le mode de fusion produit (multiply). Vous pouvez bien sûr utiliser n’importe quelle autre fond de carte de votre choix.

//création de la carte "map"    
const map = new Map({ 
    basemap : new Basemap({ //création de la basemap pour la carte "map"
        baseLayers: [
            new TileLayer({
                url:"https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer", 
                opacity: 0.7
            }),
            new TileLayer({
                url: "https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/GEBCO_basemap_NCEI/MapServer",
                blendMode: "multiply"
            }),
        ]
    }),
    qualityProfile: "high"
}); 

Cette carte est appelée dans une vue 3D (scène), dont nous choisissons l’échelle et le point central d’affichage. Notez que c’est également à cette étape que nous commençons à configurer les popups qui apparaîtront lorsque nous interrogerons les points, pour que celles-ci soient ancrées en bas à droite de l’écran et non flottantes.

//création de la vue 3D (scene)
const view = new SceneView({ 
    container: "viewDiv", // référence à la balise qui contiendra la vue
    map: map, //appel de la carte "map" à l'intérieur de la vue
    scale: 50000000, // initialisation de la vue à l'échelle 1:50,000,000
    center: [40, 21.78], //lon, lat du point central de la vue initiale
    popup: { //préconfiguration des popups pour qu'elles soient ancrées en bas à droites
        defaultPopupTemplateEnabled: false,
        dockEnabled: true,
        dockOptions: {
          buttonEnabled: false,
          breakpoint: false,
          position : "bottom-right"
        }
      },
    highlightOptions: {
        haloOpacity: 0,
        fillOpacity: 0
    }
});

Configuration et ajout des couches à la carte

Il est maintenant temps de référencer les différentes couches. Commençons par la couche d’élévation, qui est ici une couche exagérée verticalement d’un facteur 3,5 pour accentuer les points culminants. Celle-ci est ajoutée à la carte en tante que couche de configuration du sol.

//référencement de la couche d'élévation (cette couche possède une exagération verticale x3.5 pour accentuer les points culminants)       
const elevLyr = new ElevationLayer({ 
     url: "https://tiles.arcgis.com/tiles/P3ePLMYs2RVChkJx/arcgis/rest/services/GEBCO_2021_3pt5x/ImageServer" 
});
map.ground.layers.add(elevLyr); //ajout de la couche d'élévation à la carte

Nous allons ensuite ajouter des nuages, pour l'esthétisme de ce globe. Nous utilisons pour cela un MediaLayer, nouvelle fonctionnalité de la version 4.24 de l’API permettant de superposer des images à notre carte.

//création d'un Media Layer (disponible depuis v4.24) pour contenir les nuages        
const cloudsLayer = new MediaLayer({ 
    source: [new ImageElement({
        image: "https://raw.githubusercontent.com/JapaLenos/JS-API/main/Les-Sept-Sommets/assets/clouds-nasa.png", //l'image de nuages est hébergée sur mon github
        georeference: new ExtentAndRotationGeoreference({
            extent: new Extent({
                spatialReference: {
                    wkid: 4326
                },
                xmin: -180,
                xmax: 180,
                ymin: -80,
                ymax: 80
            }),
        rotation: 0
        })
    })],
});
map.add(cloudsLayer); //ajout des nuages

Maintenant, nous allons nous occuper de la couche d'entités contenant les sommets. Celle-ci est hébergée sur une organisation ArcGIS Online et est donc exposée grâce à l’API REST, vous pouvez retrouver toutes les informations sur cette couche ici.

Sur cette couche, nous commençons donc par configurer les fenêtres contextuelles (popups) qui apparaîtront lorsque nous cliquerons sur un point.

//configuration des Popups pour la couche de sommets
    
const textElement1 = new TextContent();
textElement1.text = "Continent: {Continent}"

const textElement2 = new TextContent();
textElement2.text = "Année de première ascension: {Annee}"

const textElement3 = new TextContent();
textElement3.text = "{Description}"


const popup = {
    "title": "{Nom}, {Altitude} mètres d'altitude",
    "content": [textElement1,textElement2,textElement3],
} 

Nous modifions ensuite la symbologie qui s’affichera pour les points. Tous les points s’afficheront de la même manière, nous utiliserons donc un rendu simple.

const symbo = new SimpleRenderer({
    symbol: new PointSymbol3D({
        symbolLayers: [new IconSymbol3DLayer({
            resource: { href: "https://raw.githubusercontent.com/JapaLenos/JS-API/5e6ba74a44fa14ed5eaccf7e0acc7d3a0c09e06a/Les-Sept-Sommets/assets/icon.svg" }, 
            size: 40
        })]
    })
})

Enfin, nous pouvons référencer la couche et configurer les labels qui apparaîtront à côté de chacun des points, pour que l'utilisateur puisse voir le nom des sommets sans avoir à cliquer dessus. 

//référencement du Feature Layer contenant les sommets
const sommets = new FeatureLayer({
    url: "https://services.arcgis.com/d3voDfTFbHOCRwVR/arcgis/rest/services/SeptSommets/FeatureServer/1", // la couche est hébergée en partage public sur ArcGIS Online
    outFields: ["Nom","Altitude","Continent","Description","Annee"],
    popupTemplate: popup, //référence aux popups créées plus haut
    renderer: symbo, //référence à la symbologie créée plus haut
    labelingInfo: [ //configuration des labels
        new LabelClass({
            labelExpressionInfo: { expression: "$feature.Nom" },
            labelPlacement: "center-right",
            symbol: new LabelSymbol3D({
                symbolLayers: [new TextSymbol3DLayer({
                    material: {
                        color: [250, 250, 250] //couleur du texte des labels (ici blanc)
                     },
                    background: { color: [40,36,36] }, //couleur du fond des labels (ici noir)
                    font: { //police des labels
                        size: 12,
                        family: `"Avenir Next", "Avenir", "Helvetica Neue", sans-serif`,
                        weight: "bolder"
                    }
                })]
            })
        })
    ]
});
map.add(sommets); //ajout de la couche de sommets à la carte

Notez qu'au fur et à mesure, nous avons ajouté individuellement les couches après leur référencement avec la méthode add() appliquée à la carte. Sachez qu'il est possible de les ajouter toutes en une seule fois dans un tableau grâce avec la méthode addMany() ou directement dans le constructeur de la carte avec la propriété layers.


Ajustements esthétiques

Nous allons enfin ajouter les fonctions permettant de faire tourner la planète et de rendre les nuages plus transparents lors du zoom pour éviter qu’ils ne gênent.

//Fait tourner la planète tant que l'utilisateur n'interagit pas avec l'app        
function rotate() { 
    if (!view.interacting) {
      const camera = view.camera.clone(); //crée un clone "camera" de la caméra actuelle
      camera.position.longitude -= 0.25; //enlève 0.25 degrés de longitudes au clone de la caméra (mettre un signe + pour que la planète tourne dans le sens inverse à son sens de révolution)
      view.goTo(camera, { animate: true }); //centre la vue sur le clone de la caméra, càd l'ancienne postition -0.25 degrés de longitude (ce qui donne donc l'impression que la planète bouge de 0,25° de lontitude)
      requestAnimationFrame(rotate); //indique que l'on souhaite exécuter une animation et utilise rotate en fonction de rappel, qui sera appelée avant le rafraîchissement du navigateur (la fonction va donc boucler)
    }
  }       
 reactiveUtils.when( //permet d'appeler la fonction rotate tant que la vue n'est pas mise à jour, ici tant que l'utilisateur n'interagit pas avec l'app
    ()=>!view.updating,
    ()=>{
     rotate();
     },
     {
     once : true //à supprimer pour que la planète reprenne sa rotation après interaction
    });



//Rend les nuages transparents au zoom
reactiveUtils.when(
    () => Math.floor(view.zoom), 
    (value) => {
        if (value) {
        cloudsLayer.opacity = 0.02 * Math.pow(value - 10, 2);
        }
  });

La toute dernière étape consiste à supprimer les widgets automatiquement ajoutés par l’API (NavigationToggle, Zoom et Compass), pour épurer l’interface.

//retrait des widgets présents par défaut pour épurer l'ui        
view.ui.remove("navigation-toggle");  
view.ui.remove("zoom");
view.ui.remove("compass"); 

Mot de la fin

Et voilà, le code JavaScript de l’application est terminé ! N’hésitez pas à aller jeter un coup d’œil au code de l’application « The Five Deeps », également disponible sur Github. Vous verrez que nous en avons repris les éléments essentiels en les simplifiant pour cet article, mais le code original vous permettra de voir comment l’API Javascript d'ArcGIS peut être intégrée au sein d’un code plus poussé, avec un important travail sur le style.

A bientôt pour un nouvel article, qui devrait cette fois-ci parler de l'ArcGIS API for Python !

 


 

Aucun commentaire:

Enregistrer un commentaire