效果图:
说明:
上篇已经说到如何在本机开启GraphHopper服务了,地址在这:基于Leaflet和GraphHopper实现离线路径规划_leaflet电子海图 openseamap 路径规划-优快云博客 ,里面的第一步就是,总结一下就是:一个jar包,一份pbf格式的数据,一个配置文件,然后在cmd窗口下跑一条命令。两个需要注意的地方:1.如果你想做全国的路径规划,先到OpenStreetMap上下载全国路网数据, 由于数据过大,跑的时候可能出现内存问题,可以试试加上-Xmx2g -Xms2g,我的命令:java -Xmx2g -Xms2g -Dgraphhopper.datareader.file=china-latest.osm.pbf -jar graphhopper-web-0.11.0.jar server config-example.yml 2.如果想让您本机的服务其他机器都能访问,注意修改配置文件最后的:bindHost: localhost 把localhost改成你的机器IP地址
服务启动之后,cmd窗口有提示打开localhost:8989
到现在为止,后台工作已经完成,下面就是前台请求以及可视化工作。url请求地址仿照着拼就行了,前边是协议+IP+端口,后面参数根据选的点自己拼,不需要key,要注意参数points_encoded,他默认是true,也就是说返回来的点数据都是加密的,看你需求了,不想加密的话设为false。我的一个完整URl:
Request URL:
http://localhost:8989/route?point=52.53032100669386,13.344612121582031&point=52.527710210603935,13.409500122070314&type=json&locale=zh-CN&vehicle=car&weighting=fastest&points_encoded=false
主要代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>离线路径规划</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./lib/leaflet/leaflet.css" />
<link rel="stylesheet" href="lib/leaflet/leaflet.contextmenu.css"/>
<script src="./lib/leaflet/leaflet.js"></script>
<script src="./lib/leaflet/leaflet-ant-path.js" type="text/javascript"></script>
<script src="./lib/leaflet/leaflet.contextmenu.js"></script>
</head>
<style>
* { margin: 0; padding: 0; }
html, body { height: 100%; }
#mapid { width:100%; height:100%; }
</style>
<body>
<div id="mapid" ></div>
<script>
var map = L.map('mapid', {
center: [52.52207,13.374481],
zoom: 13,
crs: L.CRS.EPSG3857,
layers: [
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
})
],
contextmenu: true,
contextmenuItems: [{
text: '设置为起点',
callback: setStartPoint
}, {
text: '设置为中间点',
callback: setWaypoints
}, '-', {
text: '设置为终点',
callback: setStopPoint
}, {
text: '开始规划',
callback: calcRoute
}]
});
var _startPoint,_stopPoint,_wayPoints = [];
var _points = [];//用于存储所有点
function setStartPoint(event){
_startPoint = event.latlng;
var _icon = L.icon({iconUrl:'./lib/img/start.png'})
L.marker(_startPoint,{icon:_icon}).addTo(map);
}
function setWaypoints(event){
_wayPoints.push(event.latlng);
var _icon = L.icon({iconUrl:'./lib/img/way.png'})
L.marker(event.latlng,{icon:_icon}).addTo(map);
}
function setStopPoint(event){
_stopPoint = event.latlng;
var _icon = L.icon({iconUrl:'./lib/img/stop.png'})
L.marker(_stopPoint,{icon:_icon}).addTo(map);
}
function calcRoute() {
var url = _buildRouteUrl();
if(url == null || url == undefined){
return;
}else{
var request,me = this;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else {
request = new ActiveXObject('Microsoft.XMLHTTP');
}
request.onreadystatechange = function () { // 状态发生变化时,函数被回调
if (request.readyState === 4) { // 成功完成
// 判断响应结果:
if (request.status === 200) {
// 成功,通过responseText拿到响应的文本:
return _success(request.responseText);
} else {
// 失败,根据响应码判断失败原因:
return _fail(request.status);
}
} else {
// HTTP请求还在继续...
}
}
// 发送请求:
request.open('GET', url);
request.send();
//alert('请求已发送,请等待响应...');
}
}
function _buildRouteUrl(){
var wayPoints = _setPointsSequence();
if(wayPoints == null || wayPoints == undefined){
return;
}else{
var locs = [],
i,
baseUrl;
for (i = 0; i < wayPoints.length; i++) {
locs.push('point=' + wayPoints[i].lat + ',' + wayPoints[i].lng);
}
baseUrl = 'http://localhost:8989' + '/route?' + locs.join('&');
return baseUrl + '&type=json&locale=zh-CN&vehicle=car&weighting=fastest&points_encoded=false';
}
}
function _setPointsSequence(){
var me = this;
if(this._startPoint == null || this._startPoint == undefined){
alert("请先设置起点");
return;
}
if(this._stopPoint == null || this._stopPoint == undefined){
alert("请先设置终点");
return;
}
this._points.push(this._startPoint);
if(this._wayPoints.length > 0){
for(let i=0;i<me._wayPoints.length;i++){
me._points.push(me._wayPoints[i]);
}
}
this._points.push(this._stopPoint);
return this._points;
}
function _success(text){
this._responseResult = text;
var json = JSON.parse(text);
var lnglats = json.paths[0].points.coordinates;//(lng,lat)
var latlngs = [];//(lat,lng)
for(let j=0;j<lnglats.length;j++){
var lnglat = lnglats[j];
var latlng = [];
latlng[0] = lnglat[1];
latlng[1] = lnglat[0];
latlngs.push(latlng);
}
var path = L.polyline.antPath(latlngs,{color: "#A52A2A", pulseColor: "#0000FF"});
path.addTo(map);
return text;
}
function _fail(code){
alert('请求失败,' + 'Error code: ' + code);
return code;
}
</script>
</body>
</html>
进行可视化的时候用到了两个插件:一个是右键菜单,一个线动画
源文件下载地址:https://download.youkuaiyun.com/download/wml00000/10787367
GraphHopper在线API测试:https://explorer.graphhopper.com/
路径规划设置障碍区域:https://docs.graphhopper.com/#section/Limit-rules-to-certain-areas
参数:
{
"points": [
[
11.539421,
48.118477
],
[
11.559023,
48.12228
]
],
"snap_preventions": [
"motorway",
"ferry",
"tunnel"
],
"details": [
"road_class",
"surface"
],
"profile": "car",
"locale": "en",
"instructions": true,
"calc_points": true,
"points_encoded": false,
"ch.disable": true,
"custom_model": {
"speed": [
{
"if": "true",
"limit_to": "100"
}
],
"priority": [
{
"if": "in_custom1",
"multiply_by": "0"
}
],
"areas": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "custom1",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
11.547064,
48.119694
],
[
11.549746,
48.119833
],
[
11.549488,
48.118014
],
[
11.547779,
48.117728
],
[
11.547064,
48.119694
]
]
]
}
}
]
}
}
}