Simulation de crue à Paris

Google Elevation API, Leaflet et D3JS

Dernière mise à jour le 23/06/2018
d3js3.x leaflet0.7.3 jquery1.9.1

Introduction

La cartographie, accessible en cliquant sur l’image ci-dessus, est composée de 13022 points géolocalisés dans la ville de Paris. En plus de la latitude et de la longitude, chaque point possède la valeur de son élévation. A partir de ces données nous construisons une surcouche qui agrège les points sous la forme d’hexagones. A chaque hexagone est attribué une couleur en fonction de l’altitude moyenne des points qui le composent. Enfin, si l’altitude calculée d’un hexagone est inférieure à la hauteur de crue sélectionnée alors cet hexagone sera bleu. Les hexagones sont recalculés à chaque fois que le niveau de zoom sur la carte change. Nous verrons dans les parties suivantes comment construire ces données et les mettre en œuvre au travers d’une librairie Leaflet quelque peu adaptée pour notre besoin.

Construction de la carte et délimitation de la ville de Paris

Nous commençons par représenter le fichier geoJSON departement.json sur une carte Leaflet. Par simplicité celui-ci est intégré dans le fichier departement.js.

var map = L.map('map1').setView([48.85841, 2.3488], 12);

var stamenToner = L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.png', {
	attribution: 'Map tiles by Stamen Design, CC BY 3.0 - Map data © OpenStreetMap',
	subdomains: 'abcd',
	minZoom: 0,
	maxZoom: 20,
	ext: 'png'
});

map.addLayer(stamenToner);

/* L'attribut department provient du fichier JS et contient le geoJSON */
var gjLayer = L.geoJson(departement, {style: style}).addTo(map);

function style(feature) {
	return {
		weight: 4,
		opacity: 1,
		color: '#1f8dd6',
		dashArray: '8',
		fillOpacity: 0
	};
}

Génération des coordonnées

Nos données représentent l'ensemble des points contenus dans la ville de Paris espacés d'un pas constant. Pour cela nous parcourons le rectangle contenant la ville de Paris (il nous sert de bornes min & max) et nous utilisons la librairie leaflet-pip qui permet de savoir si un point est dans un polygone pour Leaflet. Le pas choisi ici est de 0.01 tant pour la latitude que pour la longitude. Pour générer nos données il était de 0.001, beaucoup plus précis donc.

var lat = gjLayer.getBounds().getSouth();
var lng = gjLayer.getBounds().getWest();
var limLat = gjLayer.getBounds().getNorth();
var limLng = gjLayer.getBounds().getEast();
while (lat  <= limLat) {
	// lat et lng sont inversées
	if (leafletPip.pointInLayer([lng, lat], gjLayer).length != 0) {
		L.marker([lat, lng]).addTo(map);
	}
	lng += 0.01;
	if (lng > limLng) {
		lat += 0.01;
		lng = gjLayer.getBounds().getWest();
	}
}

Récupération d'altitude via Google Elevation API

En utilisant JQuery pour effectuer une requête il est très facile de récupération l'élévation avec l'API de Google. En revanche avec une clé gratuite, on est limité à la fois en nombre de requêtes par jour et à la fois dans un laps de temps donné. A partir de ce code nous avons pu construire le fichier locations.js qui contient les 13022 points utilisés dans notre visualisation.

$.ajax({
	url: 'https://maps.googleapis.com/maps/api/elevation/json?locations=' + lat + "," + lng + '&key=YOUR_API_KEY',
	type: 'GET',
	dataType: "json",
	header: {'Access-Control-Allow-Origin': 'https://maps.googleapis.com/'},
	crossDomain: true,
	idx: i,
	success: function (data) {
		if (data.status == 'OVER_QUERY_LIMIT') {
			// Trop de requêtes effectuées
		} else {
			// data.results[0].elevation contient l'élévation
		}
	},
	error:function (response) {          
		// response contient une erreur
	}
});

Création des hexagones

La création des hexagones nécessites deux librairies JS toutes deux trouvées sur ce site : Hexbins and D3 Map. La première permet la construction mathématiques des hexagones : hexbin.js. La seconde représente un Layer que l'on peut ajouter à une carte Leaflet. Ce Layer utilise bien sur la première librairie : leaflet-hexbin.js.

Modification de librairie

Info: La librairie leaflet-hexbin.js a été modifié pour rendre facultative la gestion de la souris et pour autoriser la mise à jour du style lorsque l'utilisateur change la hauteur de crue.

Pour construire les hexagones nous commençons par convertir le fichier location.js au format geoJSON (c'est le format qu'utilise la librairie leaflet-hexbin.js).

function reformat(locations) {
	var data = [];
	locations.map(function (d){
		data.push({
			properties: {
				alt: +d.alt
			}, 
			type: "Feature", 
			geometry: {
				coordinates:[+d.lng, +d.lat], 
				type:"Point"
			}
		});
	});
	return data;
}
var geoData = { type: "FeatureCollection", features: reformat(/*locations.js*/locations) };

Nous construisons un scale pour associer la plage d'altitude avec notre plage de couleurs.

var scale = d3.scale.linear()
	.domain([d3.min(locations, function(d) { return d.alt; }),
		 d3.max(locations, function(d) { return d.alt; })])
	.range(["#5eb95e", "#dd514c"]);

Enfin nous construisons notre Layer en commençant par définir la fonction hexbinStyle qui déterminera la couleur de chaque hexgone. Si l'altitude moyenne de l'hexagone est inférieure à la hauteur de crue, alors il est bleu sinon on utilise la fonction scale. L'option mouse dans la construction du Layer permet de gérer une action lorsque l'on clique sur l'hexagone.

function hexbinStyle(hexagons) {
	hexagons
		.attr("stroke", "black")
		.attr("fill", function (d) {
			if (d[0][2].alt <= currentAltitude) {
				return "#1f8dd6";
			}
			var avg = d3.mean(d, function(d) {
				return +d[2].alt;
			})
			return scale(avg);
		});
}

var hexLayer = L.hexbinLayer(geoData, {
		style: hexbinStyle,
		//mouse: makePie
	}).addTo(map);

Pour la gestion des commandes vous pouvez jeter un oeil au code source, il n'y a rien de compliqué. Lorsque l'utilisateur fait varier la hauteur de crue nous appelons la fonction hexLayer.updateStyle() pour mettre à jour les couleurs de chaque hexagone.

comments powered by Disqus