Angular コンテンツのナビゲーション
IgxGeographicMapComponent
コントロールのナビゲーションは、既定では有効にされており、マップ コンテンツのズームとパンが可能です。ただし、この動作は zoomable
プロパティを使用して変更できます。マップでは同期ズームのみが許可されていること、つまり、アスペクト比を維持したままマップコンテンツをスケーリングすることを知っておくことが重要です。結果として、マップコンテンツを水平方向にスケーリングせずに垂直方向にスケーリングすることはできません。
Angular コンテンツのナビゲーションの例
import { IgxGeographicMapComponent } from "igniteui-angular-maps";
export enum MapRegion {
Caribbean = "Caribbean",
UnitedStates = "United States",
UnitedKingdom = "United Kingdom",
European = "European",
SouthAfrica = "South Africa",
Poland = "Poland",
Australia = "Australia",
Japan = "Japan",
Uruguay = "Uruguay",
Egypt = "Egypt",
Hawaii = "Hawaii"
}
export class MapUtility {
public static navigateTo(geoMap: IgxGeographicMapComponent, name: MapRegion) {
const geoRect = this.getRegions()[name];
geoMap.zoomToGeographic(geoRect);
}
public static toPixel(num: number): string {
const s = Math.abs(num).toFixed(0);
return s + " px";
}
public static toLng(num: number): string {
num = this.clamp(num, -180, 180);
let s = Math.abs(num).toFixed(1);
if (num < 100) {
s = " " + s;
}
if (num > 0) {
return s + "°E";
} else {
return s + "°W";
}
}
public static toLat(num: number): string {
num = this.clamp(num, -90, 90);
let s = Math.abs(num).toFixed(1);
if (num < 100) {
s = " " + s;
}
if (num > 0) {
return s + "°N";
} else {
return s + "°S";
}
}
public static clamp(num: number, min: number, max: number): number {
return Math.max(min, Math.min(max, num));
}
public static pad(num: number, places?: number): string {
places = places || 20;
let s = num.toFixed(1).toString();
while (s.length < places) { s = " " + s; }
return s;
}
public static getBingKey(): string {
return "Avlo7qsH1zZZI0XNpTwZ4XwvUJmCbd-mczMeUXVAW9kYYOKdmBIVRe8aoO02Xctq";
}
public static getRegions(): any {
// create regions only once
if (this.regions === undefined) {
this.createRegions();
}
return this.regions;
}
private static regions: any;
private static addRegion(name: string, geoRect: any) {
geoRect.name = name;
geoRect.longitude = geoRect.left + (geoRect.width / 2);
geoRect.latitude = geoRect.top + (geoRect.height / 2);
this.regions[name] = geoRect;
}
private static createRegions() {
this.regions = {};
this.addRegion(MapRegion.Australia, { left: 81.5, top: -52.0, width: 98.0, height: 56.0 });
this.addRegion(MapRegion.Caribbean, { left: -92.9, top: 5.4, width: 35.1, height: 25.8 });
this.addRegion(MapRegion.Egypt, { left: 19.3, top: 19.9, width: 19.3, height: 13.4 });
this.addRegion(MapRegion.European, { left: -36.0, top: 31.0, width: 98.0, height: 38.0 });
this.addRegion(MapRegion.Japan, { left: 122.7, top: 29.4, width: 27.5, height: 17.0 });
this.addRegion(MapRegion.Hawaii, { left: -161.2, top: 18.5, width: 6.6, height: 4.8 });
this.addRegion(MapRegion.Poland, { left: 13.0, top: 48.0, width: 11.0, height: 9.0 });
this.addRegion(MapRegion.SouthAfrica, { left: 9.0, top: -37.1, width: 26.0, height: 17.8 });
this.addRegion(MapRegion.UnitedStates, { left: -134.5, top: 16.0, width: 70.0, height: 37.0 });
this.addRegion(MapRegion.UnitedKingdom, { left: -15.0, top: 49.5, width: 22.5, height: 8.0 });
this.addRegion(MapRegion.Uruguay, { left: -62.1, top: -35.7, width: 10.6, height: 7.0 });
}
}
tsexport class WorldUtility {
// calculate geo-paths between two locations using great circle formula
public static calcPaths(origin: any, dest: any): any[] {
const interval = 200;
const paths: any[] = [[]];
let pathID = 0;
const 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 });
const 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 static calcBearing(origin: any, dest: any): number {
origin = this.toRadianLocation(origin);
dest = this.toRadianLocation(dest);
const range = (dest.lon - origin.lon);
const y = Math.sin(range) * Math.cos(dest.lat);
const x = Math.cos(origin.lat) * Math.sin(dest.lat) -
Math.sin(origin.lat) * Math.cos(dest.lat) * Math.cos(range);
const angle = Math.atan2(y, x);
return this.toDegreesNormalized(angle);
}
// calculate destination for origin location and travel distance
public static calcDestination(origin: any, bearing: number, distance: number): any {
const 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));
const x = Math.sin(bearing) * Math.sin(distance) * Math.cos(origin.lat);
const 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, lat };
}
// calculate distance between two locations
public static calcDistance(origin: any, dest: any): number {
origin = this.toRadianLocation(origin);
dest = this.toRadianLocation(dest);
const sinProd = Math.sin(origin.lat) * Math.sin(dest.lat);
const cosProd = Math.cos(origin.lat) * Math.cos(dest.lat);
const lonDelta = (dest.lon - origin.lon);
const angle = Math.acos(sinProd + cosProd * Math.cos(lonDelta));
const distance = angle * 6371.0;
return distance; // * 6371.0; // in km
}
public static toRadianLocation(geoPoint: any): any {
const x = this.toRadians(geoPoint.lon);
const 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;
}
// converts latitude coordinate to a string
public static toStringLat(latitude: number): string {
const str = Math.abs(latitude).toFixed(1) + "°";
return latitude > 0 ? str + "N" : str + "S";
}
// converts longitude coordinate to a string
public static toStringLon(coordinate: number): string {
const val = Math.abs(coordinate);
const 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),
// tslint:disable-next-line: object-literal-sort-keys
height: Math.abs(maxLat - minLat)
};
return geoBounds;
}
}
tsimport { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { AppComponent } from "./app.component";
import { IgxGeographicMapModule } from "igniteui-angular-maps";
import { IgxDataChartInteractivityModule } from "igniteui-angular-charts";
@NgModule({
bootstrap: [AppComponent],
declarations: [
AppComponent,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
CommonModule,
FormsModule,
IgxGeographicMapModule,
IgxDataChartInteractivityModule
],
providers: [],
schemas: []
})
export class AppModule {}
tsimport { AfterViewInit, Component, TemplateRef, ViewChild, ChangeDetectorRef } from "@angular/core";
import { IgxArcGISOnlineMapImagery } from "igniteui-angular-maps";
import { IgxGeographicMapComponent } from "igniteui-angular-maps";
import { MapUtility, MapRegion } from "./MapUtility";
import { IgxRectChangedEventArgs } from "igniteui-angular-core";
@Component({
standalone: false,
selector: "app-root",
styleUrls: ["./app.component.scss"],
templateUrl: "./app.component.html"
})
export class AppComponent implements AfterViewInit {
public isRunning: boolean;
public regionType: string = "United States";
@ViewChild("map", { static: true })
public geoMap: IgxGeographicMapComponent;
@ViewChild("template", { static: true })
public tooltip: TemplateRef<object>;
public geoRect: any;
public geoT: string;
public geoL: string;
public geoH: string;
public geoW: string;
public winT: string;
public winL: string;
public winH: string;
public winW: string;
public posHorizontal: number;
public posVertical: number;
public scale: number;
public mapHoverLongitude: string = "0.0°W";
public mapHoverLatitude: string = "0.0°S";
public mapHoverX: string = "0.0000";
public mapHoverY: string = "0.0000";
public mapHoverPixelX = "0 px";
public mapHoverPixelY = "0 px";
public navigationOptions: Element[] = [];
public navigationRegions: any = {};
constructor(private ref: ChangeDetectorRef) {
const regions = MapUtility.getRegions();
for (const key in regions) {
if (regions.hasOwnProperty(key)) {
const region = regions[key];
const name = region.name;
this.navigationRegions[name] = region;
}
}
}
public ngAfterViewInit(): void {
this.componentDidMount();
if (this.geoMap !== undefined) {
// console.log("ngAfterViewInit map");
this.geoMap.actualWindowRectChanged.subscribe((e: IgxRectChangedEventArgs) =>
this.onMapWindowRectChanged(this.geoMap, e)
);
this.geoMap.zoomToGeographic({ left: -134.5, top: 16.5, width: 70.0, height: 37.0 });
}
}
public onMapWindowRectChanged(geoMap: IgxGeographicMapComponent, e: any) {
// converting window rect to geographic rect/region:
const geoRect: any = geoMap.getGeographicFromZoom(e.args.newRect);
geoRect.bottom = geoRect.top + geoRect.height;
geoRect.right = geoRect.left + geoRect.width;
// calculating center of geographic region
geoRect.longitude = geoRect.left + (geoRect.width / 2);
geoRect.latitude = geoRect.top + (geoRect.height / 2);
this.geoRect = geoRect;
const h = geoMap.actualWindowPositionHorizontal
const v = geoMap.actualWindowPositionVertical;
const s = geoMap.actualWindowScale;
this.geoT = "T: " + MapUtility.toLat(this.geoRect.top);
this.geoL = "L: " + MapUtility.toLng(this.geoRect.left);
this.geoH = "H: " + MapUtility.toLng(this.geoRect.height);
this.geoW = "W: " + MapUtility.toLng(this.geoRect.width);
this.winT = "T: " + e.args.newRect.top.toFixed(4);
this.winL = "L: " + e.args.newRect.left.toFixed(4);
this.winH = "H: " + e.args.newRect.height.toFixed(4);
this.winW = "W: " + e.args.newRect.width.toFixed(4);
this.posHorizontal = parseFloat(h.toFixed(4));
this.posVertical = parseFloat(v.toFixed(4));
this.scale = parseFloat(s.toFixed(4));
this.ref.detectChanges();
}
public onMapMouseMove = (e: any) => {
const bounds = e.target.getBoundingClientRect();
const relativeCoordinate = {
x: e.clientX - bounds.left,
y: e.clientY - bounds.top
};
const windowCoordinate = {
x: (e.clientX - bounds.left) / bounds.width,
y: (e.clientY - bounds.top) / bounds.height
};
// converting mouse pixel coordinate to geographic coordinate:
const geoCoordinate: any = this.geoMap.getGeographicPoint(relativeCoordinate);
this.mapHoverLongitude = MapUtility.toLng(geoCoordinate.x);
this.mapHoverLatitude = MapUtility.toLat(geoCoordinate.y);
this.mapHoverX = windowCoordinate.x.toFixed(4);
this.mapHoverY = windowCoordinate.y.toFixed(4);
this.mapHoverPixelX = MapUtility.toPixel(relativeCoordinate.x);
this.mapHoverPixelY = MapUtility.toPixel(relativeCoordinate.y);
this.ref.detectChanges();
}
public componentDidMount() {
const elem = document.getElementById('map');
elem.addEventListener('mousemove', this.onMapMouseMove, false);
}
public onSelectionChanged = (e: any) => {
if (this.geoMap === undefined) return;
const name = e.target.value.toString();
const region = this.navigationRegions[name];
this.geoMap.zoomToGeographic(region);
}
}
ts<div class="container vertical">
<div class="container" id="map" >
<igx-geographic-map #map
width="100%"
height="100%"
zoomable="true">
</igx-geographic-map>
</div>
<div class="overlay-left" >
<div class="vertical overlay-border" style="background: rgba(217, 217, 217, 0.5)" >
<label style="font-weight: 600" >Select Map Region</label>
<select [(ngModel)]="regionType" (change)="onSelectionChanged($event)">
<option>Australia</option>
<option>Caribbean</option>
<option>Egypt</option>
<option>European</option>
<option>Japan</option>
<option>Hawaii</option>
<option>Poland</option>
<option>South Africa</option>
<option>United States</option>
<option>United Kingdom</option>
<option>Uruguay</option>
</select>
<label style="font-weight: 600">Map Geographic Rect</label>
<div class="horizontal" >
<div class="vertical" style="margin-right: 1rem">
<label >{{geoT}}</label>
<label >{{geoL}}</label>
</div>
<div class="vertical">
<label >{{geoH}}</label>
<label >{{geoW}}</label>
</div>
</div>
<label style="font-weight: 600">Map Window Rect</label>
<div class="horizontal">
<div class="vertical" style="margin-right: 1rem">
<label >{{winT}}</label>
<label >{{winL}}</label>
</div>
<div class="vertical">
<label >{{winH}}</label>
<label >{{winW}}</label>
</div>
</div>
<label style="font-weight: 600">Map Window Position</label>
<div class="horizontal">
<div class="vertical" style="margin-right: 1rem">
<label >Horizontal:</label>
<label >Vertical:</label>
<label >Scale:</label>
</div>
<div class="vertical">
<label >{{posHorizontal}}</label>
<label >{{posVertical}}</label>
<label >{{scale}}</label>
</div>
</div>
<label style="font-weight: 600">Map Hover Coordinates</label>
<div class="horizontal">
<div class="vertical" style="margin-right: 1rem">
<label >Longitude: </label>
<label >Latitude: </label>
<label >Window X: </label>
<label >Window Y: </label>
<label >Pixel X: </label>
<label >Pixel Y: </label>
</div>
<div class="vertical">
<label >{{mapHoverLatitude}}</label>
<label >{{mapHoverLongitude}}</label>
<label >{{mapHoverX}}</label>
<label >{{mapHoverY}}</label>
<label >{{mapHoverPixelX}}</label>
<label >{{mapHoverPixelY}}</label>
</div>
</div>
</div>
</div>
<div class="overlay-bottom-right">Imagery Tiles: in ESRI/ArcGIS</div>
</div>
html/* styles are loaded the Shared CSS file located at:
https://static.infragistics.com/xplatform/css/samples/
*/
scss
このサンプルが気に入りましたか? 完全な Ignite UI for Angularツールキットにアクセスして、すばやく独自のアプリの作成を開始します。無料でダウンロードできます。
地理座標
これらの座標で囲まれた地理的領域内の地図コンテンツをナビゲートします。
- 水平方向に 180°E (マイナス) から 180°W (プラス) の経度
- 垂直方向に 85°S (マイナス) から 85°N (プラス) の緯度
このコード スニペットは、地理座標を使用してマップをナビゲートする方法を示しています。
ウィンドウ座標
また、これらの相対座標で区切られたウィンドウ長方形内でマップ コンテンツをナビゲーションできます。
- 水平方向に 0.0 から 1.0 の値
- 垂直方向に 0.0 から 1.0 の値
このコード スニペットは、相対ウィンドウ座標を使用してマップをナビゲートする方法を示しています。
プロパティ
以下の表は IgxGeographicMapComponent
コントロールのナビゲーションで使用できるプロパティをまとめたものです。
プロパティ名 | プロパティ型 | 概要 |
---|---|---|
windowRect |
Rect | 地図コンテンツの表示領域にナビゲーション ウィンドウの新しい位置とサイズを設定します。0、0、1、1 の値で長方形を指定すると、ナビゲーション ウィンドウのマップ コンテンツ全体がズームアウトされます。 |
windowScale |
number | マップ コントロールのナビゲーション ウィンドウの新しいサイズを設定します。windowRect プロパティに格納されている Width または Height の最小値です。 |
windowPositionHorizontal |
number | マップ コントロールの左端からのナビゲーション ウィンドウのアンカー ポイントの新しい水平位置を設定します。これは windowRect プロパティの Left に保存された値と等しくなります。 |
windowPositionVertical |
number | ナビゲーション ウィンドウのアンカー ポイントの、地図コントロールの上端からの新しい垂直位置を設定します。これは windowRect プロパティの Top に保存された値と等しくなります。 |
actualWindowRect |
Rect | マップ コンテンツの表示領域内のナビゲーション ウィンドウの現在の位置とサイズを示します。0、0、1、1の値で長方形を指定すると、ナビゲーション ウィンドウにマップ コンテンツ全体が表示されます。 |
actualWindowScale |
number | マップ コントロールのナビゲーション ウィンドウの現在のサイズを示します。actualWindowRect プロパティに格納されている Width または Height の最小値と同じです。 |
actualWindowPositionHorizontal |
number | マップ コントロールの左端からのナビゲーション ウィンドウのアンカー ポイントの現在の水平位置を示します。actualWindowRect プロパティの Left に保存された値と等しくなります。 |
actualWindowPositionVertical |
number | マップコントロールの上端からのナビゲーションウィンドウのアンカーポイントの垂直位置を示します。actualWindowRect プロパティの Top に保存された値と等しくなります。 |