使用mapquest API构建一个路由服务
路由是地图领域的一个焦点。路由服务在Jumia食品递送系统、谷歌地图和众多基于位置的服务公司等应用中至关重要。
地理学中的路由是指从一个指定的起点到目的地的路线。我们用一些API或插件在JavaScript中建立路由服务,如谷歌方向API、开放街道路由机(OSRM),以及我们本文的重点,Mapquest方向API。
Mapquest为小册子地图创建了一个插件,向其方向API服务发送请求,接收这些结果并在地图上显示。本教程将指导你如何在你的地图中执行这一功能。
前提条件
读者需要在以下方面有坚实的基础。
- HTML、CSS、JavaScript。
- 读者应该有一个Mapquest的API密钥。
目的
在本教程结束时,读者应该能够。
- 将Mapquest整合到他们的地图中。
- 为leaflet.Js使用Mapquest的路由API。
- 创建一个前端输入表单,用于输入我们想要的路由位置。
- 通过替换地图层清除表单数据
onload。
开始使用
我们将把这篇文章分成不同的部分。
- 创建一个输入表单。
- 添加一个地图层。
- 实现路由功能。
首先,我们将创建HTML、CSS和JavaScript文件。然后,我们就可以进入第一节了。
创建输入表单
在初始化我们的HTML模板后,我们创建一个类名为formBlock 的div标签。
然后,让我们建立一个输入表单,包含一个表单、输入和按钮标签。表单标签的id是form ,输入标签的类名是input 。
本项目中的输入表单是为了接受我们的路由过程的起点和终点(位置)。
下面是上面解释的代码片断。
<div class="formBlock">
<form id="form">
<input type="text" name="start" class="input" id="start" placeholder="Choose starting point" />
<input type="text" name="end" class="input" id="destination" placeholder="Choose end point" />
<button type="submit">Go</button>
</form>
</div>
给我们上面的输入表单添加一些样式。在我们的CSS文件中,添加以下内容。
.formBlock {
max-width: 300px;
background-color: #FFF;
border: 1px solid #ddd;
position: absolute;
top: 10px;
left: 10px;
padding: 10px;
z-index: 999;
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 5px;
width: 100%;
}
.input {
box-sizing: border-box;
padding: 10px;
width: 100%;
border: 1px solid #ddd;
font-size: 15px;
border-radius: 3px;
}
#form {
padding: 0;
margin: 0;
}
input:nth-child(1) {
margin-bottom: 10px;
}
#button{
display: none;
}
在执行上述内容时,我们的输入表单应该是:

添加一个地图层
接下来,通过CDN在我们的标题中添加小册子的JavaScript和CSS文件。让我们也包括Mapquest和它的小册子路由插件JavaScript文件。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script>
<script src="https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-map.js?key=QGer4kg9yzSEAajj53JtHB4ngaooYSVs"></script>
<script src="https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-routing.js?key=QGer4kg9yzSEAajj53JtHB4ngaooYSVs"></script>
注意!你需要一个Mapquest的API密钥来使用(Mapquest的)服务。
让我们创建一个ID为map 的div。这个div作为我们地图层的一个容器。接下来,通过初始化我们的Mapquest API密钥和定义我们的地图对象(中心和缩放)来加载地图层。
// default map layer
let map = L.map('map', {
layers: MQ.mapLayer(),
center: [9.0820, 8.6753],
zoom: 8
});
为了显示地图,添加下面的样式。
#map {
height:100vh;
width: 100%;
position: relative;
}

此刻的地图看起来不错🚀!为了移动我们的缩放控件,添加样式。
.leaflet-top .leaflet-control {
margin-top: 180px;
}
实现路由功能
在这之前,我们需要创建一个提交事件函数。首先,用参数event调用一个叫做submitForm 的JavaScript函数。添加一个preventDefault() 方法以防止提交一个空表单。同时,添加map.remove() ,一旦我们添加了一个新的输入,就删除当前的地图层。
接下来,用getElemenetById() 方法,获取我们表单中输入的每个值。添加一个叫做runDirection(start, end) 的回调函数来发送我们输入表单中的值。
function submitForm(event) {
event.preventDefault();
map.remove();
start = document.getElementById("start").value;
end = document.getElementById("destination").value;
runDirection(start, end);
document.getElementById("form").reset();
}
我们的路由函数需要在表单提交后有一个新的地图层。我们将冒昧地让我们的自定义标记物。接下来,为起点和终点创建一个标记对象。
function runDirection(start, end) {
// recreating new map layer after removal
map = L.map('map', {
layers: MQ.mapLayer(),
center: [9.0820, 8.6753],
zoom: 8
});
var direction = MQ.routing.directions();
direction.route({
locations: [
start,
end
]
});
MainRouteLayer = MQ.Routing.RouteLayer.extend({
initstartmarker: (location) => {
var icon1;
var startmarker;
icon1 = L.icon({
iconUrl: 'red.png',
iconSize: [20, 29],
iconAnchor: [10, 29],
popupAnchor: [0, -29]
});
startmarker = L.marker(location.latLng, { icon: icon1 }).addTo(map);
return startmarker;
},
initEndmarker: (location) => {
var icon2;
var endmarker;
icon2 = L.icon({
iconUrl: 'blue.png',
iconSize: [20, 29],
iconAnchor: [10, 29],
popupAnchor: [0, -29]
});
endmarker = L.marker(location.latLng, { icon: icon2 }).addTo(map);
return endmarker;
}
});
map.addLayer(new MainRouteLayer({
directions: direction,
fitBounds: true
}));
}
最后,调用我们的addEventListener 方法来提交表单结果,我们的地图应该如下所示。
const form = document.getElementById('form');
form.addEventListener('submit', submitForm);
我们的最终代码应该如下。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script>
<script src="https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-map.js?key=QGer4kg9yzSEAajj53JtHB4ngaooYSVs"></script>
<script
src="https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-routing.js?key=QGer4kg9yzSEAajj53JtHB4ngaooYSVs"></script>
<style>
#map {
height: 100vh;
width: 100%;
position: relative;
}
.formBlock {
max-width: 300px;
background-color: #FFF;
border: 1px solid #ddd;
position: absolute;
top: 10px;
left: 10px;
padding: 10px;
z-index: 999;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
border-radius: 5px;
width: 100%;
}
.input {
box-sizing: border-box;
padding: 10px;
width: 100%;
border: 1px solid #ddd;
font-size: 15px;
border-radius: 3px;
}
#form {
padding: 0;
margin: 0;
}
input:nth-child(1) {
margin-bottom: 10px;
}
#button {
display: none;
}
.leaflet-top .leaflet-control {
margin-top: 180px;
}
</style>
</head>
<body>
<div id="map"></div>
<div class="formBlock">
<form id="form">
<input type="text" name="start" class="input" id="start" placeholder="Choose starting point" />
<input type="text" name="end" class="input" id="destination" placeholder="Choose ending point" />
<button id="button" type="submit">Go</button>
</form>
</div>
</body>
<script>
// default map layer
let map = L.map('map', {
layers: MQ.mapLayer(),
center: [9.0820, 8.6753],
zoom: 8
});
function runDirection(start, end) {
// recreating new map layer after removal
map = L.map('map', {
layers: MQ.mapLayer(),
center: [9.0820, 8.6753],
zoom: 8
});
var direction = MQ.routing.directions();
direction.route({
locations: [
start,
end
]
});
MainRouteLayer = MQ.Routing.RouteLayer.extend({
initstartmarker: (location) => {
var icon1;
var startmarker;
icon1 = L.icon({
iconUrl: 'red.png',
iconSize: [20, 29],
iconAnchor: [10, 29],
popupAnchor: [0, -29]
});
startmarker = L.marker(location.latLng, { icon: icon1 }).addTo(map);
return startmarker;
},
initEndmarker: (location) => {
var icon2;
var endmarker;
icon2 = L.icon({
iconUrl: 'blue.png',
iconSize: [20, 29],
iconAnchor: [10, 29],
popupAnchor: [0, -29]
});
endmarker = L.marker(location.latLng, { icon: icon2 }).addTo(map);
return endmarker;
}
});
map.addLayer(new MainRouteLayer({
directions: direction,
fitBounds: true
}));
}
function submitForm(event) {
event.preventDefault();
map.remove();
start = document.getElementById("start").value;
end = document.getElementById("destination").value;
runDirection(start, end);
document.getElementById("form").reset();
}
const form = document.getElementById('form');
form.addEventListener('submit', submitForm);
</script>
</html>

在上面的gif中,我们的地图是由一个实时服务器运行的。如果你使用vscode ,你可能熟悉用于启动静态页面的实时服务器扩展。它通过一个安全的端口创建一个网络地址来提供页面。要安装它,请到vscode 的扩展标签,在搜索栏上输入live server 。就这么简单!
结论
我们已经能够创建一个地图层,一个输入表单,和一个路由功能。
正如我们前面所说,有几个位置路由服务是用leaflet实现的,但mapquest的路由API是迄今为止最简单的一个。
但是,容易并不意味着最好。因此,在我个人看来,对于希望在JavaScript中建立类似服务的更有经验的程序员来说,开放街道路由机(OSRM)是一个不错的选择。