DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Mocking Dependencies and AI Is the Next Frontier in Vue.js Testing
  • Building Micro-Frontends With Vue and Reusable Components
  • Designing a Java Connector for Software Integrations
  • Vibe Coding With GitHub Copilot: Optimizing API Performance in Fintech Microservices

Trending

  • AI-Based Threat Detection in Cloud Security
  • Revolutionizing Financial Monitoring: Building a Team Dashboard With OpenObserve
  • Docker Model Runner: Streamlining AI Deployment for Developers
  • It’s Not About Control — It’s About Collaboration Between Architecture and Security
  1. DZone
  2. Data Engineering
  3. Databases
  4. Calculating the Shortest Route With a HERE API and Vue.js

Calculating the Shortest Route With a HERE API and Vue.js

Why use a third-party web app to calculate the shortest route for Google Maps when you can just build it yourself?

By 
Nic Raboy user avatar
Nic Raboy
·
Sep. 02, 19 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
19.4K Views

Join the DZone community and get the full member experience.

Join For Free

Image title

Which path is the fastest? Let's build a Vue.js app to find out.

When it comes to routing, knowing how to get from point A to point B in the most efficient manner isn't exactly the only use-case. When it comes to modern applications or use-cases, a lot more can be and should be accomplished.

Let's take the scenario of a package delivery service. When it comes to a delivery driver, they fill up their truck at the warehouse and have to navigate to every address that exists on a package in their truck before returning the truck to the warehouse. The driver can't just pick random packages from the truck and deliver them randomly because that would be very inefficient. Instead, each delivery should be carefully planned to optimize how many packages can be delivered and the quickest.

So given X number of random addresses, how do you plan your route so that efficiency is the priority?

This is where the HERE Waypoint Sequence Extension API comes into play. Give it a series of positions and it will return the order that those positions should be navigated to. Then you can take that ordered sequence and calculate the actual route between them.

We're going to explore the Waypoint Sequence API in this tutorial using the Vue.js JavaScript framework.

To get an idea of what we want to accomplish, take the following animated image:

vuejs-route-waypoint-app

Voilá, your waypoint calcuating app.

What you can't see in the above image is that I provided a bunch of random positions. After receiving an ordered sequence from the Waypoint Sequence API, numbers are attached to each marker to represent the order of access. Then a route is calculated and drawn between the markers.

This was all done using Leaflet.js with Vue.js and a fancy polyline animation library.

Create a New Vue.js Project With the Vue CLI

Because this will be a Vue.js example, a new project needs to be created with the Vue CLI. Assuming the CLI has been installed, execute the following:

vue create wse-project


We're not in the clear yet. Because we'll be making HTTP requests to the HERE APIs, we'll need to install a particular package to get the job done. From the CLI, execute the following:

npm install axios --save


We'll be using the axios library to make HTTP requests. There are plenty of other ways to do this, but axios makes it very clean. If you'd like to learn about other ways to make HTTP requests with JavaScript, check out my previous tutorial titled, Execute HTTP Requests in JavaScript Applications.

No further NPM modules are necessary, but we will be needing a few browser dependencies. Open the project's public/index.html file and include the following:

<!DOCTYPE html>
<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">
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <title>WSE Project</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" />
    </head>
    <body>
        <noscript>
            <strong>We're sorry but the app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
        </noscript>
        <div id="app"></div>
        <!-- built files will be auto injected -->
        <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/leaflet.polyline.snakeanim@0.2.0/L.Polyline.SnakeAnim.min.js"></script>
    </body>
</html>


You'll notice a few things in the above HTML. We're adding both the Leaflet.js CSS and JavaScript dependencies as well as the snake animation dependency to give us a nice polyline animation.

At this point in time we can start developing our component.

Design a Leaflet.js Component for Maps and Location Functionality

To keep our code clean and reusable, we're going to create a separate Vue component for everything related to maps and location. Within the project's src/components directory create a LeafletMap.vue file with the following boilerplate code:

<template>
    <div>
        <div ref="map" style="width: 100vw; height: 100vh;"></div>
    </div>
</template>

<script>
    import axios from "axios";
    export default {
        name: "LeafletMap",
        data() {
            return {
                platform: {},
                map: {},
                sequenceMarkerGroup: {}
            }
        },
        props: {
            appId: String,
            appCode: String,
            latitude: String,
            longitude: String
        },
        created() { },
        async mounted() { },
        methods: {
            dropMarker(position, text) { },
            async calculateRouteSequence(places) { },
            drawRoute(sequence) { }
        }
    }
</script>

<style></style>


You'll notice in the above code that we have several properties, several methods, and a few life-cycle events that are a part of Vue. The Props will represent properties passed when the component is created, the mounted method will load the map when the application starts, and each of the methods will help us with our Waypoint Sequence and drawing.

A lot of the above code was explored in other tutorials that I've written on the subject of Leaflet.js.

Let's first draw our map. Within the mounted method, include the following:

async mounted() {
    const tiles = "https://1.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day/{z}/{x}/{y}/512/png8?app_id={appId}&app_code={appCode}";
    this.map = new L.Map(this.$refs.map, {
        center: [this.latitude, this.longitude],
        zoom: 10,
        layers: [L.tileLayer(tiles, { appId: this.appId, appCode: this.appCode })]
    });
},


To use Leaflet, we need to supply it map tiles. Using the HERE Map Tile API and a valid app id and app code from the HERE Developer Portal, we can configure our map.

Make note that the this.$refs.map parameter references the ref attribute found within the <template> block.

To use this component, open the project's src/App.vue file and include the following:

<template>
    <div id="app">
        <LeafletMap
            ref="map"
            appId="APP_ID_HERE"
            appCode="APP_CODE_HERE"
            latitude="37.7297"
            longitude="-121.4252"
        />
    </div>
</template>

<script>
    import LeafletMap from './components/LeafletMap.vue'

    export default {
        name: 'app',
        components: {
            LeafletMap
        },
        async mounted() {
            let map = this.$refs.map;
        }
    }
</script>

<style>
    body {
        margin: 0;
    }
</style>


In the above code we are importing the LeafletMap class and including it with the necessary properties for rendering. We should be up to speed now when it comes to the Leaflet.js foundation.

Calculate the Waypoint Sequence With HERE and HTTP Requests

The focus of this tutorial is around the HERE Waypoint Sequence API and calculating the sequence of waypoints for a optimal route. Before we start playing around with the API, let's define a bunch of positions to be used.

Within the src/App.vue file, add the following to the mounted function:

let mockPlaces = [
    { latitude: 37.74682893940135, longitude: -121.4198684692383 },
    { latitude: 37.73488314788311, longitude: -121.44561767578126 },
    { latitude: 37.72076290898376, longitude: -121.41712188720705 },
    { latitude: 37.74251196215947, longitude: -121.435 },
    { latitude: 37.731793096495316, longitude: -121.41770044283479 },
    { latitude: 37.74, longitude: -121.46 },
    { latitude: 37.72, longitude: -121.455 }
];


The above is just an array of positions in no particular order, and existing somewhere around the center point of my map. Now that we have some data, let's make use of the API.

In the calculateRouteSequence function of the project's src/components/LeafletMap.vue file, include the following:

async calculateRouteSequence(places) {
    let waypoints = {};
    for(let i = 0; i < places.length; i++) {
        waypoints["destination" + (i + 1)] = `${places[i].latitude},${places[i].longitude}`;
    }
    return axios({
        "method": "GET",
        "url": "https://wse.api.here.com/2/findsequence.json",
        "params": {
            "start": `${this.latitude},${this.longitude}`,
            ...waypoints,
            "end": `${this.latitude},${this.longitude}`,
            "mode": "fastest;car;traffic:enabled",
            "departure": "now",
            "app_id": this.appId,
            "app_code": this.appCode
        }
    }).then(response => {
        return response.data.results[0].waypoints
    });
},


The places parameter represents the mockPlaces array that we had just created. We need to properly format that data in a way that the API expects, so we loop through the array and format it more like the following:

waypoints: {
    "destination0": "...",
    "destination1": "...",
    "destination2": "...",
}


Once we have all of our properly formatted waypoints in no particular order, we can make a request with the axios library. The start and end positions can represent the warehouse that we're starting at and the warehouse that we need to return to after all of our packages are delivered.

The response to our request will be our ordered sequence of waypoints.

To use the calculateRouteSequence function, go to the project's src/App.vue file and include the following in the mounted function:

let sequence = await map.calculateRouteSequence(mockPlaces);


Having the sequence as raw data isn't particularly exciting. Instead we can draw markers at each point in the sequence and give them a number. This way we can see which marker represents which stop in our path.

Within the project's src/components/LeafletMap.vue file, add the following to the dropMarker method:

dropMarker(position, text) {
    let icon = L.divIcon({
        html: `
            <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
                <circle cx="25" cy="25" r="25" fill="#000000" />
                <text x="50%" y="50%" text-anchor="middle" fill="white" font-size="25px" dy=".3em">${text}</text>
            </svg>
        `.trim()
    });
    L.marker([position.lat, position.lng], { icon: icon }).addTo(this.sequenceMarkerGroup);
    this.sequenceMarkerGroup.addTo(this.map);
    this.map.fitBounds(this.sequenceMarkerGroup.getBounds());
},


Leaflet doesn't have a good way to add text to markers unless you're using an SVG marker. For that reason, we can take a position and some text, whip up a dynamic SVG, then add it to the map.

It is a good idea to use a marker group so the markers can be centered on. You can initialize your marker group in the created method:

created() {
    this.sequenceMarkerGroup = new L.featureGroup();
},


To drop these markers, we need to revisit the project's src/App.vue file:

for(let i = 0; i < sequence.length - 1; i++) {
    map.dropMarker(sequence[i], i.toString());
}


Because the starting point and the ending point are the same, we're not looping until the very last point, otherwise, our starting marker would be replaced with our ending marker. Not a huge problem, but it can be confusing to look at.

Now that we have the best sequence discovered, we can work towards actually navigating between these waypoints.

Calculating the Path Between Waypoints With the HERE Routing API

To calculate a route that can be navigated, the standard HERE Routing API can be used.

In the project's src/components/LeafletMap.vue file, add the following to the drawRoute function:

drawRoute(sequence) {
    let waypoints = {};
    for(let i = 0; i < sequence.length; i++) {
        waypoints["waypoint" + i] = `${sequence[i].lat},${sequence[i].lng}`;
    }
    axios({
        "method": "GET",
        "url": "https://route.api.here.com/routing/7.2/calculateroute.json",
        "params": {
            "mode": "fastest;car;traffic:enabled",
            "representation": "display",
            ...waypoints,
            "app_id": this.appId,
            "app_code": this.appCode
        }
    }).then(result => {
        let shape = result.data.response.route[0].shape;
        let line = shape.map(point => {
            let [lat, lng] = point.split(",");
            return { lat: lat, lng: lng };
        });
        new L.Polyline(line, {snakingSpeed: 500}).addTo(this.map).snakeIn();
    }, error => {
        console.error(error);
    });
}


What's happening in the drawRoute function isn't too much different than what's happening in the calculateRouteSequence function. First the sequence data is formatted and it is added to the axios request to the API.

The results of the route calculation will consist of points which can be added to a polyline and rendered on the map. We're using the snake animation library here so that way a nice animation happens for our long route between start and finish.

To make use of this drawRoute function, we can add it to the project's src/App.vue file like so:

map.drawRoute(sequence);


Just like that, we have a best-calculated route for our driver or whoever might need an optimized route between waypoints.

Conclusion

The Waypoint Sequence Extension API that HERE offers is very powerful and is a great candidate for solving the "traveling salesman" problem that a lot of organizations face. While we didn't need to use Leaflet, I felt the animation library for polylines gave a great visualization to what we were trying to solve.

Further Reading

How Does Path Planning for Autonomous Vehicles Work?

API Vue.js

Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Mocking Dependencies and AI Is the Next Frontier in Vue.js Testing
  • Building Micro-Frontends With Vue and Reusable Components
  • Designing a Java Connector for Software Integrations
  • Vibe Coding With GitHub Copilot: Optimizing API Performance in Fintech Microservices

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!