Angular Binding Geographic Data Models
The Ignite UI for Angular map component is designed to display geo-spatial data from shape files and/or geographic locations from data models on geographic imagery maps. The dataSource property of geographic series is used for the purpose of binding to data models. This property can be bound an array of custom objects.
Angular Binding Geographic Data Models Example
The following table summarized data structures required for each type of geographic series:
| Geographic Series | Properties | Description |
|---|---|---|
IgxGeographicSymbolSeriesComponent |
longitudeMemberPath, latitudeMemberPath |
Specifies names of 2 numeric longitude and latitude coordinates |
IgxGeographicHighDensityScatterSeriesComponent |
longitudeMemberPath, latitudeMemberPath |
Specifies names of 2 numeric longitude and latitude coordinates |
IgxGeographicProportionalSymbolSeriesComponent |
longitudeMemberPath, latitudeMemberPath, radiusMemberPath |
Specifies names of 2 numeric longitude and latitude coordinates and 1 numeric column for size/radius of symbols |
IgxGeographicScatterAreaSeriesComponent |
longitudeMemberPath, latitudeMemberPath, colorMemberPath |
Specifies names of 2 numeric longitude and latitude coordinates and 1 numeric column for triangulation of values |
IgxGeographicContourLineSeriesComponent |
longitudeMemberPath, latitudeMemberPath, valueMemberPath |
Specifies names of 2 numeric longitude and latitude coordinates and 1 numeric column for triangulation of values |
IgxGeographicShapeSeriesComponent |
shapeMemberPath |
Specifies the name of data column of dataSource items that contains the geographic points of shapes. This property must be mapped to an array of arrays of objects with x and y properties. |
IgxGeographicPolylineSeriesComponent |
shapeMemberPath |
Specifies the name of data column of dataSource items that contains the geographic coordinates of lines. This property must be mapped to an array of arrays of objects with x and y properties. |
Code Snippet
The following code shows how to bind the IgxGeographicSymbolSeriesComponent to a custom data model that contains geographic locations of some cities of the world stored using longitude and latitude coordinates. Also, we use the IgxGeographicPolylineSeriesComponent to plot shortest geographic path between these locations using the great circle maths of MapGeodesics, shown in full with the code below
<igx-geographic-map
#geoMap
height="100%"
width="100%"
zoomable="true">
</igx-geographic-map>
import { IgxGeographicMapComponent, IgxGeographicPolylineSeriesComponent, IgxGeographicSymbolSeriesComponent } from 'igniteui-angular-maps';
import { MarkerType } from 'igniteui-angular-charts';
// ...
/**
* Great circle maths for a map: the path between two locations, and how far apart they are.
*/
export class MapGeodesics {
// calculate geo-paths between two locations using great circle formula
public calcPaths(origin: any, dest: any): any[] {
let interval = 200;
let paths: any[] = [[]];
let pathID = 0;
let distance = this.calcDistance(origin, dest);
if (distance <= interval) {
paths[pathID].push({ x: origin.lon, y: origin.lat });
paths[pathID].push({ x: dest.lon, y: dest.lat });
} else {
let current = origin;
let previous = origin;
for (let dist = interval; dist <= distance; dist += interval)
{
previous = current
paths[pathID].push({ x: current.lon, y: current.lat });
let bearing = this.calcBearing(current, dest);
current = this.calcDestination(current, bearing, interval);
// ensure geo-path wrap around the world through the new date-line
if (previous.lon > 150 && current.lon < -150) {
paths[pathID].push({ x: 180, y: current.lat });
paths.push([]);
pathID++
current = { lon: -180, lat: current.lat }
} else if (previous.lon < -150 && current.lon > 150) {
paths[pathID].push({ x: -180, y: current.lat });
paths.push([]);
pathID++
current = { lon: 180, lat: current.lat }
}
}
paths[pathID].push({ x: dest.lon, y: dest.lat });
}
return paths;
}
// calculate bearing angle between two locations
public calcBearing(origin: any, dest: any): number
{
origin = this.toRadianLocation(origin);
dest = this.toRadianLocation(dest);
let range = (dest.lon - origin.lon);
let y = Math.sin(range) * Math.cos(dest.lat);
let x = Math.cos(origin.lat) * Math.sin(dest.lat) -
Math.sin(origin.lat) * Math.cos(dest.lat) * Math.cos(range);
let angle = Math.atan2(y, x);
return this.toDegreesNormalized(angle);
}
// calculate destination for origin location and travel distance
public calcDestination(origin: any, bearing: number, distance: number): any {
let radius = 6371.0;
origin = this.toRadianLocation(origin);
bearing = this.toRadians(bearing);
distance = distance / radius; // angular distance in radians
let lat = Math.asin(Math.sin(origin.lat) * Math.cos(distance) +
Math.cos(origin.lat) * Math.sin(distance) * Math.cos(bearing));
let x = Math.sin(bearing) * Math.sin(distance) * Math.cos(origin.lat);
let y = Math.cos(distance) - Math.sin(origin.lat) * Math.sin(origin.lat);
let lon = origin.lon + Math.atan2(x, y);
// normalize lon to coordinate between -180º and +180º
lon = (lon + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
lon = this.toDegrees(lon);
lat = this.toDegrees(lat);
return { lon: lon, lat: lat };
}
// calculate distance between two locations
public calcDistance(origin: any, dest: any): number {
origin = this.toRadianLocation(origin);
dest = this.toRadianLocation(dest);
let sinProd = Math.sin(origin.lat) * Math.sin(dest.lat);
let cosProd = Math.cos(origin.lat) * Math.cos(dest.lat);
let lonDelta = (dest.lon - origin.lon);
let angle = Math.acos(sinProd + cosProd * Math.cos(lonDelta));
let distance = angle * 6371.0;
return distance; // * 6371.0; // in km
}
public toRadianLocation(geoPoint: any): any {
let x = this.toRadians(geoPoint.lon);
let y = this.toRadians(geoPoint.lat);
return { lon: x, lat: y };
}
public toRadians(degrees: number): number
{
return degrees * Math.PI / 180;
}
public toDegrees(radians: number): number {
return (radians * 180.0 / Math.PI);
}
public toDegreesNormalized(radians: number): number
{
let degrees = this.toDegrees(radians);
degrees = (degrees + 360) % 360;
return degrees;
}
}
// ...
private mapGeodesics: MapGeodesics = new MapGeodesics();
public mapBindingDataModelOnViewInit(): void {
var geoMap = this.geoMap;
geoMap.updateZoomWindow({ left: 0.2, top: 0.1, width: 0.6, height: 0.6 });
var cityDAL = { lat: 32.763, lon: -96.663, country: "US", name: "Dallas" };
var citySYD = { lat: -33.889, lon: 151.028, country: "Australia", name: "Sydney" };
var cityNZL = { lat: -36.848, lon: 174.763, country: "New Zealand", name: "Auckland" };
var cityQTR = { lat: 25.285, lon: 51.531, country: "Qatar", name: "Doha" };
var cityPAN = { lat: 8.949, lon: -79.4, country: "Panama", name: "Panama" };
var cityCHL = { lat: -33.475, lon: -70.647, country: "Chile", name: "Santiago" };
var cityJAP = { lat: 35.683, lon: 139.809, country: "Japan", name: "Tokyo" };
var cityALT = { lat: 33.795, lon: -84.349, country: "US", name: "Atlanta" };
var cityJOH = { lat: -26.178, lon: 28.004, country: "South Africa", name: "Johannesburg" };
var cityNYC = { lat: 40.75, lon: -74.0999, country: "US", name: "New York" };
var citySNG = { lat: 1.229, lon: 104.177, country: "Singapore", name: "Singapore" };
var cityMOS = { lat: 55.75, lon: 37.7, country: "Russia", name: "Moscow" };
var cityROM = { lat: 41.88, lon: 12.52, country: "Italy", name: "Roma" };
var cityLAX = { lat: 34.0, lon: -118.25, country: "US", name: "Los Angeles" };
var flights = [
{ origin: cityDAL, dest: citySNG, color: "Green" },
{ origin: cityMOS, dest: cityNZL, color: "Red" },
{ origin: cityCHL, dest: cityJAP, color: "Blue" },
{ origin: cityPAN, dest: cityROM, color: "Orange" },
{ origin: cityALT, dest: cityJOH, color: "Black" },
{ origin: cityNYC, dest: cityQTR, color: "Purple" },
{ origin: cityLAX, dest: citySYD, color: "Gray" }
];
// the route first, so that the cities at either end of it draw on top
for (var i = 0; i < flights.length; i++) {
this.addFlightRoute(geoMap, flights[i]);
this.addFlightCities(geoMap, flights[i]);
}
}
/** the flight itself, as a great circle path between its two cities */
public addFlightRoute(geoMap: any, flight: any): void {
var geodesics = this.mapGeodesics;
var geoPath = geodesics.calcPaths(flight.origin, flight.dest);
var geoDistance = geodesics.calcDistance(flight.origin, flight.dest);
var geoRoutes = [{
points: geoPath,
origin: flight.origin,
dest: flight.dest,
distance: geoDistance,
time: geoDistance / 850
}];
var lineSeries = new IgxGeographicPolylineSeriesComponent();
lineSeries.dataSource = geoRoutes;
lineSeries.shapeMemberPath = "points";
lineSeries.shapeStrokeThickness = 9;
lineSeries.shapeOpacity = 0.5;
lineSeries.shapeStroke = flight.color;
geoMap.series.add(lineSeries);
}
/** the cities at either end, in the flight's own colour */
public addFlightCities(geoMap: any, flight: any): void {
var geoLocations = [flight.origin, flight.dest];
var symbolSeries = new IgxGeographicSymbolSeriesComponent();
symbolSeries.dataSource = geoLocations;
symbolSeries.markerType = MarkerType.Circle;
symbolSeries.latitudeMemberPath = "lat";
symbolSeries.longitudeMemberPath = "lon";
symbolSeries.markerBrush = "White";
symbolSeries.markerOutline = flight.color;
symbolSeries.thickness = 1;
geoMap.series.add(symbolSeries);
}