如何使用mapquest API建立一个路由服务

347 阅读5分钟

使用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;
}

在执行上述内容时,我们的输入表单应该是:

input

添加一个地图层

接下来,通过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;
}

map

此刻的地图看起来不错🚀!为了移动我们的缩放控件,添加样式。

.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>

final-result

在上面的gif中,我们的地图是由一个实时服务器运行的。如果你使用vscode ,你可能熟悉用于启动静态页面的实时服务器扩展。它通过一个安全的端口创建一个网络地址来提供页面。要安装它,请到vscode 的扩展标签,在搜索栏上输入live server 。就这么简单!

结论

我们已经能够创建一个地图层,一个输入表单,和一个路由功能。

正如我们前面所说,有几个位置路由服务是用leaflet实现的,但mapquest的路由API是迄今为止最简单的一个。

但是,容易并不意味着最好。因此,在我个人看来,对于希望在JavaScript中建立类似服务的更有经验的程序员来说,开放街道路由机(OSRM)是一个不错的选择。