Isoline Mapping With HERE in an Ionic Framework Progressive Web Application
In this post, we learn how to create an Ionic application and use it to create a map application.
Join the DZone community and get the full member experience.
Join For FreeI've been giving quite a few demonstrations of isoline graphs, both in person and through previous blog tutorials. It is, in my opinion, one of the most awesome features that HERE offers to developers because of how little is required from the developer while accomplishing so much. In case you're unfamiliar, an isoline is a calculation from a starting point and some range value. Given this information we can visualize how long it might take us to get somewhere within that range or how far we can get. This is not to be confused with a radius which might be inaccurate based on traffic or roads that cannot be traveled.
You might remember that I previously demonstrated how to work with isolines using strictly Angular, but this time around we're going to take a look at working with isolines using the progressive web application framework, Ionic.
To get an idea of what we hope to accomplish, take a look at the following animated image:
To keep things simple, we're only going to be worrying about displaying an isoline at our map's center rather than collecting user input as part of a search functionality. You'll notice that this is compatible in the web as well as a mobile Android or iOS application.
Building an Ionic Framework With HERE Maps Application
To start this project we are going to create a new project. However, we'll be using Ionic 4.x and a lot of this code will be recycled from a previous tutorial that was centered around Leaflet, which is a third party rendering library. In this particular tutorial, we'll use the default renderer rather than Leaflet.
Assuming the Ionic CLI is installed, execute the following:
ionic start HereMapsProject blank
The above command will create a new blank project with only one page. We're going for simplicity in an effort to eliminate any confusion that might come out of this subject material.
Now that we have our project, we need to get up to speed with our mapping component. Because I already wrote extensively on the configuration, we're going to breeze through this with minor detail.
Open the project's src/index.html file so we can include our HERE JavaScript SDK:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Ionic HERE Map</title>
<base href="/" />
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<link rel="icon" type="image/png" href="assets/icon/favicon.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.0/mapsjs-ui.css?dp-version=1533195059" />
</head>
<body>
<app-root></app-root>
<script src="https://js.api.here.com/v3/3.0/mapsjs-core.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.0/mapsjs-service.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.0/mapsjs-places.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.0/mapsjs-mapevents.js" type="text/javascript" charset="utf-8"></script>
<script src="https://js.api.here.com/v3/3.0/mapsjs-ui.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
To give us isoline functionality, we've included several of the JavaScript components as well as the CSS library. Different HERE functionality will require different components.
With the JavaScript SDK in place, we need to create our map component by executing the following:
ionic generate component here-map
The above command will create several files, this first of which is for our HTML markup. Open the project's src/app/here-map/here-map.component.html file and include the following:
<div #map style="width: 100%; height: 100%;"></div>
With the container for our map in place, we can start developing the TypeScript logic to go with it. Open the project's src/app/here-map/here-map.component.ts file and include the following:
import { Component, OnInit, ViewChild, ElementRef, Input } from '@angular/core';
declare var H: any;
@Component({
selector: 'here-map',
templateUrl: './here-map.component.html',
styleUrls: ['./here-map.component.scss']
})
export class HereMapComponent implements OnInit {
@ViewChild("map")
public mapElement: ElementRef;
@Input()
public appId: any;
@Input()
public appCode: any;
@Input()
public lat: any;
@Input()
public lng: any;
private platform: any;
private map: any;
private router: any;
public constructor() { }
public ngOnInit() {
this.platform = new H.service.Platform({
"app_id": this.appId,
"app_code": this.appCode
});
this.router = this.platform.getRoutingService();
}
public ngAfterViewInit() {
setTimeout(() => {
let defaultLayers = this.platform.createDefaultLayers();
this.map = new H.Map(
this.mapElement.nativeElement,
defaultLayers.normal.map,
{
zoom: 10,
center: { lat: this.lat, lng: this.lng }
}
);
let behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(this.map));
}, 100);
}
public isoline() { }
}
Everything should look pretty familiar up until now if you saw the previous tutorials I wrote. One difference between this code and the Leaflet code is how we are refreshing the component when the view has finished loading.
You'll notice that the entire ngAfterViewInit
method is wrapped with a setTimeout
. This is necessary because in the Ionic Framework, the view size isn't instantly ready, even in the lifecycle hooks that Angular offers. We could either add a timeout to the whole code, or we could optionally set a timeout like this:
setTimeout(() => {
this.map.getViewPort().resize();
}, 100);
What you decide to use is totally up to you. The use of the resize
method more similarly matches what I used in the Leaflet example where I used invalidateSize
instead.
Before we can start using the component in our pages, we need to add it to the module for the pages we wish to use it in. Open the project's src/app/home/home.module.ts file and make it look like the following:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { HereMapComponent } from '../here-map/here-map.component';
import { HomePage } from './home.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild([
{
path: '',
component: HomePage
}
])
],
declarations: [HomePage, HereMapComponent],
exports: [HereMapComponent]
})
export class HomePageModule {}
We've imported the HereMapComponent
and added it to the @NgModule
block. Finally we can use it in our page. Open the project's src/app/home/home.page.html file and include the following:
<ion-header>
<ion-toolbar>
<ion-title>
Ionic HERE Map
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<here-map appId="APP-ID-HERE" appCode="APP-CODE-HERE" lat="37.7397" lng="-121.4252"></here-map>
</ion-content>
You'll need to have registered for a free account with HERE in order to get your app id and app code values. But notice that these are the expected inputs that are defined in the previous TypeScript file. The lat
and lng
values will also represent our center point on the map as well as the center point to our isoline.
Just like I previously mentioned, the goal of this article was not to go in depth with showing HERE maps in an Ionic Framework application. This was already covered in my previous article titled, Interacting with a Leaflet Map in an Ionic Framework PWA. We just needed the foundation in place so we can work with isoline functionality.
Calculating an Isoline With a Center Point and Range Variable
With the application functional, we can worry about our isoline, which is actually just a few lines of code.
Open the project's src/app/here-map/here-map.component.ts file and include the following isoline
method:
public isoline() {
let params = {
"mode": "fastest;car;traffic:enabled",
"range": "300",
"rangetype": "time",
"departure": "now",
"start": this.lat + "," + this.lng
}
this.map.removeObjects(this.map.getObjects());
this.router.calculateIsoline(params, data => {
if(data.response) {
let center = new H.geo.Point(data.response.center.latitude, data.response.center.longitude),
isolineCoords = data.response.isoline[0].component[0].shape,
linestring = new H.geo.LineString(),
isolinePolygon,
isolineCenter;
isolineCoords.forEach(coords => {
linestring.pushLatLngAlt.apply(linestring, coords.split(','));
});
isolinePolygon = new H.map.Polygon(linestring);
isolineCenter = new H.map.Marker(center);
this.map.addObjects([isolineCenter, isolinePolygon]);
this.map.setViewBounds(isolinePolygon.getBounds());
}
}, error => {
console.error(error);
});
}
So what is happening in the above code?
To calculate an isoline, a few parameters must be defined. We need to know how the isoline is being measured, which in our case is transport by car with traffic being monitored. We need to know the range that we're measuring, which in our case is 300 seconds. Because traffic is involved, we need to specify a time to track where now
is the current traffic conditions rather than a date in the past. The start
point is the center of our isoline which for this example is the center of the map.
Every time we run this method we are going to clear the map. When we calculate the isoline we are going to get the coordinate information necessary from the response in order to draw our polygons and lines. We're also placing a marker at the given center of the isoline.
The calculation through the API is quite simple in comparison to what it could be if you had to do all of this by hand.
Conclusion
You just saw how to work with isolines in an Ionic Framework application that works for both the web as well as mobile. This particular example used the default HERE map and Ionic 4.x. If you're still using Ionic 3.x and you need help configuring your application to use HERE, you might check out my previous tutorial titled, Display an Interactive HERE Map in an Ionic Framework Application.
This example should build for the web with no added dependencies. If you wish to build for Android or iOS, you'll need Apache Cordova available to you. However, no changes to the code are necessary to cross build.
Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments