In Web Components map component, you can use the IgcGeographicHighDensityScatterSeriesComponent to bind and show scatter data ranging from hundreds to millions of data points requiring exceedingly little loading time.
Web Components Geographic High Density Map Example
EXAMPLE
DATA
TS
HTML
CSS
exportclassWorldUtils{
// calculate geo-paths between two locations using great circle formulapublicstatic 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-lineif (previous.lon > 150 && current.lon < -150) {
paths[pathID].push({ x: 180, y: current.lat });
paths.push([]);
pathID++
current = { lon: -180, lat: current.lat }
} elseif (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 locationspublicstatic 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);
returnthis.toDegreesNormalized(angle);
}
// calculate destination for origin location and travel distancepublicstatic 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 radianslet 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 locationspublicstatic 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
}
publicstatic toRadianLocation(geoPoint: any): any {
let x = this.toRadians(geoPoint.lon);
let y = this.toRadians(geoPoint.lat);
return { lon: x, lat: y };
}
publicstatic toRadians(degrees: number): number
{
return degrees * Math.PI / 180;
}
publicstatic toDegrees(radians: number): number {
return (radians * 180.0 / Math.PI);
}
publicstatic toDegreesNormalized(radians: number): number
{
let degrees = this.toDegrees(radians);
degrees = (degrees + 360) % 360;
return degrees;
}
// converts latitude coordinate to a stringpublicstatic toStringLat(latitude: number): string {
let str = Math.abs(latitude).toFixed(1) + "°";
return latitude > 0 ? str + "N" : str + "S";
}
// converts longitude coordinate to a stringpublicstatic toStringLon(coordinate: number): string {
let val = Math.abs(coordinate);
let str = val < 100 ? val.toFixed(1) : val.toFixed(0);
return coordinate > 0 ? str + "°E" : str + "°W";
}
publicstatic toStringAbbr(value: number): string {
if (value > 1000000000000) {
return (value / 1000000000000).toFixed(1) + " T"
} elseif (value > 1000000000) {
return (value / 1000000000).toFixed(1) + " B"
} elseif (value > 1000000) {
return (value / 1000000).toFixed(1) + " M"
} elseif (value > 1000) {
return (value / 1000).toFixed(1) + " K"
}
return value.toFixed(0);
}
publicstatic getLongitude(location: any): number {
if (location.x) return location.x;
if (location.lon) return location.lon;
if (location.longitude) return location.longitude;
returnNumber.NaN;
}
publicstatic getLatitude(location: any): number {
if (location.y) return location.y;
if (location.lat) return location.lat;
if (location.latitude) return location.latitude;
returnNumber.NaN;
}
publicstatic getBounds(locations: any[]): any {
let minLat = 90;
let maxLat = -90;
let minLon = 180;
let maxLon = -180;
for (const location of locations) {
const crrLon = this.getLongitude(location);
if (!Number.isNaN(crrLon)) {
minLon = Math.min(minLon, crrLon);
maxLon = Math.max(maxLon, crrLon);
}
const crrLat = this.getLatitude(location);
if (!Number.isNaN(crrLat)) {
minLat = Math.min(minLat, crrLat);
maxLat = Math.max(maxLat, crrLat);
}
// if (location.x) {// minLon = Math.min(minLon, location.x);// maxLon = Math.max(maxLon, location.x);// } else if (location.lon) {// minLon = Math.min(minLon, location.lon);// maxLon = Math.max(maxLon, location.lon);// } else if (location.longitude) {// minLon = Math.min(minLon, location.longitude);// maxLon = Math.max(maxLon, location.longitude);// }// if (location.y) {// minLat = Math.min(minLat, location.y);// maxLat = Math.max(maxLat, location.y);// } else if (location.lat) {// minLat = Math.min(minLat, location.lat);// maxLat = Math.max(maxLat, location.lat);// } else if (location.latitude) {// minLat = Math.min(minLat, location.latitude);// maxLat = Math.max(maxLat, location.latitude);// }
}
const geoBounds = {
left: minLon,
top: minLat,
width: Math.abs(maxLon - minLon),
height: Math.abs(maxLat - minLat)
};
return geoBounds;
}
publicstatic getNightShapes(): any[] {
let nightShape = [];
let line: any[] = [];
for (let lon = -180; lon <= 180; lon += 1) {
// let line: any[] = [{x: lon, y: -90}, {x: lon, y: 90}];let x = lon;
let y = 75 * Math.cos(lon * Math.PI / 180);
line.push({x: x, y: y});
}
// line.push({x: 180, y: 90});// line.push({x: -180, y: 90});// line.push({x: -180, y: -90});let coordinateLine = {points: [line]};
nightShape.push(coordinateLine);
return nightShape;
}
}
ts
<!DOCTYPE html><html><head><title>MapTypeScatterDensitySeries</title><metacharset="UTF-8" /><linkrel="shortcut icon"href="https://static.infragistics.com/xplatform/images/browsers/wc.png" ><linkrel="stylesheet"href="https://fonts.googleapis.com/icon?family=Material+Icons" /><linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Kanit&display=swap" /><linkrel="stylesheet"href="https://fonts.googleapis.com/css?family=Titillium Web" /><linkrel="stylesheet"href="https://static.infragistics.com/xplatform/css/samples/shared.v8.css"type="text/css" /></head><body><divid="root"><divclass="container sample"><igc-geographic-mapid="geoMap"width="100%"height="100%"></igc-geographic-map></div></div><!-- This script is needed only for parcel and it will be excluded for webpack -->
<% if (false) { %><scriptsrc="src/index.ts"></script><% } %>
</body></html>html
/* shared styles are loaded from: *//* https://static.infragistics.com/xplatform/css/samples */css
Like this sample? Get access to our complete Ignite UI for Web Components toolkit and start building your own apps in minutes. Download it for free.
The demo above shows the IgcGeographicHighDensityScatterSeriesComponent series in the map component bound to hundreds or even thousands of data points representing Australia’s population density. The map plot area with more densely populated data points represented as coalescences of red pixels and loosely distributed data points by discrete blue pixels.
Because there are so many data points, the series displays the scatter data as tiny dots as opposed to full size markers, and displays areas with the most data using a higher color density representing a cluster of data points.
Data Requirements
Similar to other types of scatter series in the map control, the IgcGeographicHighDensityScatterSeriesComponent series has the ItemsSource property which can be bound to an array of objects. In addition, each data item in the items source must have two data columns that store geographic longitude and latitude coordinates and uses the longitudeMemberPath and latitudeMemberPath properties to map these data columns.
Data Binding
The following table summarizes the GeographicHighDensityScatterSeries series properties used for data binding.
Uses the ItemsSource property to determine the location of the latitude values on the assigned items
Heat Color Scale
The Heat Color Scale, an optional feature, determines the color pattern within the series. The following table summarizes the properties used for determining the color scale.