Skip to main content

Integrating the HERE Raster Tile V3 & Traffic APIs with Leaflet.js

HERE Raster Tile Traffic & Leaflet

Introduction

There are many ways to build a web mapping application. Increasingly, mobile friendly solutions are a must, and HERE has a very robust Maps API for JavaScript to build incredibly feature rich web applications. We build with it on our team exclusively. Some customers though have already built web apps with other client-side JavaScript libraries, such as Leaflet.js or other open-source options. While we do not support those, it is possible to integrate with leaflet and call HERE APIs. This blog post serves as a tutorial for existing leaflet users looking to branch out and add HERE to their applications. 

This post covers adding the HERE Raster Tile API v3 (previously the HERE Map Tile API, which is deprecated) to use as a base map, additionally we will add the HERE Traffic API to overlay (display) real-time traffic conditions for an area of interest as a basic demonstration of adding other data layers. 

Note: If you are looking to switch to the HERE Maps API for JavaScript, its vector based rendering is preferred (HARP engine) as it is much more dynamic and offers high quality layers and labeling among other advantages. For expanded functionality through building with the Maps API for JS, you can find the developer guide here.

Prerequisites & Project Setup

To complete this web mapping application you will need:

  1. A free HERE platform account.
  2. Credentials to authenticate (we need an API Key or Bearer Token). This example uses an API Key.
  3. A text editor, such as Visual Studio Code, notepad ++ or similar.
  4. A general understanding of JavaScript/HTML/CSS helps.
  5. A Web server or local server for testing (I like Netlify or the VS Code extension “Live Server.”  

You need a project folder with your index.html and script.js. Feel free to use the source code or boilerplate files below or build your own. For adding elements such as legend styling, we’ll use html in a style tag as opposed to CSS for simplicity.

Step 1: Initializing the Map with Leaflet

Within the index.html, we can see how this is structured to include leaflet within the body tag:

Copied
        <body>
    <div id="map"></div>
    <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
    <script src="script.js"></script>
</body>
  

For the script file, to initialize a Leaflet map we need to ensure the following JS object is declared which also sets a default latitude and longitude and zoom level:

Copied
        //Initalize Leaflet Map
document.addEventListener('DOMContentLoaded', function() {
    const map = L.map('map', {
        center: [47.606209, -122.332069],
        zoom: 13
    });
  

Note: 'Const' is used to declare variables that hold references to map objects, API endpoints, and other configurations because these references typically do not change once they are set. Using const makes the intent clear and helps prevent bugs related to accidental reassignment. In the boilerplate var might be used for broader compatibility, especially in contexts where ES6 support isn't guaranteed. However, in modern JavaScript development, especially when ES6 or later is supported, it's recommended to use let and const. So use what you need.

Step 2: Authenticate and add a Base Map using the HERE Raster Tile API V3

To be an actual "map" we will add a base map to give some geographical context. With your authentication in hand we will call the Raster Tile API V3 to configure the base map layer. We use a simple JavaScript object to store the API key, which allows it to be easily accessible throughout our application.

Copied
        // HERE base map layer and authorization using the new Map Tile API
const here = {
apiKey: 'YOUR_API_KEY' // Replace with your actual API key
};
  

Note:

Ideally you would secure the API Key to not be imbedded but this is a basic example. It's critical to protect your API keys.

After setting up our API key in the previous section, the next step is to select a map style and integrate the tile layer into our Leaflet map. HERE's Raster Tile API offers a variety of map styles, allowing us to choose one that best fits our application's needs and ultimate change how elements of a map are represented. As the API provides map tiles, (small, pre-rendered images), it is an easy way to display a map in the browser. 

Define a preferred map style:

Copied
        const style = 'lite.day';
  

Raster Tile Endpoint:
Next, we construct the dynamic URL for fetching the map tiles. This URL follows a specific pattern required by the HERE Raster Tile API V3, and we can construct it with our API key and style. This dynamic URL construction allows Leaflet to request the exact map tiles needed for the current map view, ensuring efficient and accurate map rendering:

Copied
        const hereTileUrl = `https://maps.hereapi.com/v3/base/mc/{z}/{x}/{y}/png8?style=your_style&apiKey=your_api_key`;
L.tileLayer(hereTileUrl).addTo(map);
  

Understanding the URL Components

  • ${style} will be replaced by the value of the style variable, which is defined in your JavaScript code (const style = 'lite.day';).
  • ${here.apiKey} will be replaced by the value of here.apiKey, which should be your HERE API key.
  • https://maps.hereapi.com/v3/base/mc/: This is the base URL for the Raster Tile API V3.
  • {z}/{x}/{y}: These placeholders are automatically replaced by Leaflet with the appropriate zoom level (z) and tile coordinates (x, y) to load the correct map section.
  • png8: Specifies the image format (PNG) and bit depth (8-bit) for the tiles.
  • style=${style}: Applies our chosen map style.
  • apiKey=${here.apiKey}: Authenticates our request using the API key defined earlier.

Note: We can use dollar curly braces ${} in JavaScript String Template: The ${style} and ${here.apiKey} are examples of JavaScript template literals (also known as template strings). In a template literal, you can embed expressions inside ${}. JavaScript will evaluate these expressions and insert their results into the string.

Step 3: Fetching and Displaying Real-Time Traffic Data

  • Using HERE Traffic API: Explanation of fetching traffic data using HERE API.
  • Processing Data: How to process and display the JSON data on the map. (loop through the data)

To access real-time traffic data, we make a request to the API endpoint with specific parameters. The Traffic API v7 provides flow and incident information. The example below will focus on flow data.:

Copied
        const hereTrafficApiUrl = `https://data.traffic.hereapi.com/v7/flow?locationReferencing=shape&in=bbox:-122.351018,47.571051,-122.275047,47.658364&apiKey=${here.apiKey}`;

  

Understanding the URL Components

  • locationReferencing=shape: Specifies the format of the traffic data.
  • in=bbox:...: Is the region to request flow data within. It also defines the bounding box coordinates of that area for which we want traffic data. See more on geospatial filtering.
  • apiKey: As with the Raster Tile API, it authenticates our request with your HERE API key defined earlier as a JavaScript object.
Making the Request

We use JavaScript's fetch function to make the request and process the response:

Copied
        fetch(hereTrafficApiUrl)
   .then(response => response.json())
   .then(data => {
       // Process and visualize the traffic data
   })
   .catch(error => console.error('Error fetching traffic data:', error));

  

What do we get back from the API? To understand the Traffic Data Structure you can use Postman but here is a sample of the JSON format data. It includes detailed information about each road segment within the requested area:
 

Copied
        {
   "results": [
       {
           "location": {
               "shape": {
                   "links": [
                       {
                           "points": [{"lat": 47.606, "lng": -122.332}, ...],
                           "currentFlow": {"speed": 40, "jamFactor": 2}
                       },
                       // Additional links...
                   ]
               }
           }
       },
       // Additional results...
   ]
}

  

For detailed documentation on the flow data review this doc. In a nutshell, each item in the results array represents a segment of the road. Key details include:

  • shape.links: An array of road segments.
  • points: Latitude and longitude coordinates defining the road segment.
  • currentFlow: The current traffic flow, including speed and jamFactor (the latter will be used to symbolize).

To be able to see this as a meaningful visual, we need to loop through each item in the 'results' and extract them:

Copied
        data.results.forEach(item => {
   const links = item.location.shape.links;
   links.forEach(link => {
       // Process each road segment
   });
});

  

This code snippet is responsible for creating the visual elements: For each road segment (link), we use its points to draw a line on the map. The line's color and thickness can be adjusted based on traffic speed and congestion (in this example using jamFactor).

We can also add interactivity by binding pop-up content to each line, which provides viewers with detailed information about the traffic flow when they hover over different segments of the road (this is included in the full sample files).

Step 4: Visualizing Traffic with Dynamic Line Colors

To enhance the user experience we can use dynamic line colors as a way to represent the different traffic conditions based on JamFactor

Mapping "JamFactor" to Colors

The JamFactor is a key metric in our traffic data. It ranges from 0 (no congestion) to 10 (heavy congestion). To simplify, we can categorize this range into three main congestion levels and assign a color to each:

  1. Low Congestion (0-3): Green signifies smooth traffic.
  2. Moderate Congestion (4-7): Orange indicates slower moving traffic.
  3. High Congestion (8-10): Red represents heavy traffic or traffic jams.
Color Determination Logic

We will use a simple conditional logic to assign colors based on the Jam Factor:

Copied
        function getLineColor(jamFactor) {
   if (jamFactor <= 3) {
       return '#2ECC40'; // Green for low congestion
   } else if (jamFactor <= 7) {
       return '#FF851B'; // Orange for moderate congestion
   } else {
       return '#FF4136'; // Red for high congestion
   }
}
  
Applying Color to Map Lines

As we process our traffic data, we use a function to set the color of each line (representing road segments) on the map:

Copied
        data.results.forEach(item => {
   item.location.shape.links.forEach(link => {
       const points = link.points.map(point => new L.LatLng(point.lat, point.lng));
       const lineColor = getLineColor(link.currentFlow.jamFactor);
       L.polyline(points, { color: lineColor, weight: 5 }).addTo(trafficLayerGroup);
   });
});
  

This allows us to:

  • Convert each link's points to LatLng objects.
  • getLineColor determines the line color based on the JamFactor.
  • Create a polyline with the specific color representing congestion ranges and add it to the map.


Step 5: Adding a Custom Legend

To make sense of this, we can add a simple legend to the map. As with the line colors we will have three entries tied to a range of the Jam Factor:

  1. Low Congestion (Green)
  2. Moderate Congestion (Orange)
  3. High Congestion (Red)

Each entry will include a color swatch and a description and we will add to our script file logic for implementing the legend and then use html Style tag in our html file.

Implementing the Legend in Code

We'll use Leaflet's L.control method to create a new control and then define its appearance and content:

Copied
        var legend = L.control({position: 'bottomright'});

legend.onAdd = function (map) {
    var div = L.DomUtil.create('div', 'info legend'),
        jamFactorClasses = [
            { range: "0 - 3", description: "Low Congestion", color: "#2ECC40" },
            { range: "4 - 7", description: "Moderate Congestion", color: "#FF851B" },
            { range: "8 - 10", description: "High Congestion", color: "#FF4136" }
        ],
        labels = [];

    // Add the title
    labels.push('<h4>Jam Factor</h4>');

    jamFactorClasses.forEach(function (jfClass) {
        labels.push(
            '<div class="label">' +
                '<i style="background:' + jfClass.color + '"></i> ' +
                jfClass.range + ': ' + jfClass.description +
            '</div>');
    });

    div.innerHTML = labels.join('');
    return div;
};

legend.addTo(map);
  

This does 5 primary things:

  • Specifies the position of the legend (bottomright).
  • A title is added to the legend called "Jam Factor"
  • The forEach loop dynamically adds each congestion level to the legend, with a color swatch and descriptive text.
  • The labels.join('') combines all parts into a single HTML string and then sets as the content of the legend's div.
  • Adds the legend to the map.
Styling the legend

Open the index.html to add the legend's appearance using CSS. For simplicity, we can add the CSS directly into our HTML file within <style> tags:

Copied
        <style>
 body, html { border: 0; padding: 0; margin: 0; }
           #map { width: 100vw; height: 100vh; }
           
    /* Legend styling */
    .legend {
    padding: 6px 8px;
    background: rgba(255, 255, 255, 0.8);
    box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
    border-radius: 5px;
    color: #555;
}

.legend i {
    width: 18px;
    height: 18px;
    float: left;
    margin-right: 8px;
    border: 1px solid #888;
}

.legend .label {
    display: flex;
    align-items: center;
    margin-bottom: 4px;
}
    
    /* Add style for the legend title */
    .legend h3 {
        text-align: center;
        margin: 0 0 10px 0;
        padding: 0;
        color: #333;
        font-size: 16px;
    }
</style>
  

With the addition of a custom legend, our traffic visualization web app has some substance and is a more effective tool for visualizing real-time traffic conditions. The complete app will look similar to this:

Conclusion

We now have a functional interactive real-time traffic app over Seattle with basic visual elements and navigation. To summarize, we integrated HERE real-time traffic data, leveraged the new Raster Tile API V3 for a base map, then applied visualizations and a custom legend. From here, there are many directions we could go. Some ideas:

  1. User Interaction: Incorporate features that allow users to interact with the map, such as clicking on a road segment to get more detailed traffic reports.
  2. Data Filters: Implement filters to view traffic data for specific times of day or specific road types or other variables.
  3. Traffic Data Analysis: Comparisons over different times or days.
  4. Route Planning: Add functionality to plan routes directly on the map.
  5. Localization and Accessibility: Implement features for localization (supporting multiple languages) and accessibility

Checkout the source code for expanded functionality. We will follow this up with a similar build that uses the HERE Maps API for JS to showcase its true power and flexibility for creating dynamic high quality web apps.

Thanks for reading! Drop us a line if you have any feedback or questions below or come by is our Slack workspace

X @heredev

 

 

Aaron Falk

Aaron Falk

Principal Developer Evangelist

Have your say

Sign up for our newsletter

Why sign up:

  • Latest offers and discounts
  • Tailored content delivered weekly
  • Exclusive events
  • One click to unsubscribe