简体   繁体   中英

How to use Azure Maps in Angular

I cannot find any support, module or documentation for using Azure Maps in Angular. Is Azure Maps still too new and have no support for Angular yet?

I have tried the following module without success: https://www.npmjs.com/package/angular-azure-maps

I have tried following Microsofts instructions in their documentations for Azure Maps (non-Angular), but without success.

I am using Angular version 5.2.9.

Azure Maps is fairly new and we haven't had a chance to look into Angular ourselves yet (I'm the program manager for map controls on Azure Maps). There is an open source project that has been started by the community here: https://github.com/Acaisoft/angular-azure-maps I believe this is the source code to the library you are trying on npm.

We do plan to investigate how we can make using Azure Maps easier to use in Angular in the new year, but will likely start by integrating it into one of the many existing Angular map libraries that exist.

I recommend make a feature request so we can track this and others can upvote it here: https://feedback.azure.com/forums/909172-azure-maps

It's easy to use Azure Maps with Angular.

Firstly, you need to install npm package: npm i azure-maps-control --save .

Then, modify your angular.json file. Include files to the styles and scripts :

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

After that in your component, create ViewChild for you map container and initialize map. Don't forget to include some Azure Maps Subscription Key from the environment variable.

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
            }
        });
    }
}

And here's your map.component.html

<div #map></div>

I think that best way is to use native azure-maps-control . And demos from Azure Maps Web Control Samples .

Tested with @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>

In addition to @rbrundritt answer, I've been trying Acaisoft Azure Maps library and, well, it is full of errors and none of the samples linked from that GitHub repository work at all... But I guess I have good news, there is a Post, by Chris Pendleton,"Principal PM Manager, Azure Maps" , talking about S1 pricing tier and there I've found that

... 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

EDIT (few hours later):

I tried the library without success and meanwhile Azure Maps teams creates proper documentation and hopefully a how-to guide to make that work in angular I'll keep using Leaflet and MapBox.

I hope it helps.

@Vlad's and @Alexey's answers are very helpful but I'd like to provide an additional example for anyone wanting to use code from the sample library , especially those samples which require services. Below is a version of the Fuzzy Search with Services Module with the minimum adjustments necessary for use in 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);
        }
    }
}

The html would then be something like:

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

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

(Note: This example is intended to be as close to the sample code as possible to make comparison simpler but could be improved using Angular and TypeScript conventions).

This is how I got Azure maps to work for sattelite view.

I imported leaflet in the app.module (simply imported, no need to add anything to imports array).

import 'leaflet';

In the component where I am generating a map, I created the satellite layer like this:

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);

I then added the layer to my leaflet options:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM