使用 OpenLayers 从 GraphHpper 绘制路线
Use OpenLayers for Draw Route from GraphHpper
我刚开始使用地图 GraphHopper、OpenStreetMap 和其他库。我想绘制由 GraphHopper 路由引擎生成的路由(实际上是 Java 语言)。是否可以使用 OpenLayer 从 GH 绘制路线?
我读过这个GWT-OpenLayer, but I can't find how to write a route in real road like this GraphHopper Routing Example
我希望 openlayers API 可以满足我的需求
- GH 路由引擎生成从 A(经度、纬度)到 B(经度、纬度)的路径
- OpenLayers GWT 从 GH 绘制每条路线
任何帮助将不胜感激:)
GraphHopper 路由 API 与许多其他路由 API 非常相似,它可以直接从 JavaScript 应用程序(例如 OpenLayers)中获取,结果包含一条折线,如下所示本例中使用 https://openlayers.org/en/main/examples/feature-move-animation.html(但折线可以包含高程并具有标准的 ie5 比例因子)。更改 OpenLayers 示例以使用 GraphHopper 示例中的路由(我复制了 API 密钥,但对于生产,您应该拥有自己的密钥)结果是:
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#map {
position: relative;
}
#controls {
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
</head>
<body>
<div id="map" class="map">
<div id="controls">
<label for="speed">
speed:
<input id="speed" type="range" min="10" max="999" step="10" value="60">
</label>
<button id="start-animation">Start Animation</button>
</div>
</div>
<script type="text/javascript">
const center = [-5639523.95, -3501274.52];
const map = new ol.Map({
target: document.getElementById('map'),
view: new ol.View({
center: center,
zoom: 10,
minZoom: 2,
maxZoom: 19,
}),
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
],
});
// The polyline string is read from a JSON similiar to those returned
// by directions APIs such as Openrouteservice and Mapbox.
const api_key = 'ab642f98-3b45-4643-981d-9b80f58239a3';
const startLonLat = [111.352111, 0.136299];
const endLonLat = [111.299744, -0.255431];
fetch('https://graphhopper.com/api/1/route' +
'?point=' + startLonLat.slice().reverse().join(',') +
'&point=' + endLonLat.slice().reverse().join(',') +
'&type=json&locale=en-US&key=' + api_key +
'&elevation=true&profile=car'
).then(function (response) {
response.json().then(function (result) {
const polyline = result.paths[0].points;
const route = new ol.format.Polyline({
factor: 1e5,
geometryLayout: 'XYZ'
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857',
});
map.getView().fit(route);
const routeFeature = new ol.Feature({
type: 'route',
geometry: route,
});
const geoMarker = new ol.Feature({
type: 'geoMarker',
geometry: new ol.geom.Point(route.getCoordinateAt(0)),
});
const startMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(route.getCoordinateAt(0)),
});
const endMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(route.getCoordinateAt(1)),
});
const styles = {
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6,
color: [237, 212, 0, 0.8],
}),
}),
'icon': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://openlayers.org/en/main/examples/data/icon.png',
}),
}),
'geoMarker': new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({color: 'black'}),
stroke: new ol.style.Stroke({
color: 'white',
width: 2,
}),
}),
}),
};
let animating = false;
const vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature, geoMarker, startMarker, endMarker],
}),
style: function (feature) {
// hide geoMarker if animation is active
if (animating && feature.get('type') === 'geoMarker') {
return null;
}
return styles[feature.get('type')];
},
});
map.addLayer(vectorLayer);
let speed, startTime;
const speedInput = document.getElementById('speed');
const startButton = document.getElementById('start-animation');
function moveFeature(event) {
const vectorContext = ol.render.getVectorContext(event);
const frameState = event.frameState;
if (animating) {
const elapsedTime = frameState.time - startTime;
const distance = (speed * elapsedTime) / 1e6;
if (distance >= 1) {
stopAnimation(true);
return;
}
const currentPoint = new ol.geom.Point(route.getCoordinateAt(distance));
const feature = new ol.Feature(currentPoint);
vectorContext.drawFeature(feature, styles.geoMarker);
}
// tell OpenLayers to continue the postrender animation
map.render();
}
function startAnimation() {
if (animating) {
stopAnimation(false);
} else {
animating = true;
startTime = new Date().getTime();
speed = speedInput.value;
startButton.textContent = 'Cancel Animation';
// hide geoMarker
geoMarker.changed();
// just in case you pan somewhere else
map.getView().fit(route);
vectorLayer.on('postrender', moveFeature);
map.render();
}
}
function stopAnimation(ended) {
animating = false;
startButton.textContent = 'Start Animation';
// if animation cancelled set the marker at the beginning
const coord = route.getCoordinateAt(ended ? 1 : 0);
geoMarker.getGeometry().setCoordinates(coord);
// remove listener
vectorLayer.un('postrender', moveFeature);
}
startButton.addEventListener('click', startAnimation, false);
});
});
</script>
</body>
</html>
我刚开始使用地图 GraphHopper、OpenStreetMap 和其他库。我想绘制由 GraphHopper 路由引擎生成的路由(实际上是 Java 语言)。是否可以使用 OpenLayer 从 GH 绘制路线?
我读过这个GWT-OpenLayer, but I can't find how to write a route in real road like this GraphHopper Routing Example
我希望 openlayers API 可以满足我的需求
- GH 路由引擎生成从 A(经度、纬度)到 B(经度、纬度)的路径
- OpenLayers GWT 从 GH 绘制每条路线
任何帮助将不胜感激:)
GraphHopper 路由 API 与许多其他路由 API 非常相似,它可以直接从 JavaScript 应用程序(例如 OpenLayers)中获取,结果包含一条折线,如下所示本例中使用 https://openlayers.org/en/main/examples/feature-move-animation.html(但折线可以包含高程并具有标准的 ie5 比例因子)。更改 OpenLayers 示例以使用 GraphHopper 示例中的路由(我复制了 API 密钥,但对于生产,您应该拥有自己的密钥)结果是:
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#map {
position: relative;
}
#controls {
z-index: 1;
position: absolute;
bottom: 0;
left: 0;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
</head>
<body>
<div id="map" class="map">
<div id="controls">
<label for="speed">
speed:
<input id="speed" type="range" min="10" max="999" step="10" value="60">
</label>
<button id="start-animation">Start Animation</button>
</div>
</div>
<script type="text/javascript">
const center = [-5639523.95, -3501274.52];
const map = new ol.Map({
target: document.getElementById('map'),
view: new ol.View({
center: center,
zoom: 10,
minZoom: 2,
maxZoom: 19,
}),
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
],
});
// The polyline string is read from a JSON similiar to those returned
// by directions APIs such as Openrouteservice and Mapbox.
const api_key = 'ab642f98-3b45-4643-981d-9b80f58239a3';
const startLonLat = [111.352111, 0.136299];
const endLonLat = [111.299744, -0.255431];
fetch('https://graphhopper.com/api/1/route' +
'?point=' + startLonLat.slice().reverse().join(',') +
'&point=' + endLonLat.slice().reverse().join(',') +
'&type=json&locale=en-US&key=' + api_key +
'&elevation=true&profile=car'
).then(function (response) {
response.json().then(function (result) {
const polyline = result.paths[0].points;
const route = new ol.format.Polyline({
factor: 1e5,
geometryLayout: 'XYZ'
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857',
});
map.getView().fit(route);
const routeFeature = new ol.Feature({
type: 'route',
geometry: route,
});
const geoMarker = new ol.Feature({
type: 'geoMarker',
geometry: new ol.geom.Point(route.getCoordinateAt(0)),
});
const startMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(route.getCoordinateAt(0)),
});
const endMarker = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(route.getCoordinateAt(1)),
});
const styles = {
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6,
color: [237, 212, 0, 0.8],
}),
}),
'icon': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://openlayers.org/en/main/examples/data/icon.png',
}),
}),
'geoMarker': new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({color: 'black'}),
stroke: new ol.style.Stroke({
color: 'white',
width: 2,
}),
}),
}),
};
let animating = false;
const vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature, geoMarker, startMarker, endMarker],
}),
style: function (feature) {
// hide geoMarker if animation is active
if (animating && feature.get('type') === 'geoMarker') {
return null;
}
return styles[feature.get('type')];
},
});
map.addLayer(vectorLayer);
let speed, startTime;
const speedInput = document.getElementById('speed');
const startButton = document.getElementById('start-animation');
function moveFeature(event) {
const vectorContext = ol.render.getVectorContext(event);
const frameState = event.frameState;
if (animating) {
const elapsedTime = frameState.time - startTime;
const distance = (speed * elapsedTime) / 1e6;
if (distance >= 1) {
stopAnimation(true);
return;
}
const currentPoint = new ol.geom.Point(route.getCoordinateAt(distance));
const feature = new ol.Feature(currentPoint);
vectorContext.drawFeature(feature, styles.geoMarker);
}
// tell OpenLayers to continue the postrender animation
map.render();
}
function startAnimation() {
if (animating) {
stopAnimation(false);
} else {
animating = true;
startTime = new Date().getTime();
speed = speedInput.value;
startButton.textContent = 'Cancel Animation';
// hide geoMarker
geoMarker.changed();
// just in case you pan somewhere else
map.getView().fit(route);
vectorLayer.on('postrender', moveFeature);
map.render();
}
}
function stopAnimation(ended) {
animating = false;
startButton.textContent = 'Start Animation';
// if animation cancelled set the marker at the beginning
const coord = route.getCoordinateAt(ended ? 1 : 0);
geoMarker.getGeometry().setCoordinates(coord);
// remove listener
vectorLayer.un('postrender', moveFeature);
}
startButton.addEventListener('click', startAnimation, false);
});
});
</script>
</body>
</html>