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
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.
COMMENTAIRES
DIOUCK ABDOU
Bonjour
C'est tres enrichissant votre tuto. Selement j'essaye d'adapter votre requete ajax pour convertir un api json en geojson.
http://data.nantes.fr/api/p....
Avez vous une idée pour une itégrtion dans leaflet?
Merci de votre compréhension
Voici la syntaxe
$.ajax({
async: false,
url: 'http://data.nantes.fr/api/p...,
type: 'POST',
dataType:"json",
header: {'Access-Control-Allow-Origin': 'http://data.nantes.fr/'},
crossDomain: true,
success: function(json) {
local=json;
}
}).complete(function () {
var urlvar = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
urlvar[key] = value;
});
if (urlvar.hasOwnProperty('x') && urlvar.hasOwnProperty('y') && urlvar.hasOwnProperty('z')) {
map.setView([parseFloat(urlvar['y']), parseFloat(urlvar['x'])], parseInt(urlvar['z']));
}
});
var test=new L.geoJson(local, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng, {
icon: L.AwesomeMarkers.icon({
icon: 'home',
color: 'cadetblue',
//spin: true
prefix:'fa'
}),
title: feature.properties.nom_comple
});
} ,
onEachFeature:onEachFeature
});
ericfrigot
Bonjour,
Merci pour le compliment. Concernant vos données, que voulez-vous en faire ? Les mettre sur un carte pour faire des marqueurs ? Si c'est le cas vous devriez d'abord récupérer votre fichier JSON et le lire comme je le fais dans les tutoriels de la section "Maps". Si vous m'en dites un peu plus sur votre objectif, je pourrais surement vous aider. Sinon merci de m'avoir fait décrouvrir AwesomeMarkers, je ne connaissais pas.
Eric
DIOUCK ABDOU
Bonjour
Oui en effet au lieu de telecharger la donnée, l'idée c'est de requetter directement l'API de l'open data de Nantes et les afficher sur une carte leaflet. j'ai dea fait des tentatives pour le parser en php en vain. Mais ton tuto m'a tres l'air plus adapté pour le faire
ericfrigot
J'ai fait ça : http://datavis.fr/playing/l...
Le truc c'est que pour éviter les problèmes de cross domain j'ai directement inclus les données dans mon code javascript, mais je ne sais pas si ça vous conviendra.
Eric
DIOUCK ABDOU
Oui super intéressant ca rend la même chose si on télécharge les données en shp ou csv. Mais les données sont mise à jour régulièrement. Et c'est donc pour éviter de les telecharger que je cherche à requêter directement via l'API. Je ne sais pas si c'est assez claire .
ericfrigot
Bonjour, si vous voulez que les données soient mises à jour j'imagine que vous travaillez dans un contexte professionnel. Dans ce cas là la meilleure solution c'est d'utiliser un serveur Proxy et avec Apache c'est très facile à mettre en œuvre (par exemple : http://stackoverflow.com/qu....
DIOUCK ABDOU
En faite les données sont mise à jour non pas par moi mais par le site.
Sinon c'est superbe votre doc, ce n'est pas dans le cadre pro c'est juste pour se former sur l'appel des api.
Sinon j'ai repris votre exemple en rajouter un lien php qui appelle directement la donnee:
Même si ca ne resoud pas totalement le problème ça me depane un peu. Reste plus qu'a rajouter les popup