Pendant tout le mois de novembre a lieu un challenge palpitant, le
#30DayMapChallenge. Avec quelques-uns de mes collègues, nous avons décidé de former une petite
équipe pour relever ce défi ensemble ! Il revient à chacun d'entre nous de
réaliser 3 cartes, et pour ma part, j'ai décide de faire chacune d'entre elles
en y ajoutant une petite touche de JavaScript ou de Python.
La première de mes cartes est celle du jour 4, sur le thème Hexagones.
L'occasion d'explorer une thématique assez commune, les données d'élévation,
sous une forme originale. Dans cet article, je vous propose de découvrir cette
carte, mais aussi d'apprendre à réaliser la même chose par vous-même à travers
un tutoriel détaillé (qui utilisera notamment l'API JavaScript d'ArcGIS, mais à un niveau très accessible).
L'application
Voici l'application que j'ai créée, que vous pouvez
consulter en pleine page
pour un meilleur confort. J'aime beaucoup le rendu de cette carte, qui me fait
penser notamment au
jeu de plateau Catan, que je vous conseille fortement si vous souhaitez perdre tous vos amis.
Puisque l'application est interactive, il est très aisé de se promener Ã
l'intérieur pour obtenir des points de vue sur les différents massifs
montagneux, comme je l'ai fait pour réaliser le poster ci-dessous :
Maintenant, restez avec moi si vous souhaitez reproduire ce tutoriel pour
recréer votre propre carte, ce qui vous permettra de la personnaliser par
exemple à l'échelle de votre région ou avec les couleurs de votre choix !
Le tutoriel
1/ Préparation et publication des données
Dans cette première étape, je vais vous expliquer comment j'ai transformé la
donnée de base dans
ArcGIS Pro
et comment je l'ai publiée afin de pouvoir l'utiliser en donnée d'entrée pour
mon application. Si vous n'avez pas ArcGIS Pro ou que vous n'êtes intéressé
que par le code, vous pouvez passer directement à la deuxième partie ou je
vous donne le lien direct vers la donnée finale prête à être utilisée.
Dans un premier temps, j'ai récupéré le
MNT de la France métropolitaine et de la Corse sur data.gouv.fr, publié à partir des données SRTM de la NASA. Cette donnée est fournie au format .TIF. C'est donc un raster, donc chacune
des cellule contient la moyenne d'élévation de la zone, que j'ajoute dans
ArcGIS Pro.
La donnée étant trop résolue par rapport à mon besoin, je vais commencer par
rééchantillonner
le raster en donnant des nouvelles valeurs de X et de Y égales à 0,01. Ainsi,
je vais dégrader la résolution et obtenir des temps de traitement plus
rapides.
J'utilise ensuite l'outil
Raster vers points
qui me permet de transformer cette donnée raster en donnée vecteur, en plaçant
un point contenant la valeur d'élévation de chaque cellule au milieu de ladite
cellule.
Enfin, je vais pouvoir
agréger les points
en groupes d'hexagones de 10 kilomètres. J'indique que chaque hexagone doit
retourner comme valeur la moyenne d'élévation de tous les points contenus dans
la zone.
[Note : L'information d'élévation est contenue dans le champ grid_code].
J'ai réalisé ce workflow sur les données de la France entière, mais j'ai zoomé
dans une petite partie des Alpes pour l'illustration ci-dessous :
Il est maintenant temps de publier mes données afin de pouvoir les partager en
ligne. Vous devez pour cela posséder des privilèges de publication sur votre
portail ArcGIS Online ou Enterprise. Retirez toutes les couches sauf la couche
d'hexagones de votre projet, puis allez dans l'onglet Partager et sélectionnez
l'option carte web afin de partager vos données sur le portail. Vous
rencontrerez d'éventuels messages d'erreur lors du partage, qui sont tous
résolvables en suivant les indications renvoyées par le message.
2/ Code
Je vais maintenant pouvoir créer une application pour permettre au grand
public d'explorer les données que je viens de publier, et pour cela, je vais
utiliser l'API JavaScript d'ArcGIS. Cette API va me permettre à la fois de travailler en 3D (très utile ici
pour bien représenter l'élévation), de modifier le style de symbologie, et de
permettre une navigation fluide dans les données, le tout avec un effort de
développement très faible. L'API est accessible gratuitement, alors n'hésitez
pas la à tester !
Tout le code que je vais vous présenter est comme d'habitude disponible
sur mon Github, et vous pouvez également le tester de manière interactive dans
ce CodePen
si vous ne souhaitez pas le recopier de zéro. 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 unique balise <viewDiv>
qui
contiendra la vue de ma carte.
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>
France | Élévation
</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>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
Côté CSS, je m'assure simplement que la taille de la
<viewDiv>
prendra l'entièreté de l'écran.html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
position: absolute;
}
Il est maintenant temps de faire appel à l'API JavaScript pour insérer notre
carte !
Comme d'habitude, je commence par appeler les classes qui me seront utiles
dans le require (ici, Map, SceneView et
FeatureLayer), 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/Map",
"esri/views/SceneView",
"esri/layers/FeatureLayer",
], function (
Map,
SceneView,
FeatureLayer,
) {
//le reste du code ira ici
});
Je crée ensuite une instance de
Feature Layer, dont l'url
renvoie vers le service publié à l'étape précédente.
const elevLayer = new FeatureLayer({
url:
"https://services.arcgis.com/d3voDfTFbHOCRwVR/arcgis/rest/services/Altitudes_hexagones_WFL1/FeatureServer/1",
copyright: "SRTM - NASA",
outFields: ["*"],
elevationInfo: {
mode: "relative-to-ground"
}
});
Si vous n'avez pas publié votre propre service, vous pouvez utiliser la même
url que moi. Sinon, pour retrouver l'url de votre service, rendez-vous sur
l'item correspondant au Feature Layer hébergé, puis scrollez jusqu'à atteindre
l'URL comme ci-dessous :
Ouvrez le lien dans une nouvelle fenêtre, puis dans la section Layers, cliquez
sur la couche correspondant à votre couche d'hexagones (qui devrait être la
seule). Vous pouvez alors copier l'url et le remplacer dans le code.
Notez également que j'utilise la propriété
elevationInfo
afin de spécifier de quelle manière les entités seront placées par
rapport à la surface de ma scène 3D. Ici, nous utilisons le
mode "relative-to-ground"
.
Je vais ensuite définir le
Renderer
de la couche, c'est-à -dire son rendu, la manière dont elle sera représentée et
ce qui lui permettra de véhiculer l'information que je souhaite. Différents
types de rendus sont possibles, ici, je vais utiliser un rendu simple (SimpleRenderer
) associé à des variables visuelles (visualVariables
).
elevLayer.renderer = {
type: "simple",
symbol: {
type: "polygon-3d",
symbolLayers: [
{
type: "extrude"
}
]
},
visualVariables: [
{
type: "color",
field: "Altitude_moyenne",
stops: [
{ value: -12, color: "#A1B696" },
{ value: 500, color: "#FCD170" },
{ value: 1000, color: "#647F2F" },
{ value: 1500, color: "#60562D" },
{ value: 2000, color: "#815F5B" },
{ value: 2500, color: "#DBCDCB" }
]
},
{
type: "size",
field: "Altitude_moyenne",
stops: [
{ value: 0, size: 1 },
{ value: 3300, size: 100000 }
],
axis: "height"
}
]
};
Pour construire ce rendu, je commence par indiquer que le
type
de rendu utilisé est "simple
" pour un
SimpleRenderer
. Je dois ensuite définir le
symbole
utilisé. Puisque je travaille en 3D sur une donnée polygonale, je vais
utiliser la classe
PolygonSymbol3D
, et j'indique pour cela que le
type
de symbole est "polygon-3d
". Je peux ensuite indiquer le
symbolLayers
, permettant de définir la manière dont les objets seront visualisés. Ici,
nous définirons le
type
sur "extrude"
afin d'obtenir une extrusion 3D.
Enfin, pour faire varier la couleur et la hauteur de l'extrusion selon
l'altitude moyenne de l'hexagone, je vais me baser sur des
visualVariables
.
La première sera une
ColorVariable
pour faire varier la couleur. J'indique cela en paramétrant le
type
sur "color"
, puis je défini le champ (field
) selon lequel la couleur devra varier, chez moi Altitude_moyenne qui
contient l'altitude. Je peux ensuite indiquer les
stops
, qui sont un array contenant des valeurs clés auxquelles j'attribue des
valeurs précises. Ici par exemple, je définis 12 valeurs d'altitudes qui
prendront une couleur particulière que je passe avec sa valeur hexadécimale
(j'aurais également pu utiliser du rgb). Entre ces valeurs, l'API va
déterminer automatiquement une rampe de couleurs pour attribuer des couleurs Ã
chacun de mes polygones.
Je répète l'opération une seconde fois en utilisant cette fois-ci une
SizeVariable
, pour cette fois-ci faire en sorte que la hauteur d'extrusion de mes
polygones soit plus importante à mesure que leur valeur d'altitude augmente.
Voilà , le plus dur est fait ! Afin d'afficher cette couche, je crée maintenant
une instance de carte (
Map
) dans laquelle je passe dans la propriété
layers
la couche que je viens de paramétrer juste avant. Je vais ensuite paramétrer
le
Ground
afin d'empêcher la navigation sous la carte avec la propriété
navigationConstraint
paramétrée sur "stay-above", et j'indique également que je ne souhaite pas
qu'il soit visible en réglant son opacité (opacity
) sur 0.
var map = new Map({
layers: [elevLayer],
ground: {
navigationConstraint: {
type: "stay-above"
},
opacity: 0
}
});
Afin de pouvoir voir ma carte, je vais devoir afficher celle-ci dans une
SceneView
, qui me permet de générer une vue 3D interactive de ma carte.
var view = new SceneView({
container: "viewDiv",
map: map,
camera: {
heading: -5,
tilt: 50,
position: {
latitude: 27.5,
longitude: 5,
z: 2300000,
spatialReference: { wkid: 3857 }
}
},
viewingMode: "local",
environment: {
background: {
type: "color",
color: "#212526"
},
atmosphereEnabled: false,
starsEnabled: false
}
});
Je commence par indiquer le
container
, la balise de mon HTML dans laquelle la carte sera affichée, ici "viewDiv"
comme nous l'avons défini au tout début du tutoriel. J'indique également que
la carte (map
) sur laquelle je génère la vue est la carte créée juste ci-dessus.
Je dois ensuite placer la
camera
, qui donnera l'angle initial avec lequel je dois virtuellement filmer ma
carte. Pour cela, je définis une orientation par rapport au Nord (heading
), une inclinaison (tilt
), la
position
constituée de la longitude
, de la latitude
et de l'élévation (z
) ainsi qu'une
référence spatiale (spatialReference
).
Je peux également déterminer qu'il s'agit d'une scène locale grâce au
viewingMode
, et modifier l'environment en choisissant une couleur
d'arrière-plan (background
) ainsi qu'en supprimant l'atmosphère et les étoiles
présentes par défaut.
Enfin, je retire également les widgets de l'interface utilisateurs présents
par défaut afin d'épurer l'application au maximum.
view.ui.remove([ "compass", "zoom","navigation-toggle"]);
Et voilà , vous avez votre carte interactive ! Vous pouvez désormais ajuster
l'HTML et le CSS afin d'obtenir plus d'éléments d'interface, par exemple un
titre ou des crédits, comme je l'ai fait pour mon application. Si vous avez
besoin d'un coup de pouce ou du code complet, n'hésitez pas à nouveau à consulter le code complet
sur mon Github
ou dans
ce CodePen.
Si cet article vous a plus, n'hésitez pas à retrouver les tutoriels de
mes deux autres créations cartographiques pour ce challenge : une animation sur les variations d'étendues de l'Arctique, et une carte d'isohypses pour représenter les concentrations des photos que j'ai prises dans ma ville.
Aucun commentaire:
Enregistrer un commentaire