186 lines
5.1 KiB
HTML
186 lines
5.1 KiB
HTML
|
<!doctype html>
|
||
|
<html lang="en">
|
||
|
<head>
|
||
|
<meta charset="utf-8">
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
<title>PgRouting Example</title>
|
||
|
|
||
|
<!-- CSS/JS for OpenLayers map -->
|
||
|
<link rel="stylesheet" href="https://openlayers.org/en/v6.1.1/css/ol.css" type="text/css">
|
||
|
<script src="https://openlayers.org/en/v6.1.1/build/ol.js"></script>
|
||
|
|
||
|
<style>
|
||
|
body {
|
||
|
padding: 0;
|
||
|
margin: 0;
|
||
|
}
|
||
|
html, body, #map {
|
||
|
height: 100%;
|
||
|
width: 100%;
|
||
|
font-family: sans-serif;
|
||
|
}
|
||
|
#meta {
|
||
|
background-color: rgba(255,255,255,0.75);
|
||
|
color: black;
|
||
|
z-index: 2;
|
||
|
position: absolute;
|
||
|
top: 10px;
|
||
|
left: 20px;
|
||
|
padding: 10px 20px;
|
||
|
margin: 0;
|
||
|
width: min-content;
|
||
|
}
|
||
|
</style>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
|
||
|
<div id="meta">
|
||
|
<h2>PgRouting / pg_tileserv / pg_featureserv</h2>
|
||
|
<ul>
|
||
|
<li><a href="https://openlayers.org/">OpenLayers</a></li>
|
||
|
<li><a href="https://pgrouting.org/">PgRouting</a></li>
|
||
|
<li><a href="https://github.com/crunchydata/pg_tileserv">pg_tileserv</a></li>
|
||
|
<li><a href="https://github.com/crunchydata/pg_featureserv">pg_featureserv</a></li>
|
||
|
</ul>
|
||
|
<p>Click once to set a start point, and a second time to set an end point and generate a route.</p>
|
||
|
<p>Routes are node-to-node so clicks are interpretted as starting from the nearest node.</p>
|
||
|
</div>
|
||
|
|
||
|
<div id="map"></div>
|
||
|
|
||
|
<script>
|
||
|
|
||
|
//********************************************************************************/
|
||
|
// CONSTANTS
|
||
|
//********************************************************************************/
|
||
|
|
||
|
var serverName = 'MYLOCALHOST'
|
||
|
|
||
|
//********************************************************************************/
|
||
|
// BASE MAP (Raster tiles from wikimedia)
|
||
|
//********************************************************************************/
|
||
|
|
||
|
var baseLayer = new ol.layer.Tile({
|
||
|
source: new ol.source.XYZ({
|
||
|
url: "http://{1-4}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"
|
||
|
})
|
||
|
});
|
||
|
|
||
|
//********************************************************************************/
|
||
|
// WAY LAYER (Vector tiles of all ways from pg_tileserv)
|
||
|
//********************************************************************************/
|
||
|
|
||
|
var vectorUrl = "http://" + serverName + ":7800/public.ways/{z}/{x}/{y}.pbf";
|
||
|
|
||
|
var vectorStyle = new ol.style.Style({
|
||
|
stroke: new ol.style.Stroke({
|
||
|
width: 3,
|
||
|
color: "#00000055"
|
||
|
})
|
||
|
});
|
||
|
|
||
|
var vectorLayer = new ol.layer.VectorTile({
|
||
|
source: new ol.source.VectorTile({
|
||
|
format: new ol.format.MVT(),
|
||
|
url: vectorUrl
|
||
|
}),
|
||
|
style: vectorStyle
|
||
|
});
|
||
|
|
||
|
//********************************************************************************/
|
||
|
// CLICK LAYER (One point for each click)
|
||
|
//********************************************************************************/
|
||
|
|
||
|
var clicks = [];
|
||
|
var clickSource = new ol.source.Vector({});
|
||
|
|
||
|
var clickLayer = new ol.layer.Vector({
|
||
|
source: clickSource,
|
||
|
style: new ol.style.Style({
|
||
|
image: new ol.style.RegularShape({
|
||
|
fill: new ol.style.Fill({
|
||
|
color: 'red'
|
||
|
}),
|
||
|
stroke: new ol.style.Stroke({
|
||
|
width: 1,
|
||
|
color: 'grey'
|
||
|
}),
|
||
|
points: 16,
|
||
|
radius: 10,
|
||
|
angle: Math.PI / 4
|
||
|
})
|
||
|
})
|
||
|
});
|
||
|
|
||
|
//********************************************************************************/
|
||
|
// ROUTE LAYER (GeoJSON source reading from pg_featureserv)
|
||
|
//********************************************************************************/
|
||
|
|
||
|
function routeUrl(coord1, coord2) {
|
||
|
var url = "http://" + serverName + ":9000/functions/boston_find_route/items.json";
|
||
|
url += "?from_lon=" + coord1[0];
|
||
|
url += "&from_lat=" + coord1[1];
|
||
|
url += "&to_lon=" + coord2[0];
|
||
|
url += "&to_lat=" + coord2[1];
|
||
|
url += "&limit=1000"
|
||
|
return url;
|
||
|
}
|
||
|
|
||
|
var routeSource = new ol.source.Vector({
|
||
|
format: new ol.format.GeoJSON(),
|
||
|
projection : 'EPSG:4326',
|
||
|
features: []
|
||
|
});
|
||
|
|
||
|
var routeLayer = new ol.layer.Vector({
|
||
|
title: 'Route',
|
||
|
source: routeSource,
|
||
|
style: new ol.style.Style({
|
||
|
stroke: new ol.style.Stroke({
|
||
|
width: 3,
|
||
|
color: "#ff0000"
|
||
|
})
|
||
|
})
|
||
|
});
|
||
|
|
||
|
//********************************************************************************/
|
||
|
// MAP SETUP (Layers and click action function)
|
||
|
//********************************************************************************/
|
||
|
|
||
|
var map = new ol.Map({
|
||
|
target: 'map',
|
||
|
view: new ol.View({
|
||
|
center: ol.proj.transform([-71.0526, 42.3553], 'EPSG:4326', 'EPSG:3857'),
|
||
|
zoom: 15
|
||
|
}),
|
||
|
layers: [baseLayer, vectorLayer, routeLayer, clickLayer]
|
||
|
});
|
||
|
|
||
|
map.on('singleclick', function(evt) {
|
||
|
// Click when we already have 2 clicks means a fresh start
|
||
|
if (clicks.length >= 2) {
|
||
|
clicks.length = 0;
|
||
|
clickSource.clear();
|
||
|
routeSource.clear();
|
||
|
}
|
||
|
// Add latest click to the map
|
||
|
clicks.push(ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326'));
|
||
|
clickSource.addFeature(new ol.Feature({
|
||
|
geometry: new ol.geom.Point(evt.coordinate),
|
||
|
}));
|
||
|
// Have two clicks? Calculate route!
|
||
|
if (clicks.length == 2) {
|
||
|
var url = routeUrl(clicks[0], clicks[1]);
|
||
|
routeSource.setUrl(url);
|
||
|
routeSource.clear();
|
||
|
routeSource.refresh();
|
||
|
}
|
||
|
// Redraw with new elements
|
||
|
map.render();
|
||
|
});
|
||
|
|
||
|
</script>
|
||
|
</body>
|
||
|
</html>
|