Dessiner un Cercle sur une Carte avec OpenLayers et jQuery UI

En écrivant ce titre, je me suis rappelé qu’enfant, il était déjà plus difficile de dessiner un cercle plutôt qu’une ligne. L’aide d’un accessoire était même indispensable pour déterminer le rayon souhaité. Représenter un cercle sur une cartographie en ligne est possible en utilisant différentes méthodes mais dans ce tutoriel, on s’appuie sur un outil appelé slider afin de contrôler les dimensions de la figure. L’objectif est de permettre à l’utilisateur de choisir un lieu qui représente le centre du cercle et de régler la longueur du rayon. La vidéo ci-dessous montre le résultat obtenu.

 

Dans un premier temps, les outils utilisés sont présentés puis on créé méthodiquement l’interface de WebMapping.

1. Outils utilisés pour dessiner le cercle

Dans ce tutoriel, on utilise deux API : celle d’OpenLayers pour la partie cartographique et jQuery UI (User Interface) pour le slider.

OpenLayers, déjà pris en exemple à de nombreuses reprises, continue son évolution et en est à sa version 4.6.4 lors de l’écriture de ce post.

C’est la première fois que je vous parle de jQuery UI et pour ceux qui ne connaissent pas, je vous conseille d’aller sur leur site internet bien documenté. Cette librairie s’appuie sur jQuery et permet d’ajouter de nombreuses fonctionnalités pour les utilisateurs telles des interactions (ordre et déplacement de contenu, etc), des widgets (calendrier, auto-complétion, etc), des effets (ajout de classes, etc) et quelques utilitaires. On peut par exemple réaliser des interfaces de WebMapping relativement poussées avec la manipulation des ordres des couches :

 

Ici, on s’intéresse au widget slider pour lequel de nombreux exemples sont mis à disposition. De plus, on utilise Bootstrap (v4) et Font Awesome pour les icons.

2. Construction de l’Interface de WebMapping

2.1. Mise en place basique de l’Interface

Les différentes API utilisées sont chargées puis on s’occupe de l’ergonomie de l’interface en disposant les différents blocs. Basiquement, on a :

<!DOCTYPE html>
<html>
	<head>
		<title>Dessin d'un Cercle sur une Carte avec un Slider</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
		<link rel="stylesheet" href="https://openlayers.org/en/v4.6.4/css/ol.css" type="text/css">
		<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
		<!-- Bootstrap core CSS -->	
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css">
		<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">	
	</head>
	<body class="bg-dark">
		<div class="container-fluid text-light">
			<div class="row">
			</div> <!-- ./ row -->
			<div class="row">
			</div> <!-- ./ row -->
		</div> <!-- ./ container-fluid -->
		<!-- jQuery, puis Popper.js, puis Bootstrap JS -->
		<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
		<script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
		<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
		<script src="https://openlayers.org/en/v4.6.4/build/ol.js"></script>
	</body>
</html>

Ici, les fichiers CSS sont placés dans le <head> et les fichiers JavaScript en bas du <body> pour un chargement plus rapide. Dans cet exemple, ils sont appelés via un URL mais vous pouvez aussi construire votre interface via Browser ou NPM.

La carte est ensuite développée en JavaScript en choisissant de la centrer sur des coordonnées géographiques prédéfinies et transformées en projection EPSG:3857. On y ajoute le fond de carte OpenStreetMap.

<!DOCTYPE html>
<html>
	<head>
		<title>Dessin d'un Cercle sur une Carte avec un Slider</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
		<link rel="stylesheet" href="https://openlayers.org/en/v4.6.4/css/ol.css" type="text/css">
		<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
		<!-- Bootstrap core CSS -->	
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css">
		<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">	
		<style>
			.map{
				width: 100%;
				height: 500px;
			}
		</style>
	</head>
	<body class="bg-dark">
		<div class="container-fluid text-light">
			<div class="row">
				</div> <!-- ./ col-lg-8 -->
			</div> <!-- ./ row -->
			<div class="row">
				<div class="col-lg-8 mx-auto map" id="map"></div>
			</div> <!-- ./ row -->
		</div> <!-- ./ container-fluid -->
		<!-- jQuery, puis Popper.js, puis Bootstrap JS -->
		<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
		<script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
		<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
		<script src="https://openlayers.org/en/v4.6.4/build/ol.js"></script>
		<script>
			latIni = 48;
			lonIni = 2;
			// Couche OpenStreetMap
			var osm = new ol.layer.Tile({
				source: new ol.source.OSM(),
			});
			// Déclaration de la carte
			var map = new ol.Map({
				layers: [osm],
				target: 'map',
				view: new ol.View({
					center: ol.proj.transform([lonIni,latIni], 'EPSG:4326', 'EPSG:3857'),
					zoom: 10
				}),
			});
		</script>
	</body>
</html>

Passons à la programmation du slider.

2.2. Fonctionnement du Slider

Le slider est basé sur une fonction de jQuery appelé slider $('#div').slider({}) liée à l’id de la div (ici : #slider ) où l’on souhaite placé l’outil. Dans cette fonction, on déclare les options et les évènements du widget détaillés sur le site de l’API pour le fonctionnement de l’interface. En ce qui concernent les options, on choisit une échelle de valeurs avec une valeur minimale, une valeur maximale et une valeur de départ qui pourrait être autre que zéro. L’événement slide est choisi pour montrer la valeur indiquée (ui.value) par le curseur du slider. On a :

<!DOCTYPE html>
<html>
	<head>
		<title>Dessin d'un Cercle sur une Carte avec un Slider</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
		<link rel="stylesheet" href="https://openlayers.org/en/v4.6.4/css/ol.css" type="text/css">
		<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
		<!-- Bootstrap core CSS -->	
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css">
		<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">	
		<style>
			.blocSlider{
				padding: 30px;
			}
			#inputSlider{
				border:0; 
				color:#f6931f; 
				font-weight:bold;
			}
			#slider{
				margin: 20px 0;
			}
			.map{
				width: 100%;
				height: 500px;
			}
		</style>
	</head>
	<body class="bg-dark">
		<div class="container-fluid text-light">
			<div class="row">
				<div class="col-lg-8 mx-auto blocSlider text-center">
					<label for="inputSlider"><i class="fa fa-circle-o"></i> RAYON DU CERCLE <i class="fa fa-caret-right"></i></label>
					<input type="text" class="bg-dark" id="inputSlider" readonly>
					<div id="slider"></div>
				</div> <!-- ./ col-lg-8 -->
			</div> <!-- ./ row -->
			<div class="row">
				<div class="col-lg-8 mx-auto map" id="map"></div>
			</div> <!-- ./ row -->
		</div> <!-- ./ container-fluid -->
		<!-- jQuery, puis Popper.js, puis Bootstrap JS -->
		<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
		<script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
		<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
		<script src="https://openlayers.org/en/v4.6.4/build/ol.js"></script>
		<script>
			// Valeurs du Slider 
			min = 0;
			max = 10000;
			ini = 0;
			var divSlider = $( "#inputSlider" );
			latIni = 48;
			lonIni = 2;
			$(function() {
				// Fonction slider liée à la Div
				$( "#slider" ).slider({
					// Options
					range: "min",
					value: ini, // $( "#slider" ).slider("value")
					min: min,
					max: max,
					// Events
					slide: function( event, ui ) {
						divSlider.val( ui.value + " / " + max + " m" );
					},
				});
				divSlider.val( ini + " / " + max + " m" );
			});
			// Couche OpenStreetMap
			var osm = new ol.layer.Tile({
				source: new ol.source.OSM(),
			});
			// Déclaration de la carte
			var map = new ol.Map({
				layers: [osm],
				target: 'map',
				view: new ol.View({
					center: ol.proj.transform([lonIni,latIni], 'EPSG:4326', 'EPSG:3857'),
					zoom: 10
				}),
			});
		</script>
	</body>
</html>

On renvoie les valeurs indiquées avant et après l’évènement dans le bloc HTML correspondant (ici : #inputSlider). L’interaction entre l’évènement du slider et la cartographie est détaillée dans la section suivante.

2.3. Dessine-Moi un Cercle

Avant de mettre en œuvre l’interaction entre le widget et la cartographie, il est bon de discuter de la géométrie liée au cercle. Comment dessiner un cercle sur une carte dans OpenLayers?

Veuillez vous Connecter pour consulter ce contenu. S'Inscrire Gratuitement ››

En conclusion, grâce aux API d’OpenLayers et de jQuery UI, l’interface créé permet à l’utilisateur de dessiner un cercle (buffer) avec les choix du lieu et de la longueur du rayon. De nombreuses améliorations sont possibles pour améliorer cette interface:

  • On peut penser par exemple à la saisie des longitudes et latitudes directement dans les inputs qui provoquerait le centrage de la carte sur ces nouvelles coordonnées géographiques.
  • D’autres évènements pourraient être implémentés dans la fonction slider tel stop, ce qui permettrait à l’arrêt du curseur de générer de nouvelles fonctions liées à la géométrie spatiale créée. L’enregistrement du vecteur pourrait être issu d’une de ses fonctions ou encore l’intersection entre le buffer et d’autres vecteurs.
Taggé , , .Mettre en favori le Permaliens.

A propos Florian Delahaye

Fondateur et Administrateur de Geomatick. Consultant en Géomatique. Docteur en Géographie, Spécialités en SIG et Télédétection.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *