// ---- Variables Globales
var road2Url = "https://wxs.ign.fr/calcul/geoportail/isochrone/rest/1.0.0/isochrone?";
var oldUrl = "https://wxs.ign.fr/calcul/isochrone/isochrone.json?"
var map;
var clickedPoint = new Array();
var loader = document.getElementById("loading");
loader.classList.add('not_displayed');
// -- Variables par défaut que l'utilisateur peut modifier
var defaultResource = "bdtopo-pgr";
var defaultProfile = "car";
var defaultCostType = "time";
var defaultDirection = "departure";
var defaultGraphName = "Voiture";
var defaultMethod = "time";
var defaultReverse = "false"
// --
// -- Variables pour la carte
// Vecteurs qui vont contenir les éléments de l'itineraire sur la carte
var vectorRoad = new ol.source.Vector();
var vectorRoadOther = new ol.source.Vector();
var vectorPoint = new ol.source.Vector();
// Couches de la carte qui vont afficher l'itinéraire
var vectorRoadLayer = new ol.layer.Vector({
source: vectorRoad
});
var vectorRoadOtherLayer = new ol.layer.Vector({
source: vectorRoadOther
});
var vectorPointLayer = new ol.layer.Vector({
source: vectorPoint
});
// Styles pour les marqueurs
var styles = {
routePolyline: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6, color: [200, 40, 40, 0.8]
})
}),
routeWkt: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6, color: [40, 40, 40, 0.8]
})
}),
icon: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAsCAYAAAAATWqyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABB5JREFUeNq8WFtLVFEUXkdNpwsVmhVGlGGaJihU2lMgRj1I2KO9SQ9JEZSh0R8IgsSHEtLsN1RaEUE95JOalCYVSCbdENIeEo0ya7W+s2f2Po7O2ec4M37wMXvOXpfv7NmXNduhEGDmQvmoEx4R7hfuEq6Pds8JPwrfCPuEjxzHmaBUQZI7whPC5xwez6O+ji2PYxFRKR+3hIc9D4mGh4kGBog+fCCanlbPt2wh2rOHqLqaqFLcnEWh+4VnZYSGVzISzcJ5/W6fPjFfusS8fTuk+BM2sIWPAWI1hxGQKbyt3WdnVdDsbLuAeMIHvohhgNiZQeZDt3YZHWXeuze8gHgiBmIZdPvOG+ls1aZ9fcybNiUvIkbEQkyD1kQiqoQLrsnISGpFeMUgtgJyVcWLyBC+dLtnZpiLilIvIkbERg4F5MzwCmnQA3bhQvpExIgcBg16H5EvL+TjIE3IRlhcTLSwYF9eO3cS1dcre2BsjKinh+jzZ7tvVpayL8RGTUOyvxyCiDKt7eJF+9tEIswdHfILLyzdR/EMfbCxxUEugzIIaXGbf/8yb93q75yTEz/zlwdsYOsXC7mQU6EFQnrd5tCQ/S2uXw9+ysDWFg85FXohZNxtdnX5O23ezPz7d3AhsIWPX0zkVBjH0ilwJ9D79/4T7OhRouzs4IcVbOHjB5OzAEIibnNmxt9JzfBwsPmYnBGzmWzY4O80OxteiM3HkxNCfritvDx/p5GR8EJsPibnDwgZd5ulpf5O/f1qEwoK2MLHDybnOOnaY2pKDmbHf5YfO+Zd+4kBG9j6xUIu5IzWKBBySgeoqrKv/dOnpdaaTywCfbCxxUEug1MQslH4U5Ur3cEOrYoK5rt3mX/9MqHQxjP0BYnRresv5N4YO33v6LfZvTv4KYozpaREMcj5EiNymFG94y0DpEjgP+7j+/fTXwYghwJyFsUXR+16mBsb0ycCsQ3alysV1wnHdOWejiqtuNhb0SPXukR160H9Ew0OMq9ZkzoRiGVOW0yQA7a/FFf0wF27ljohiGVwOcgfLBTSz1zzf/+Ya2qSF1Fbq2IpPF1UMFvE7BB+d92+fGHOzV25iLw85q9fYyKmhQVh//ue1AN5797KhcDXoH6lVxKdOsSZM+FFNDV5RXQmczeCJf3ODTM3x7xvX3ARpaWyef+MiXgrXJvsRU0lKlA33KtX9uo8Vu3DNlq9CitSdWvUrAe4rc0upL3d+5M0U6oQva54okMfP55YBPoMHge5tgorZpvwmxt+cpI5P3+pCDxDnwJst1E6IIHr9Ls+eLC4okP74UPvaNRROiEJbupU588bIWgb3KB0Q5JIBcSvdVVWXq5oqjX0RWg1IInKIUPfs5n7MTwrp9WEJDy3TOl8jlYb0SV9FWVUlFeTWar/BRgA8G9p83hisDUAAAAASUVORK5CYII='
})
})
};
// --
// -- Creation de la carte à la fin du chargement de la page
Gp.Services.getConfig({
apiKey: "essentiels",
onSuccess: createMap
});
// --
// ----
// ---- Création d'un nouveau menu contextuel sur la carte
var contextMenuItems = [
{
text: "Définir point de départ",
callback: definePoint
},
{
text: "Supprimer les données",
callback: cancelUserData
}
];
// ----
// Fonction pour créer la carte
function createMap() {
map = new ol.Map({
target: 'map-isochrone',
layers: [
new ol.layer.GeoportalWMTS({
layer: "GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2"
}),
vectorRoadOtherLayer,
vectorRoadLayer,
vectorPointLayer
],
view: new ol.View({
center: [261223, 6250240],
zoom: 10,
minZoom: 5,
maxZoom: 18,
projection: "EPSG:3857"
})
});
// Création du Layer Switcher
var layerSwitcher = new ol.control.LayerSwitcher({
layers: [
{
layer: vectorRoadLayer,
config: {
title: 'Résultats du nouveau service (rouge)'
}
},
{
layer: vectorRoadOtherLayer,
config: {
title: "Résultats de l'ancien service (noir)"
}
},
{
layer: vectorPointLayer,
config: {
title: 'Toto'
}
}
],
options: {
collapsed: false
}
}) ;
// Ajout du LayerSwitcher à la carte
map.addControl(layerSwitcher);
// Creation du controle
var mpControl = new ol.control.GeoportalMousePosition({
collapsed: true,
displayAltitude: false,
editCoordinates : true,
systems : [
{
crs : 'EPSG:2154',
label : "Lambert 93",
type : "Metric"
},
{
crs : "EPSG:4326",
label : "Géographiques",
type : "Geographical"
},
,
{
crs : "EPSG:3857",
label : "PM",
type : "Metric"
}
],
units : ["DEC","M"]
});
// Ajout du controle à la carte
map.addControl(mpControl);
// Ajout du menu contextuel à la carte
var contextmenu = new ContextMenu({
width: 180,
items: contextMenuItems
});
map.addControl(contextmenu);
hideLayers();
}
// Pour cacher les layers dans le layerswitcher
function hideLayers() {
let layers = document.getElementsByClassName("GPlayerSwitcher_layer");
for (i = 0; i < layers.length; i++){
let layer = layers[i];
console.log(layer.innerText)
if (layer.innerText === "Toto\n100%" || layer.innerText === "Plan IGN v2\n100%") {
layer.style = "display: none";
}
}
}
// ---- Ajouter un point sur la carte
// Fonction utilisée lors d'un clique droit sur la carte
// Il s'agit d'afficher un marqueur et de stocker les coordonnées de ce point
// Et tout cela en intéragissant avec le formulaire des paramètres de l'isochrone
function definePoint(evt) {
// on récupère les coordonnées du point cliqué
let clickedCoordinate = utils.to4326(evt.coordinate);
if (clickedPoint.length !== 0) {
clickedPoint = new Array();
vectorPoint.clear();
cancelMap();
}
// on stocke les coordonnées pour pouvoir lancer un isochrone
clickedPoint.push(clickedCoordinate);
// on affiche ce point sur la carte
utils.createFeature(clickedCoordinate, vectorPoint);
// on lance le calcul d'isochrone
computeIso();
return true;
}
// ----
// ---- Calculer un isochrone
// Cette fonction est appelée lorsque l'on clique sur un des boutons du formulaire
function computeIso() {
// Déclarations
let request = {};
// on récupère les valeurs du formulaire
request.finalPoint = clickedPoint[0];
request.finalCostValue = document.getElementById('userCostValue').value;
// Gestion des points de l'utilisateur
if ( request.finalPoint === "" || request.finalCostValue === "") {
// il n'y a pas de points ou de valeur pour l'isochrone
return false;
}
// -- Gestion des paramètres de l'utilisateur
// Si certains paramètres ne sont pas remplis dans le formulaire, il y a des valeurs par défaut
loadUserParameter(request);
// --
// ---- Requete envoyée au nouveau service
let requestStr = road2Url +
"resource=" + request.finalResource +
"&profile=" + request.finalProfile +
"&costType=" + request.finalCostType +
"&costValue=" + request.finalCostValue +
"&direction=" + request.finalDirection +
"&point=" + request.finalPoint +
"&constraints=" + request.finalConstraint +
"&geometryFormat=geojson";
// On affiche la requete sur la page
let requestDiv = document.getElementById('request');
requestDiv.innerHTML = "<div class='card card-body'><a href='"+ requestStr + "'>"+requestStr+"</a></div>";
// on calcule l'itinéraire
loader.classList.remove('not_displayed');
loader.classList.add('displayed');
fetch(requestStr)
.then(function(response) {
return response.json();
})
.then(function(responseJSON) {
utils.createIso(responseJSON.geometry, "geojson", vectorRoad);
// On affiche la réponse sur la page
let responseDiv = document.getElementById('response');
responseDiv.innerHTML = "<div class='card card-body'><pre>"+ JSON.stringify(responseJSON, undefined, 2) +"</pre></div>";
});
// ----
// ---- Requete envoyée à un autre service
computeOtherRoad(request);
// ----
return true;
}
// ----
// ---- Calculer un itinéraire sur un autre service
function computeOtherRoad(request) {
let otherRequest = {};
// -- Prise en compte des paramètres utilisateurs
mapOtherParameter(request, otherRequest);
// --
let requestStr = oldUrl +
"graphName=" + otherRequest.finalGraphName +
"&method=" + otherRequest.finalMethod +
"&location=" + request.finalPoint +
"&reverse=" + otherRequest.finalReverse +
"&exclusions=" + otherRequest.finalConstraint +
"&srs=EPSG:4326&smoothing=true&holes=true";
if (otherRequest.finalMethod === "time") {
requestStr = requestStr + "&time=" + request.finalCostValue;
} else if (otherRequest.finalMethod === "distance") {
requestStr = requestStr + "&distance=" + request.finalCostValue;
} else {
return false;
}
// on calcule l'itinéraire
fetch(requestStr)
.then(function(response) {
return response.json();
})
.then(function(responseJSON) {
// On affiche l'itinéraire sur la carte
utils.createIso(responseJSON.wktGeometry, "wkt", vectorRoadOther);
loader.classList.add('not_displayed');
loader.classList.remove('displayed');
});
}
// ----
// ---- Charger les paramètres de l'utilisateur
function loadUserParameter(request) {
let constraintObject = {};
// Resource
request.finalResource = defaultResource;
// Profile
request.finalProfile = document.getElementById("userProfile").value;
// CostType
request.finalCostType = document.getElementById("userCostType").value;
// Direction
request.finalDirection = document.getElementById("userDirection").value;
// Constraint
let plural = false;
request.finalConstraint = "";
if (document.forms["iso-form"].elements["banned-highway"].checked) {
constraintObject.constraintType = "banned";
constraintObject.key = "wayType";
constraintObject.operator = "=";
constraintObject.value = "autoroute";
request.finalConstraint = JSON.stringify(constraintObject);
plural = true;
}
if (document.forms["iso-form"].elements["banned-tunnel"].checked) {
if (plural) {
request.finalConstraint = request.finalConstraint + "|";
} else {
plural = true;
}
constraintObject.constraintType = "banned";
constraintObject.key = "wayType";
constraintObject.operator = "=";
constraintObject.value = "tunnel";
request.finalConstraint = request.finalConstraint + JSON.stringify(constraintObject);
}
if (document.forms["iso-form"].elements["banned-bridge"].checked) {
if (plural) {
request.finalConstraint = request.finalConstraint + "|";
}
constraintObject.constraintType = "banned";
constraintObject.key = "wayType";
constraintObject.operator = "=";
constraintObject.value = "pont";
request.finalConstraint = request.finalConstraint + JSON.stringify(constraintObject);
}
}
// ----
// ---- Faire le lien avec l'autre service
function mapOtherParameter(request, otherRequest) {
// Profile
if (document.forms["iso-form"].elements["userProfile"].value !== "") {
if (request.finalProfile === "car") {
otherRequest.finalGraphName = "Voiture";
} else if (request.finalProfile === "pedestrian") {
otherRequest.finalGraphName = "Pieton";
} else {
otherRequest.finalGraphName = defaultGraphName;
}
} else {
otherRequest.finalGraphName = defaultGraphName;
}
// CostType
if (document.forms["iso-form"].elements["userCostType"].value !== "") {
if (request.finalCostType === "time") {
otherRequest.finalMethod = "time";
} else if (request.finalCostType === "distance") {
otherRequest.finalMethod = "distance";
} else {
otherRequest.finalMethod = defaultMethod;
}
} else {
otherRequest.finalMethod = defaultMethod;
}
// Direction
if (document.forms["iso-form"].elements["userDirection"].value !== "") {
if (request.finalDirection === "departure") {
otherRequest.finalReverse = "false";
} else if (request.finalDirection === "arrival") {
otherRequest.finalReverse = "true";
} else {
otherRequest.finalReverse = defaultReverse;
}
} else {
otherRequest.finalReverse = defaultReverse;
}
// Constraints
let other = false;
otherRequest.finalConstraint = "";
if (document.forms["iso-form"].elements["banned-highway"].checked) {
otherRequest.finalConstraint = "Toll";
other = true;
}
if (document.forms["iso-form"].elements["banned-tunnel"].checked) {
if (other) {
otherRequest.finalConstraint = otherRequest.finalConstraint + ";";
} else {
other = true;
}
otherRequest.finalConstraint = otherRequest.finalConstraint + "Tunnel";
}
if (document.forms["iso-form"].elements["banned-bridge"].checked) {
if (other) {
otherRequest.finalConstraint = otherRequest.finalConstraint + ";";
}
otherRequest.finalConstraint = otherRequest.finalConstraint + "Bridge";
}
}
// ----
// ---- Supprimer les données de l'utilisateur
function cancelUserData() {
cancelMap();
cancelForm();
}
// ---- Supprimer l'itinéraire affiché sur la carte
// Cette fonction est appelée lorsque l'on clique sur un des boutons du formulaire
function cancelMap() {
// Nettoyage des vecteurs qui contiennent les données sur la map
vectorRoad.clear();
vectorRoadOther.clear();
// Nettoyage des div qui concernent les isochrones supprimés
let currentDiv = document.getElementById('request');
currentDiv.innerHTML = "";
currentDiv = document.getElementById('response');
currentDiv.innerHTML = "";
}
// ----
// ---- Supprimer les paramètres du formulaire
// Cette fonction est appelée lorsque l'on clique sur un des boutons du formulaire
function cancelForm() {
// Nettoyage du formulaire
document.getElementById("iso-form").reset();
// Nettoyage des tableaux qui contiennent les points
clickedPoint = new Array();
// Nettoyage du vecteur qui contient les données sur la map
vectorPoint.clear();
}
// ----
var utils = {
to4326: function(coord) {
return ol.proj.transform([
parseFloat(coord[0]), parseFloat(coord[1])
], 'EPSG:3857', 'EPSG:4326');
},
createFeature: function(coord, vector) {
var feature = new ol.Feature({
type: 'place',
geometry: new ol.geom.Point(ol.proj.fromLonLat(coord))
});
feature.setStyle(styles.icon);
vector.addFeature(feature);
},
deleteFeature: function(coord, vector) {
let feature = vector.getClosestFeatureToCoordinate(coord);
vector.removeFeature(feature);
},
createIso: function(geom, format, vector) {
let route = {};
if (format === "polyline") {
route = new ol.format.Polyline({
factor: 1e5
}).readGeometry(geom, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
});
} else if (format === "wkt") {
route = new ol.format.WKT().readGeometry(geom, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
});
} else if (format === "geojson") {
route = new ol.format.GeoJSON().readGeometry(geom, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
});
} else {
return false;
}
let feature = new ol.Feature({
type: 'route',
geometry: route
});
if (format === "polyline") {
feature.setStyle(styles.routePolyline);
} else if (format === "wkt") {
feature.setStyle(styles.routeWkt);
} else if (format === "geojson") {
feature.setStyle(styles.routePolyline);
} else {
}
vector.addFeature(feature);
}
};
// Pour le chargement au changement de formulaire
$('.selectpicker').on('change', function(e){
computeIso()
});
$('.constrChkBx').on('change', function(e){
computeIso()
});
<div class="container-fluid row">
<form id="iso-form">
<p><strong>Paramètres de l'isochrone</strong></p>
<p>Mode de déplacement :
<select class="selectpicker" id="userProfile">
<option value="car">Voiture</option>
<option value="pedestrian">Piéton</option>
</select>
</p>
<p>Mode de calcul :
<select class="selectpicker" id="userCostType">
<option value="time">Isochrone</option>
<option value="distance">Isodistance</option>
</select></p>
<p>Sens de parcours :
<select class="selectpicker" id="userDirection">
<option value="departure">Depuis le point</option>
<option value="arrival">Vers le point</option>
</select></p>
<label for="userCostValue">Durée (en secondes) ou distance (en mètres)</label> : <input type="text" name="userCostValue" id="userCostValue" value="100"/><br>
<p>Contraintes : exclure les routes comprenant des :
<input class="constrChkBx" type="checkbox" id="banned-highway" name="Autoroutes">
<label for="Autoroutes">Péages</label>
<input class="constrChkBx" type="checkbox" id="banned-tunnel" name="Tunnels">
<label for="Tunnels">Tunnels</label>
<input class="constrChkBx" type="checkbox" id="banned-bridge" name="Ponts">
<label for="Ponts">Ponts</label>
</p>
</form>
</div>
<div class="container-fluid row">
<div id="map-isochrone" class="col">
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading collapsed" data-toggle="collapse" data-target="#request">
<i class="fa fa-fw fa-chevron-down"></i>
<i class="fa fa-fw fa-chevron-right"></i>Requête envoyée au nouveau service d'isochrone
</div>
<div class="panel-body">
<!-- The inside div eliminates the 'jumping' animation. -->
<div class="collapse" id="request">
</div>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading collapsed" data-toggle="collapse" data-target="#response">
<i class="fa fa-fw fa-chevron-down"></i>
<i class="fa fa-fw fa-chevron-right"></i>Réponse du nouveau service d'isochrone
</div>
<div class="panel-body">
<!-- The inside div eliminates the 'jumping' animation. -->
<div class="collapse" id="response">
</div>
</div>
</div>
<div id="loading"></div>
.panel-heading.collapsed .fa-chevron-down,
.panel-heading .fa-chevron-right {
display: none;
}
.panel-heading.collapsed .fa-chevron-right,
.panel-heading .fa-chevron-down {
display: inline-block;
}
i.fa {
margin-right: 5px;
}
.panel-heading {
cursor: pointer;
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
border-bottom: 2px solid #bce8f1;
line-height: 2;
}
.collapsed ~ .panel-body {
padding: 0;
}
div[id^="GPlayersList"]{
width: 250px;
}
#loading {
position: absolute;
top: 0;
left: 0;
z-index: 100;
width: 100vw;
height: 100vh;
background-color: rgba(192, 192, 192, 0.5);
background-image: url("http://i.stack.imgur.com/MnyxU.gif");
background-repeat: no-repeat;
background-position: center;
}
.not_displayed {
display: none;
}
.displayed {
display : block;
}
External resources loaded into this fiddle: