지리적 위치를 사용한 React 바인딩 CSV 파일
Ignite UI for React 사용하면 다양한 파일 유형에서 로드된 지리적 데이터를 플로팅할 수 있습니다. 예를 들어, 쉼표로 구분된 값(CSV) 파일에서 지리적 위치를 로드할 수 있습니다.
React Binding CSV Files with Geographic Locations Example
export default class WorldUtils {
public static 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);
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;
}
public static 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);
}
public static calcDestination(origin: any, bearing: number, distance: number): any {
let radius = 6371.0;
origin = this.toRadianLocation(origin);
bearing = this.toRadians(bearing);
distance = distance / radius;
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);
lon = (lon + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
lon = this.toDegrees(lon);
lat = this.toDegrees(lat);
return { lon: lon, lat: lat };
}
public static 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;
}
public static toRadianLocation(geoPoint: any): any {
let x = this.toRadians(geoPoint.lon);
let y = this.toRadians(geoPoint.lat);
return { lon: x, lat: y };
}
public static toRadians(degrees: number): number
{
return degrees * Math.PI / 180;
}
public static toDegrees(radians: number): number {
return (radians * 180.0 / Math.PI);
}
public static toDegreesNormalized(radians: number): number
{
let degrees = this.toDegrees(radians);
degrees = (degrees + 360) % 360;
return degrees;
}
public static toStringLat(latitude: number): string {
let str = Math.abs(latitude).toFixed(1) + "°";
return latitude > 0 ? str + "N" : str + "S";
}
public static 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";
}
public static toStringAbbr(value: number): string {
if (value > 1000000000000) {
return (value / 1000000000000).toFixed(1) + " T"
} else if (value > 1000000000) {
return (value / 1000000000).toFixed(1) + " B"
} else if (value > 1000000) {
return (value / 1000000).toFixed(1) + " M"
} else if (value > 1000) {
return (value / 1000).toFixed(1) + " K"
}
return value.toFixed(0);
}
public static getLongitude(location: any): number {
if (location.x) return location.x;
if (location.lon) return location.lon;
if (location.longitude) return location.longitude;
return Number.NaN;
}
public static getLatitude(location: any): number {
if (location.y) return location.y;
if (location.lat) return location.lat;
if (location.latitude) return location.latitude;
return Number.NaN;
}
public static 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);
}
}
const geoBounds = {
left: minLon,
top: minLat,
width: Math.abs(maxLon - minLon),
height: Math.abs(maxLat - minLat)
};
return geoBounds;
}
public static getNightShapes(): any[] {
let nightShape = [];
let line: any[] = [];
for (let lon = -180; lon <= 180; lon += 1) {
let x = lon;
let y = 75 * Math.cos(lon * Math.PI / 180);
line.push({x: x, y: y});
}
let coordinateLine = {points: [line]};
nightShape.push(coordinateLine);
return nightShape;
}
}
ts
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import WorldUtils from "./WorldUtils"
import { IgrGeographicMapModule } from "@infragistics/igniteui-react-maps";
import { IgrGeographicMap } from "@infragistics/igniteui-react-maps";
import { IgrGeographicHighDensityScatterSeries } from "@infragistics/igniteui-react-maps";
import { IgrDataChartInteractivityModule } from "@infragistics/igniteui-react-charts";
import { IgrDataContext } from "@infragistics/igniteui-react-core";
IgrGeographicMapModule.register();
IgrDataChartInteractivityModule.register();
export default class MapBindingDataCSV extends React.Component {
public geoMap: IgrGeographicMap;
constructor(props: any) {
super(props);
this.onMapRef = this.onMapRef.bind(this);
}
public render(): JSX.Element {
return (
<div className="container sample">
<div className="container" >
<IgrGeographicMap
ref={this.onMapRef}
width="100%"
height="100%"
zoomable="true"/>
</div>
<div className="overlay-bottom-right overlay-border">Imagery Tiles: @OpenStreetMap</div>
</div>
);
}
public onMapRef(geoMap: IgrGeographicMap) {
if (!geoMap) { return; }
this.geoMap = geoMap;
}
public componentDidMount() {
fetch("https://static.infragistics.com/xplatform/data/UsaCitiesPopulation.csv")
.then((response) => response.text())
.then(data => this.onDataLoaded(data));
}
public onDataLoaded(csvData: string) {
const csvLines = csvData.split("\n");
const geoLocations: any[] = [];
for (let i = 1; i < csvLines.length; i++) {
const columns = csvLines[i].split(",");
const location = {
latitude: Number(columns[1]),
longitude: Number(columns[2]),
name: columns[0],
population: Number(columns[3])
};
geoLocations.push(location);
}
// creating HD series with loaded data
const geoSeries = new IgrGeographicHighDensityScatterSeries( { name: "hdSeries" });
geoSeries.dataSource = geoLocations;
geoSeries.latitudeMemberPath = "latitude";
geoSeries.longitudeMemberPath = "longitude";
geoSeries.heatMaximumColor = "Red";
geoSeries.heatMinimumColor = "Black";
geoSeries.heatMinimum = 0;
geoSeries.heatMaximum = 5;
geoSeries.pointExtent = 1;
geoSeries.tooltipTemplate = this.createTooltip;
geoSeries.mouseOverEnabled = true;
// adding symbol series to the geographic amp
this.geoMap.series.add(geoSeries);
// zooming to bound of lower 48-states
const geoBounds = {
left: -130,
top: 15,
width: Math.abs(-130 + 65),
height: Math.abs(50 - 15)
};
this.geoMap.zoomToGeographic(geoBounds);
}
public createTooltip(context: any) {
const dataContext = context.dataContext as IgrDataContext;
if (!dataContext) return null;
const series = dataContext.series as any;
if (!series) return null;
const dataItem = dataContext.item as any;
if (!dataItem) return null;
const lat = WorldUtils.toStringLat(dataItem.latitude);
const lon = WorldUtils.toStringLon(dataItem.longitude);
const population = WorldUtils.toStringAbbr(dataItem.population);
return <div>
<div className="tooltipTitle">{dataItem.name}</div>
<div className="tooltipBox">
<div className="tooltipRow">
<div className="tooltipLbl">Latitude:</div>
<div className="tooltipVal">{lat}</div>
</div>
<div className="tooltipRow">
<div className="tooltipLbl">Longitude:</div>
<div className="tooltipVal">{lon}</div>
</div>
<div className="tooltipRow">
<div className="tooltipLbl">Population: </div>
<div className="tooltipVal">{population}</div>
</div>
</div>
</div>
}
}
// rendering above class to the React DOM
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<MapBindingDataCSV/>);
tsx
Like this sample? Get access to our complete Ignite UI for React toolkit and start building your own apps in minutes. Download it for free.
Data Example
다음은 CSV 파일의 데이터 예입니다.
City,Lat,Lon,State,Code,County,Density,Population
New York,40.7856,-74.0093,New Jersey,NJ,Hudson,21057,54227
Dundee,42.5236,-76.9775,New York,NY,Yates,579,1650
ts
Code Snippet
다음 코드는 지도 구성 요소의 IgrGeographicHighDensityScatterSeries
지리적 위치가 포함된 로드된 CSV 파일에서 생성된 개체 배열에 로드하고 바인딩합니다.
import { IgrGeographicHighDensityScatterSeries } from 'igniteui-react-maps';
public componentDidMount() {
fetch(url + "/Data/UsaCities.csv")
.then((response) => response.text())
.then(data => this.onDataLoaded(data));
}
public onDataLoaded(csvData: string) {
const csvLines = csvData.split("\n");
const geoLocations: any[] = [];
for (let i = 1; i < csvLines.length; i++) {
const columns = csvLines[i].split(",");
const location = {
name: columns[0],
latitude: Number(columns[1]),
longitude: Number(columns[2]),
state: columns[3],
code: columns[4],
county: columns[5],
density: Number(columns[6]),
population: Number(columns[7])
};
geoLocations.push(location);
}
const geoSeries = new IgrGeographicHighDensityScatterSeries( { name: "hdSeries" });
geoSeries.dataSource = geoLocations;
geoSeries.latitudeMemberPath = "latitude";
geoSeries.longitudeMemberPath = "longitude";
geoSeries.heatMaximumColor = "Red";
geoSeries.heatMinimumColor = "Black";
geoSeries.heatMinimum = 0;
geoSeries.heatMaximum = 5;
geoSeries.pointExtent = 1;
geoSeries.mouseOverEnabled = true;
this.geoMap.series.add(geoSeries);
}
ts
API References