Integrating HERE Maps API for JavaScript with ASP.NET MVC
This comprehensive blog post details the step-by-step process of integrating HERE Maps into an ASP.NET MVC project. This how-to guide aims to help developers and customers troubleshoot common issues with HERE Maps integration within the ASP.net environment. It provides:
- A clear setup guide for ASP.NET MVC projects.
- Detailed instructions on incorporating HERE Maps JavaScript libraries.
- Practical examples of implementing and customizing map functionalities
- Tips for handling interactive map elements and route visualizations.
Prerequisites
• Visual Studio installed for Windows or Visual Studio Code installed for Mac.
• If using Mac and terminal make sure to install .NET Core SDK.
• Basic understanding of ASP.NET MVC.
• A HERE platform account to obtain an API key.
Step 1: Creating an ASP.NET MVC Project
1. Open Visual Studio and select "Create a new project."
2. Choose the "ASP.NET Core Web Application" template and click "Next."
3. Name your project HereMapsProject and click "Create."
4. Select "Web Application (Model-View-Controller)" and ensure .NET Core and ASP.NET Core are selected. Click "Create."
Or (from Mac Terminal)
1. mkdir HereMapsIntegration
2. cd HereMapsIntegration
3. dotnet new mvc
Step 2: Adding Dependencies
Include the HERE Maps API for JavaScript by referencing the necessary files in your project.
Step 3: Creating the Layout
The _Layout.cshtml file in ASP.NET MVC defines the common layout for your web pages. Here’s how we set it up:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - HereMapsProject</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/HereMapsProject.styles.css" asp-append-version="true" />
<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
<script src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-harp.js" charSet="utf-8"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">HereMapsProject</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2024 - HereMapsProject - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Step 4: Creating the Home View
The Index.cshtml file defines the content for the home page. Here’s how it looks:
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome to HERE Maps Integration</h1>
<p>Explore the map integration below.</p>
</div>
<!-- Map container -->
<div id="jobHereRouteMap" style="width: 100%; height: 500px;"></div>
<!-- Directions panel -->
<div id="here-directions-panel" style="width: 100%;"></div>
@section Scripts {
<!-- Ensure the paths are correct; they should point to where your scripts are located in the wwwroot/js folder -->
<script src="~/js/hereMapsIntegration.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Configuration object for the DFHereMap function
var config = {
mapDivId: 'jobHereRouteMap',
directionsPanelId: 'here-directions-panel',
initialLat: 52.53086, // You can adjust these coordinates
initialLng: 13.38469,
apiKey: 'yourapikey' // Replace this with your actual HERE API key
};
try {
var hereMap = new DFHereMap(config);
hereMap.initialize();
} catch (e) {
console.error("Error initializing the map:", e);
}
});
</script>
}
Step 5: Creating the JavaScript Integration
The hereMapsIntegration.js file contains the JavaScript code to integrate HERE Maps. Here’s the complete code:
DFHereMap Function
1. Initialization:
var herePlatform = new H.service.Platform({
'apikey': 'yourapikey'
});
This initializes the HERE platform with your API key.
2. Engine and Layers:
var engineType = H.Map.EngineType['HARP'];
var defaultLayers = herePlatform.createDefaultLayers({
engineType: H.Map.EngineType['HARP']
});
Configures the map to use the HARP engine and default layers.
3. Map Container:
var mapDiv = document.getElementById(configuration.mapDivId);
if (!mapDiv) {
console.error("Map div not found");
return;
}
Retrieves the HTML element where the map will be rendered.
4. Map Initialization:
var map = new H.Map(mapDiv, defaultLayers.vector.normal.map, {
zoom: 14,
engineType: H.Map.EngineType['HARP'],
center: { lat: configuration.initialLat, lng: configuration.initialLng }
});
Initializes the map with default settings.
5. Map Events and UI:
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var ui = H.ui.UI.createDefault(map, defaultLayers);
Adds interactivity and default UI controls to the map.
6. Route Instructions Panel:
var routeInstructionsContainer = document.getElementById(configuration.directionsPanelId);
Retrieves the HTML element where route instructions will be displayed.
7. Waypoint Marker:
var waypointMarkers = [];
var routeLine, rerouteLine, currentRoute;
var svgCircle = '<svg width="20" height="20" version="1.1" xmlns="http://www.w3.org/2000/svg">' +
'<circle cx="10" cy="10" r="7" fill="blue" stroke="blue" stroke-width="4"/>' +
'</svg>';
var waypointCreateMarker = new H.map.Marker({
lat: 0,
lng: 0,
visibility: false,
volatility: true
}, {
icon: new H.map.Icon(svgCircle, {
anchor: { x: 10, y: 10 }
})
});
waypointCreateMarker.draggable = true;
map.addObject(waypointCreateMarker);
Defines a custom marker for waypoints on the map.
8. Centering the Map:
this.setCenter = function(lat, lng) {
map.setCenter({ lat: lat, lng: lng });
};
A method to center the map at specified coordinates.
9. Drawing the Route:
this.drawRoute = function(route) {
if (routeLine) {
map.removeObject(routeLine);
}
var linestrings = [];
route.sections.forEach((section) => {
linestrings.push(H.geo.LineString.fromFlexiblePolyline(section.polyline));
});
var multiLineString = new H.geo.MultiLineString(linestrings);
routeLine = new H.map.Polyline(multiLineString, {
style: { lineWidth: 10, strokeColor: 'rgba(0, 128, 255, 0.7)' }
});
map.addObject(routeLine);
map.getViewModel().setLookAtData({ bounds: routeLine.getBoundingBox() });
this.addManeuversToPanel(route);
};
Draws the calculated route on the map.
10. Adding Maneuvers to the Panel:
this.addManeuversToPanel = function(route) {
var nodeOL = document.createElement('ol');
nodeOL.style.fontSize = 'small';
nodeOL.style.marginLeft = '5%';
nodeOL.style.marginRight = '5%';
nodeOL.className = 'directions';
route.sections.forEach((section) => {
section.actions.forEach((action) => {
var li = document.createElement('li');
var spanArrow = document.createElement('span');
var spanInstruction = document.createElement('span');
spanArrow.className = 'arrow ' + (action.direction || '') + action.action;
spanInstruction.innerHTML = action.instruction;
li.appendChild(spanArrow);
li.appendChild(spanInstruction);
nodeOL.appendChild(li);
});
});
routeInstructionsContainer.innerHTML = '';
routeInstructionsContainer.appendChild(nodeOL);
};
Populates the directions panel with turn-by-turn instructions.
11. Requesting a Route:
this.requestRoute = function(origin, destination) {
var router = herePlatform.getRoutingService(null, 8);
var routingParameters = {
routingMode: 'fast',
transportMode: 'car',
origin: origin,
destination: destination,
return: 'polyline,turnByTurnActions,actions,instructions,travelSummary'
};
router.calculateRoute(routingParameters, (result) => {
this.drawRoute(result.routes[0]);
}, (error) => {
console.error('Routing error:', error.message);
});
};
Sends a request to the HERE Routing API to calculate a route.
12. Initializing the Map:
this.initialize = function() {
this.requestRoute('52.5160,13.3779', '48.8566,2.3522');
};
Initializes the map with a default route.
13. Utility to Remove Route Line:
function removeRouteLine() {
if (routeLine) {
map.removeObject(routeLine);
routeLine = null;
}
}
Removes the existing route line from the map.
Complete JavaScript Code
function DFHereMap(configuration) {
var herePlatform = new H.service.Platform({
'apikey': 'yourapikey'
});
var engineType = H.Map.EngineType['HARP'];
var defaultLayers = herePlatform.createDefaultLayers({
engineType: H.Map.EngineType['HARP']
});
var mapDiv = document.getElementById(configuration.mapDivId);
if (!mapDiv) {
console.error("Map div not found");
return;
}
var map = new H.Map(mapDiv, defaultLayers.vector.normal.map, {
zoom: 14,
engineType: H.Map.EngineType['HARP'],
center: { lat: configuration.initialLat, lng: configuration.initialLng }
});
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var ui = H.ui.UI.createDefault(map, defaultLayers);
var routeInstructionsContainer = document.getElementById(configuration.directionsPanelId);
var waypointMarkers = [];
var routeLine, rerouteLine, currentRoute;
var svgCircle = '<svg width="20" height="20" version="1.1" xmlns="http://www.w3.org/2000/svg">' +
'<circle cx="10" cy="10" r="7" fill="blue" stroke="blue" stroke-width="4"/>' +
'</svg>';
var waypointCreateMarker = new H.map.Marker({
lat: 0,
lng: 0,
visibility: false,
volatility: true
}, {
icon: new H.map.Icon(svgCircle, {
anchor: { x: 10, y: 10 }
})
});
waypointCreateMarker.draggable = true;
map.addObject(waypointCreateMarker);
this.setCenter = function(lat, lng) {
map.setCenter({ lat: lat, lng: lng });
};
this.drawRoute = function(route) {
if (routeLine) {
map.removeObject(routeLine);
}
var linestrings = [];
route.sections.forEach((section) => {
linestrings.push(H.geo.LineString.fromFlexiblePolyline(section.polyline));
});
var multiLineString = new H.geo.MultiLineString(linestrings);
routeLine = new H.map.Polyline(multiLineString, {
style: { lineWidth: 10, strokeColor: 'rgba(0, 128, 255, 0.7)' }
});
map.addObject(routeLine);
map.getViewModel().setLookAtData({ bounds: routeLine.getBoundingBox() });
this.addManeuversToPanel(route);
};
this.addManeuversToPanel = function(route) {
var nodeOL = document.createElement('ol');
nodeOL.style.fontSize = 'small';
nodeOL.style.marginLeft = '5%';
nodeOL.style.marginRight = '5%';
nodeOL.className = 'directions';
route.sections.forEach((section) => {
section.actions.forEach((action) => {
var li = document.createElement('li');
var spanArrow = document.createElement('span');
var spanInstruction = document.createElement('span');
spanArrow.className = 'arrow ' + (action.direction || '') + action.action;
spanInstruction.innerHTML = action.instruction;
li.appendChild(spanArrow);
li.appendChild(spanInstruction);
nodeOL.appendChild(li);
});
});
routeInstructionsContainer.innerHTML = '';
routeInstructionsContainer.appendChild(nodeOL);
};
this.requestRoute = function(origin, destination) {
var router = herePlatform.getRoutingService(null, 8);
var routingParameters = {
routingMode: 'fast',
transportMode: 'car',
origin: origin,
destination: destination,
return: 'polyline,turnByTurnActions,actions,instructions,travelSummary'
};
router.calculateRoute(routingParameters, (result) => {
this.drawRoute(result.routes[0]);
}, (error) => {
console.error('Routing error:', error.message);
});
};
this.initialize = function() {
this.requestRoute('52.5160,13.3779', '48.8566,2.3522');
};
// Additional utilities and methods as required
function removeRouteLine() {
if (routeLine) {
map.removeObject(routeLine);
routeLine = null;
}
}
}
Running the Project
1. Place the JavaScript file hereMapsIntegration.js in the wwwroot/js folder of your project.
2. Ensure the paths in _Layout.cshtml is in the Views/Shared folder, and Index.cshtml is in the Views/Home folder inside the root of the project.
3. Run the project by pressing F5 or clicking the run button in Visual Studio in Windows or Visual Studio Code if you are using Mac, you can also run the project by going to the root of the project and type command “dotnet run” from the terminal.
3. The application will run at http://localhost:5139
Conclusion
By following this blog, you have successfully integrated HERE Maps into your ASP.NET MVC project. This integration allows you to display maps, calculate routes, and provide turn-by-turn navigation. The detailed explanation of each code snippet ensures you understand how each part of the integration works, empowering you to customize and expand upon this foundation.
Thanks for reading! Drop us a line if you have any feedback or questions below or come by is our Slack workspace!
X @heredev
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