如何在 Angular 中使用 Azure Maps

How to use Azure Maps in Angular

我在 Angular 中找不到使用 Azure Maps 的任何支持、模块或文档。 Azure Maps 还是太新了,还不支持 Angular 吗?

我尝试了以下模块但没有成功:https://www.npmjs.com/package/angular-azure-maps

我尝试按照 Microsoft 在其 Azure Maps 文档中的说明进行操作(非Angular),但没有成功。

我正在使用 Angular 版本 5.2.9。

Azure Maps 相当新,我们还没有机会亲自研究 Angular(我是 Azure Maps 地图控件的程序经理)。这里的社区已经启动了一个开源项目:https://github.com/Acaisoft/angular-azure-maps 我相信这是您在 npm 上试用的库的源代码。

我们确实计划在新的一年 Angular 研究如何使 Azure Maps 更易于使用,但可能会首先将其集成到许多现有的 Angular 地图中存在的库。

我建议提出一个功能请求,这样我们就可以跟踪它,其他人可以在这里投票:https://feedback.azure.com/forums/909172-azure-maps

除了@rbrundritt 的回答,我一直在尝试 Acaisoft Azure Maps 库,嗯,它充满了错误,none 从 GitHub 存储库链接的示例工作在所有...但我想我有个好消息,有 a Post, by Chris Pendleton,"Principal PM Manager, Azure Maps",谈论 S1 定价层,我发现

... we have also combined the TypeScript definitions with a copy of the Azure Maps Web SDK source code and made it available as a NPM package, thus making it easier to integrate with modern web frameworks and providing you the option to host the Azure Maps Web SDK locally with your app for faster loading. You can find Azure-Maps-Control or install it from the command line using the following:

npm i azure-maps-control

编辑(几小时后):

我尝试了这个库但没有成功,同时 Azure Maps 团队创建了适当的文档,并希望有一个操作指南来使它在 angular 中发挥作用我将继续使用 Leaflet 和 MapBox。

希望对您有所帮助。

我认为最好的方法是使用原生 azure-maps-control. And demos from Azure Maps Web Control Samples

使用@angular测试:“^7.2.4”。

  1. npm install azure-maps-control

This package includes a minified version of the source code as well as the TypeScript definitions for the Azure Maps Web Control.

  1. maps.component.ts

    import { Component, OnInit } from '@angular/core';
    import * as atlas from 'azure-maps-control';
    
    @Component({
      selector: 'app-maps',
      templateUrl: './maps.component.html',
      styleUrls: ['./maps.component.scss']
    })
    
    export class MapsComponent implements OnInit {
    
      // Azure Active Directory Authentication Client ID
      // or Shared Key Authentication KEY
      // get it from portal.azure.com
      key: string = '{key}';
      map: any;
    
      constructor(
      ) {
      }
    
      ngOnInit() {
        //Initialize a map instance.
        this.map = new atlas.Map('mapContainer', {
          authOptions: {
            authType: 'subscriptionKey',
            subscriptionKey: this.key
          }
        });
    
        //Wait until the map resources are ready.
        this.map.events.add('ready', () => {
          //Create a HTML marker and add it to the map.
          this.map.markers.add(new atlas.HtmlMarker({
            color: 'DodgerBlue',
            text: '10',
            position: [0, 0]
          }));
        });
      }
    
    }
    
  2. maps.component.html

    <div id="mapContainer"></div>
    

通过 Angular 使用 Azure Maps 很容易。

首先,你需要安装npm包:npm i azure-maps-control --save.

然后,修改您的 angular.json 文件。将文件包含到 stylesscripts:

"styles": [
    "node_modules/azure-maps-control/dist/atlas.min.css",
    "src/styles.scss"
],
"scripts": [
    "node_modules/azure-maps-control/dist/atlas.min.js"
]

之后,在您的组件中,为您的地图容器创建 ViewChild 并初始化地图。不要忘记从环境变量中包含一些 Azure Maps 订阅密钥。

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Map, AuthenticationType } from 'azure-maps-control';
import { environment } from '@environments/environment';

@Component({
    selector: 'app-map-component',
    templateUrl: './map.component.html',
    styleUrls: [ './map.component.scss' ]
})
export class MapComponent implemens AfterViewInit {

    @ViewChild('map', { static: true })
    public mapContainer: ElementRef;

    public ngAfterViewInit(): void {
        const map = new Map(this.mapContainer.nativeElement, {
            center: [50.016, 36.13],
            zoom: 8,
            authOptions: {
                authType: AuthenticationType.subscriptionKey,
                subscriptionKey: environment.azureMapsSubscriptionKey
            }
        });
    }
}

这是你的 map.component.html

<div #map></div>

@Vlad 和@Alexey 的回答非常有帮助,但我想为任何想要使用 sample library, especially those samples which require services. Below is a version of the Fuzzy Search with Services Module 代码的人提供一个额外的示例,并在 Angular 中使用所需的最小调整.

import { Component, ViewChild, ElementRef, AfterViewInit } from "@angular/core";
import * as atlas from 'azure-maps-control';
import * as atlasRest from 'azure-maps-rest'; // install npm azure-maps-rest

@Component({
    selector: 'map',
    templateUrl: './map.component.html',
    styles: ['#map {height: 300px; width: 1110px;}']
    //Remember to set the dimensions of the map container or layers may appear
    //offset or behind the map.
})

export class MapComponent implements AfterViewInit {
    @ViewChild('input') public input: ElementRef;
    @ViewChild('mapContainer') public mapContainer: ElementRef;
    private key: string = '<Your Azure Maps Key>';
    public map: any;
    public dataSource: any;
    public popup: any;
    public searchURL: any;

    ngAfterViewInit(): void {
        this.map = new atlas.Map(this.mapContainer.nativeElement, {
            view: 'Auto',
            authOptions: {
                authType: atlas.AuthenticationType.subscriptionKey,
                subscriptionKey: this.key
            }
        });

        //Create a pipeline using the Azure Maps subscription key.
        var pipeline = atlasRest.MapsURL.newPipeline(new atlasRest.SubscriptionKeyCredential(atlas.getSubscriptionKey()));

        //Create an instance of the SearchURL client.
        this.searchURL = new atlasRest.SearchURL(pipeline);

        //Wait until the map resources are ready.
        this.map.events.add('ready', () => {

            // Add zoom control
            this.map.controls.add(new atlas.control.ZoomControl(), {
                position: 'bottom-left'
            });

            //Create a data source and add it to the map.
            this.dataSource = new atlas.source.DataSource();
            this.map.sources.add(this.dataSource);

            //Add a layer for rendering the results as symbols.
            var resultsLayer = new atlas.layer.SymbolLayer(this.dataSource);
            this.map.layers.add(resultsLayer);

            //Create a popup but leave it closed so we can update it and display it later.
            this.popup = new atlas.Popup({
                position: [0, 0],
                pixelOffset: [0, -18]
            });

            //Add a click event to the results symbol layer.
            //Remember to bind the event to 'this' or the this.popup and this.map
            //lines of the symbolClicked function will return undefined!
            this.map.events.add('click', resultsLayer, this.symbolClicked.bind(this));
        });
    }

    public closePopup(): void {
        this.popup.close();
    }

    public search(): void {
        var query = this.input.nativeElement.value;

        //Remove any previous results from the map.
        this.dataSource.clear();

        this.searchURL.searchFuzzy(atlasRest.Aborter.timeout(10000), query, {
            radius: 100000,
            view: 'Auto'
        }).then(results => {
            //Get the results in GeoJSON format and add it to the data source.
            var data = results.geojson.getFeatures();
            this.dataSource.add(data);

            //Set the camera to the bounds of the results.
            this.map.setCamera({
                bounds: data.bbox,
                padding: 40
            });
        });
    }

    public symbolClicked(e): void {
        //Make sure the event occurred on a point feature.
        if (e.shapes && e.shapes.length > 0 && e.shapes[0].getType() === 'Point') {
            var properties = e.shapes[0].getProperties();

            //Using the properties, create HTML to fill the popup with useful information.
            var html = ['<div style="padding:10px;"><span style="font-size:14px;font-weight:bold;">'];
            var addressInTitle = false;

            if (properties.type === 'POI' && properties.poi && properties.poi.name) {
                html.push(properties.poi.name);
            } else if (properties.address && properties.address.freeformAddress) {
                html.push(properties.address.freeformAddress);
                addressInTitle = true;
            }

            html.push('</span><br/>');

            if (!addressInTitle && properties.address && properties.address.freeformAddress) {
                html.push(properties.address.freeformAddress, '<br/>');
            }

            html.push('<b>Type: </b>', properties.type, '<br/>');

            if (properties.entityType) {
                html.push('<b>Entity Type: </b>', properties.entityType, '<br/>');
            }

            if (properties.type === 'POI' && properties.poi) {
                if (properties.poi.phone) {
                    html.push('<b>Phone: </b>', properties.poi.phone, '<br/>');
                }

                if (properties.poi.url) {
                    html.push('<b>URL: </b>', properties.poi.url, '<br/>');
                }

                if (properties.poi.classifications) {
                    html.push('<b>Classifications:</b><br/>');
                    for (var i = 0; i < properties.poi.classifications.length; i++) {
                        for (var j = 0; j < properties.poi.classifications[i].names.length; j++) {
                            html.push(' - ', properties.poi.classifications[i].names[j].name, '<br/>');
                        }
                    }
                }

            }

            html.push('</div>');
            
            //Set the popup options.
            this.popup.setOptions({
                //Update the content of the popup.
                content: html.join(''),

                //Update the position of the popup with the pins coordinate.
                position: e.shapes[0].getCoordinates()
            });

            //Open the popup.
            this.popup.open(this.map);
        }
    }
}

html 将类似于:

<input type="search" #input>
<button (click)="search()">Search</button>

<div #mapContainer id="map"></div>

(注意:此示例旨在尽可能接近示例代码以使比较更简单,但可以使用 Angular 和 TypeScript 约定进行改进)。

这就是我如何让 Azure 地图适用于卫星视图。

我在 app.module 中导入了传单(简单导入,无需向导入数组添加任何内容)。

import 'leaflet';

在生成地图的组件中,我创建了这样的卫星层:

const azureMapsUrl = `https://atlas.microsoft.com/map/imagery/png?api-version=1&style=satellite&zoom={z}&x={x}&y={y}&subscription-key=${myAzureMapsKey}`;
this.satelliteLayer = new L.TileLayer(azureMapsUrl);

然后我将图层添加到我的传单选项中:

this.leafletOptions = {
        zoomControl: false,
        minZoom: 6,
        layers: [this.satelliteLayer],
        zoom: 6,
        center: ...
};