How to use Google Maps in Angular?

Google maps meet Angular. Having such a strong developer community and being used by thousands of developers around the world made Angular ideal for bringing most tools to the framework. bringing Google maps to Angular is one of them, it solved many problems for the Angular users. Manually adding Google maps to Angular is very difficult, so some people took it up upon themselves to make adding GMaps to your apps as easy as importing a module.

In this post, we will be looking at integrating Google Maps in your Angular application

The AGM library

This is the main library we will be using. The main library in the AGM is the @agm/core library. @agm/core contains solutions for the Google Maps JavaScript Core API.

To use this, we will first scaffold an Angular project:

ng new ng-maps

The above command will create a new Angular project.

Now, we install the @agm/core library:

npm i @agm/core

We need a component where we can display the map, to do that we scaffold a component:

g c map

This command will create map.component.ts in src/app/map/ folder.

We need to import the AgmModule in our AppModule:

...
import { AgmCoreModule } from '@agm/core';

@NgModule({
    declarations: [
        AppComponent,
        MapComponent
    ],
    imports: [
        BrowserModule,
        AgmCoreModule.forRoot({
            apiKey: environment.keys.gmap,
            libraries: ["places", "geometry"]
            /* apiKey is required, unless you are a premium customer, in which case you can use clientId */
        })
    ],
    providers: [
        ...
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

See, the AgmModule is imported and placed in the imports section. We need a GMaps key, to get it go to console.developers.google.com and follow the instructions.

After successfully obtaining the key, you can paste it here

...
        AgmCoreModule.forRoot({
            apiKey: "",
            libraries: ["places", "geometry"]
            /* apiKey is required, unless you are a premium customer, in which case you can use clientId */
        })
...

I added mine to the environment.ts file. For simplicity just add it to the apiKey property above.

We are done now. To display the map, we open up our map.component.ts and paste this:

<!-- map.component.html -->
<agm-map></agm-map>
// map.component.ts
@Component({
    ...
})
export class MapComponent {}

This will render the Google Map on our MapComponent.

Run ng serve, we will see it on our browser.

The agm-map selector tag is used to render the Google Maps on our components. It has inputs and outputs which we will see in the below sections.

Display a Selected Latitude and Longitude 🌍

The above code does nothing just displays a Map. Let’s make it display a selected location from a provided latitude and longitude position.

Remember, latitude and longitude is what is used to locate a position on a map, It is triangulated in the x-y plane. The latitude is in the x-plane while longitude is in the y-plane.

So when given a latitude and longitude, we trace from the x-axis and the y-axis, till they meet. The intersection is the location/position of the object or place.

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude"></agm-map>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785
        }
    }
}

interface Location {
    latitude: number;
    longitude: number
}

Map Type 🌍

Google Maps have options on how we want the map view displayed.

street view : This will show the streets on an eye-level, we can navigate/walk the streets with the arrow buttons

satellite: Displays the amp as seen by a satellite.

normal: The default map showed us by Google.

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType"></agm-map>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite"
        }
    }
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
}

Zooming 🔎

agm-map has an option to zoom in or out in the map view. We use the [zoom] input to accomplish that.

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom"></agm-map>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite",
            zoom: 5
        }
    }
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
}

We set the zoom depth to 5.

This has zoom levels:

  • 1: World
  • 5: Landmass/continent
  • 10: City
  • 15: Streets
  • 20: Buildings

Specifying a zoom level of 0-4 will show the map of the entire Earth. 5-9 will show the map in the continent at a higher resolution more than 0-5. Zoom level from 11 - 14 will show the cities in the map location at a higher resolution than the previous zoom level. 15-19 will show the streets and 20-~ will show the buildings at an eye level.

So our above example will show the location on the map on the landmass/continent level.

Placing a marker 📌

To place an indicator/marker📍 on the map to show the precise location, we will use the agm-marker. Markers are like pins on the map.

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker [latitude]="location.marker.lat" [longitude]="location.marker.lng"></agm-marker>
</agm-map>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite",
            zoom: 5,
            marker: {
                lat: -28.68352,
                lng: -147.20785
            }
        }
    }
}

interface Marker {
    lat: number;
    lng: number;
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
    marker: Marker;
}

A marker/pin will appear at the precise location of (-28.68352,-147.20785).

Adding a marker 📌

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker *ngFor="let marker of location.markers" [latitude]="marker.lat" [longitude]="marker.lng"></agm-marker>
</agm-map>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite",
            zoom: 5,
            markers: [
                {
                    lat: -28.68352,
                    lng: -147.20785
                }
            ]
        }
    }

    addMarker(lat: number, lng: number) {
        this.location.markers.push({
            lat,
            lng
        })
    }
}

interface Marker {
    lat: number;
    lng: number;
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
    markers: Array<Marker>;
}

In this example, when a user clicks the map, it adds a new marker to the map. We hold the markers in an array, the agm-marker iterates over the array and places them on the map with a pin/marker. When we click on the map, a new marker is pushed to the markers array. A pin/marker appears over the position clicked.

Selecting a marker

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker *ngFor="let marker of location.markers" [latitude]="marker.lat" [longitude]="marker.lng" (markerClick)="selectMarker($event)"></agm-marker>
</agm-map>
<div>
    Selected Marker is: Longitude {{selectedMarker.lat}} Latitude {{selectedMarker.lng}}
</div>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location
    selectedMarker: Marker

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite",
            zoom: 5,
            markers: [
                {
                    lat: -28.68352,
                    lng: -147.20785
                }
            ]
        }
    }

    addMarker(lat: number, lng: number) {
        this.location.markers.push({
            lat,
            lng
        })
    }

    selectMarker(event) {
        this.selectedMarker = {
            lat: event.latitude,
            lng: event.longitude
        }
    }
}

interface Marker {
    lat: number;
    lng: number;
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
    markers: Array<Marker>;
}

Dragging marker

We can click, hold and drag a marker around.

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker 
    *ngFor="let marker of location.markers" [latitude]="marker.lat" 
    [longitude]="marker.lng" 
    (markerClick)="selectMarker($event)"     [markerDraggable]="true"
    (dragEnd)="markerDragEnd(coords, $event)"
></agm-marker>
</agm-map>
<div>
    Selected Marker is: Longitude {{selectedMarker.lat}} Latitude {{selectedMarker.lng}}
</div>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location
    selectedMarker: Marker

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite",
            zoom: 5,
            markers: [
                {
                    lat: -28.68352,
                    lng: -147.20785
                }
            ]
        }
    }

    addMarker(lat: number, lng: number) {
        this.location.markers.push({
            lat,
            lng
        })
    }

    selectMarker(event) {
        this.selectedMarker = {
            lat: event.latitude,
            lng: event.longitude
        }
    }

    markerDragEnd(coords: any, $event: MouseEvent) {
        this.location.latitude = coords.latitude
        this.location.longitude = coodrs.longitude
    }
}

interface Marker {
    lat: number;
    lng: number;
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
    markers: Array<Marker>;
}

We use the [markerDraggable]="true" to make the marker draggable. Then, we have the event (dragEnd)="markerDragEnd(coords, $event)", this event is fired when the user stops dragging the marker.

Labelling a marker

We can label a marker, i.e attach a name or description to a marker. It will be a name hovering above the marker, to identify the marker.

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker 
    *ngFor="let marker of location.markers" [latitude]="marker.lat" 
    [longitude]="marker.lng" 
    (markerClick)="selectMarker($event)"     [markerDraggable]="true"
    (dragEnd)="markerDragEnd(coords, $event)"
    [label]="marker.label"
></agm-marker>
</agm-map>
<div>
    Selected Marker is: Longitude {{selectedMarker.lat}} Latitude {{selectedMarker.lng}}
</div>
// map.component.ts
@Component({
    ...
})
export class MapComponent implements OnInit{
    location: Location
    selectedMarker: Marker

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite",
            zoom: 5,
            markers: [
                {
                    lat: -28.68352,
                    lng: -147.20785,
                    label: "new york"
                }
            ]
        }
    }

    addMarker(lat: number, lng: number) {
        this.location.markers.push({
            lat,
            lng,
            label: Date.now().toLocaleString()
        })
    }
    ...
}

interface Marker {
    lat: number;
    lng: number;
    label: string;
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
    markers: Array<Marker>;
}

We used the [label] input to add label to the marker. We added a label property to the Marker interface, so we changed our code to include the new addition. Our first marker will display new york on top of the marker, others will have Date it was created on top of them.

Now, it would be nice if the names of the markers will be shown on their heads instead of dates they were created. We use geocoding.

We need to install googlemaps library:

npm i googlemaps

We import it in our MapComponent and declare a google var:

import {} from "googlemaps"
declare var google: any;
...

Then, our code:

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker 
    *ngFor="let marker of location.markers" [latitude]="marker.lat" 
    [longitude]="marker.lng" 
    (markerClick)="selectMarker($event)"     [markerDraggable]="true"
    (dragEnd)="markerDragEnd(coords, $event)"
    [label]="marker.label"
></agm-marker>
</agm-map>
<div>
    Selected Marker is: Longitude {{selectedMarker.lat}} Latitude {{selectedMarker.lng}}
</div>
// map.component.ts
...
@Component({
    ...
})
export class MapComponent implements OnInit {
    location: Location
    selectedMarker: Marker

    ngOnInit() {
        this.location = {
            latitude: -28.68352,
            longitude: -147.20785,
            mapType: "satelite",
            zoom: 5,
            markers: [
                {
                    lat: -28.68352,
                    lng: -147.20785,
                    label: this.getAddress(-28.68352, -147.20785)
                }
            ]
        }
    }

    addMarker(lat: number, lng: number) {
        this.location.markers.push({
            lat,
            lng,
            label: this.getAddress(lat, lng)
        })
    }

  getAddress(lat, lng) {
    const geocoder = new google.maps.Geocoder();
    var latlng = new google.maps.LatLng(lat, lng);
    const request: google.maps.GeocoderRequest = {
      location: latlng
    };
    geocoder.geocode(request, (results, status) => {
      this.ngZone.run(() => {
        const address = results[0].formatted_address;
        return address
      });
    });
  }    
    ...
}

interface Marker {
    lat: number;
    lng: number;
    label: string;
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
    markers: Array<Marker>;
}

The getAddress method uses the latitude and longitude passed to it to get the address of the place. See, we modified the addMarker method, so it calls the getAddress method to assign the marker address to the label property.

We constructed a geocoder object, then set a GeoCoder request with the lat and lng passed, finally, we called the geocode method in the geocoder, and in the function callback we got the address of the location.

Displaying our current position 🎌🌍

Here, let’s make it display our current position:

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker 
    *ngFor="let marker of location.markers" [latitude]="marker.lat" 
    [longitude]="marker.lng" 
    (markerClick)="selectMarker($event)"     [markerDraggable]="true"
    (dragEnd)="markerDragEnd(coords, $event)"
    [label]="marker.label"
></agm-marker>
</agm-map>
<div>
    Selected Marker is: Longitude {{selectedMarker.lat}} Latitude {{selectedMarker.lng}}
</div>
// map.component.ts
...
@Component({
    ...
})
export class MapComponent implements OnInit {
    location: Location
    selectedMarker: Marker

    ngOnInit() {
        this.setCurrentPosition()
    }

    addMarker(lat: number, lng: number) {
        this.location.markers.push({
            lat,
            lng,
            label: this.getAddress(lat, lng)
        })
    }
    setCurrentPosition() {
        if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(position => {
            const {latitude, longitude} = position
            this.location = {
                latitude,
                longitude,
                mapType: "satelite",
                zoom: 14,
                markers: [
                    {
                        lat: longitude,
                        lng: latitude,
                        label: "My current position"
                    }
                ]
            }
        });
        } else {
        alert("Geolocation is not supported by this browser, please use google chrome.");
        }
    }
    ...
}

interface Marker {
    lat: number;
    lng: number;
    label: string;
}

interface Location {
    latitude: number;
    longitude: number;
    mapType: ?string;
    zoom: ?number;
    markers: ?Array<Marker>;
}

Now, we have set the component to display our current position on the map when loaded. How did we do it? Simple, we used the navigator object. The navigator has a geolocation object which we use to call the getCurrentPosition() function, this function accepts a function callback which it calls with the location object. See our function callback will receive the location in the position parameter.

Setting direction

We can plot directions on a map. This we do with the help of agm-direction.

First, we install it:

npm i agm-direction

Next, we import the modules:

// app.module.ts
...
import { AgmDirectionModule } from 'agm-direction';

@NgModule({
  ...
  imports: [
    ...
    AgmDirectionModule
  ]
})
export class AppModule { }

So, now to plot direction from origin Taipei Main Station to destination Taiwan Presidential Office:

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <!-- ... -->
    <agm-direction 
        [origin]="origin" 
        [destination]="destination"
    ></agm-direction>
</agm-map>
<!-- ... -->
// map.component.ts
...
@Component({
    ...
})
export class MapComponent implements OnInit {
    ...
    origin: any;
    destination: any;

    ngOnInit() {
        this.origin = { 
            lat: 24.799448, 
            lng: 120.979021 
        };
        this.destination = { 
            lat: 24.799524, 
            lng: 120.975017 
        };
    }
    ...
}
...

Calculating distance between points

We can calculate the distance between points on the map.

To calculate the distance between Taipei Main Station and destination Taiwan Presidential Office, we do this:

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <!-- ... -->
    <agm-direction 
        [origin]="origin" 
        [destination]="destination"
    ></agm-direction>
</agm-map>
<div>
    Distance: {{distance}}
</div>
<!-- ... -->
// map.component.ts
...
@Component({
    ...
})
export class MapComponent implements OnInit {
    ...
    origin: any;
    destination: any;
    distance: Number;

    ngOnInit() {
        this.origin = { 
            lat: 24.799448, 
            lng: 120.979021 
        };
        this.destination = { 
            lat: 24.799524, 
            lng: 120.975017 
        };
        this.distance = this.calculatedistance(this.origin, this.destination)
    }

    // calculate the distances from point1 to point2
    calculateDistance(point1, point2) {
        const p1 = new google.maps.LatLng(
        point1.lat,
        point1.lng
        );
        const p2 = new google.maps.LatLng(
        point2.lat,
        point2.lng
        );
        return (
        google.maps.geometry.spherical.computeDistanceBetween(p1, p2)/1000
        ).toFixed(2);
    }
    ...
}
...

We have a method calculateDistance that computes the distance between two points passed to it. We construct LatLng objects of the two points and pass it to google.maps.geometry.spherical.computeDistanceBetween(...). This returns the distance between the two points.

Rendering info window

We can place an info window over a marker. This is how we do it:

<!-- map.component.html -->
<agm-map [latitude]="location.latitude" [longitude]="location.longitude" [mapTypeId]="location.mapType" [zoom]="location.zoom" (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <agm-marker 
    *ngFor="let marker of location.markers" [latitude]="marker.lat" 
    [longitude]="marker.lng" 
    (markerClick)="selectMarker($event)"     [markerDraggable]="true"
    (dragEnd)="markerDragEnd(coords, $event)"
    [label]="marker.label"
>
         <agm-info-window [disableAutoPan]="true">{{marker.label}}</agm-info-window>
</agm-marker>
    <!-- ... -->
</agm-map>
<!-- ... -->

See it is placed inside the agm-marker.

Drawing a circle on the map

To draw a circle over a location we use the agm-circle tag.

It has the following inputs:

“latitude”: The latitude of the location

“longitude”: The longitude of the location

“clickable”: Sets the circle clickable or not

“draggable”: Sets the circle draggable or not

“editable”: Sets the circle editable or not

“fillColor”: The color of the circle

“fillOpacity”: The transparency of the circle

“radius”: The radius of the circle

<!-- map.component.html -->
<agm-map 
    [latitude]="location.latitude" 
    [longitude]="location.longitude" 
    [mapTypeId]="location.mapType" 
    [zoom]="location.zoom" 
    (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <!-- ... -->
    <agm-circle 
        [latitude]="location.latitude" 
        [longitude]="location.longitude" [clickable]="false" 
        [draggable]="true" 
        [editable]="false" 
        [fillColor]="green" 
        [fillOpacity]="0" 
        [radius]="circleRadius">
    </agm-circle>
</agm-map>
<!-- ... -->

Drawing a rectangle on the map

We use the agm-rectangle. We must provide the bounds:

“north”: The north bound

“east”: The east bound

“south”: The south bound

“west”: The west bound

<!-- map.component.html -->
<agm-map 
    [latitude]="location.latitude" 
    [longitude]="location.longitude" 
    [mapTypeId]="location.mapType" 
    [zoom]="location.zoom" 
    (mapClick)="addMarker($event.coords.lat, $event.coords.lng)">
    <!-- ... -->
    <agm-rectangle 
        [north]="north" 
        [south]="south" 
        [east]="east" 
        [west]="west"> 
    </agm-rectangle>
</agm-map>
<!-- ... -->

Conclusion

We pretty much exhausted Google Maps on Angular. There are still many more on this. Many inputs and outputs in the agm-circle, agm-rectangle, agm-info, agm-marker, agm-direction and agm-map. This should serve as a basic guide to Google Maps in Angular.

Write your comments below, if I missed a point or concept, spelling, grammar error, in short anything at all.

Thanks!!!

#angular #google-maps

How to use Google Maps in Angular?
318.90 GEEK