Drawing a Polygon Using Angular Google Maps

Maria Zacharia
5 min readMay 10, 2020

--

This article demonstrates how to use Angular Google Maps component to construct a polygonal region and compute its area.

1. Create an API Key for your application

In order to use the Maps JavaScript API in your application, you need to generate an API Key. API key is a unique identifier that is used to authenticate requests associated with the application.

Follow the steps mentioned here for getting an API Key:

2. Create an Angular application and install the dependencies

ng new agm-example
npm install @agm/core
ng add @angular/material //optional

3. Add import statements for AgmCoreModule in app.module.ts

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

Also, add it to the imports array along with the API Key you generated for the application.

AgmCoreModule.forRoot({
apiKey: <YOUR_API_KEY>,
libraries: ['places', 'drawing', 'geometry']
})

4. Create a custom angular component to include agm-map component

ng g c agm-example

Once the component is created, add the following in the HTML code to bring up the map interface.

<agm-map [zoom]="5" [latitude]="lat" [longitude]="lng"> </agm-map>

Initialize lat and lng with valid values in the ts file. This would define the center point of the initial view.

lat = 20.5937;
lng = 78.9629;

You can also set the lat and lng as your current location by calling the following function inside ngOnInit()

private setCurrentPosition() {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
this.lat = position.coords.latitude;
this.lng = position.coords.longitude;
});
}
}

5. Set a height for agm-map component

This is really important. If you miss this step, you won't be able to see the map on the screen.

agm-map {
height: 400px;
}

With the above steps done, the google maps UI should be showing up on the screen. The steps following this point are for enabling drawing on the map.

6. Add declare statement for google

Add the following line at the top of agm-example.component.ts file after the import statements.

declare const google: any;

7. Add mapReady Event to agm-map component

<agm-map [zoom]="5" [latitude]="lat" [longitude]="lng"
(mapReady)="onMapReady($event)"
></agm-map>

Define onMapReady() function as shown below, to initialize the drawing manager.

onMapReady(map) {
this.initDrawingManager(map);
}

8. Initialize drawingManager

const options = {
drawingControl: true,
drawingControlOptions: {
drawingModes: ['polygon'],
},
polygonOptions: {
draggable: true,
editable: true,
},
drawingMode: google.maps.drawing.OverlayType.POLYGON,
};
this.drawingManager = new google.maps.drawing.DrawingManager(options);

9. Add event listeners

The following are the major events you need to handle:

  • overlaycomplete
    Set on the drawing manager. It is invoked whenever a closed polygon is created on the map.
  • insert_at
    Set on each point in the path. It is invoked whenever a new point is added to the polygon.
  • remove_at
    Set on each point in the path. It is invoked whenever a point is removed from the polygon.
  • set_at
    Set on each point in the path. It is invoked whenever a point in the polygon is edited.

Whenever overlaycomplete is invoked, that means the closed polygon is either created or updated. Once you get the points on the polygon, you need to add event listeners for the other three events (namely, insert_at, remove_at, set_at) mentioned above, for all the points.

10. Define variables to store the polygon coordinates and area

Define an array to store the points which make up the polygon and another variable to store the area enclosed by the polygon.

pointList: { lat: number; lng: number }[] = [];
selectedArea = 0;

Whenever the events mentioned in step 9 get fired, you need to update the above two variables by calling the following function with event.overlay.getPath() as the parameter.

updatePointList(path) {
this.pointList = [];
const len = path.getLength();
for (let i = 0; i < len; i++) {
this.pointList.push(
path.getAt(i).toJSON()
);
}
this.selectedArea = google.maps.geometry.spherical.computeArea(
path
);
}

In order to compute the spherical area enclosed by the polygon, you need to use computeArea() function, which is available as part of the google maps module.

11. Set selectedShape variable

Once we are done creating one closed polygon, we need to make sure that we store it in a variable, say selectedShape, for future reference. This can be done by calling the following setSelection() function with the new polygon created as an argument.

Whenever we are trying to set the new polygon, we also need to make sure we are clearing the existing shape. For that, we use the clearSelection() function as defined below.

We will be making use of the selectedShape variable later when we need to delete the polygon drawn.

  clearSelection() {
if (this.selectedShape) {
this.selectedShape.setEditable(false);
this.selectedShape = null;
this.pointList = [];
}
}
setSelection(shape) {
this.clearSelection();
this.selectedShape = shape;
shape.setEditable(true);
}

12. Limit the drawing to one polygon

By default, you will be able to draw any number of polygons on the map. This can be prevented by setting the drawingMode to null once you complete creating one closed polygon.

self.drawingManager.setDrawingMode(null);
// To hide the controls:
self.drawingManager.setOptions({
drawingControl: false
});

With steps 8–11 completed, initDrawingManager() function would look like the following:

initDrawingManager = (map: any) => {
const self = this;
const options = {
drawingControl: true,
drawingControlOptions: {
drawingModes: ['polygon'],
},
polygonOptions: {
draggable: true,
editable: true,
},
drawingMode: google.maps.drawing.OverlayType.POLYGON,
};
this.drawingManager = new google.maps.drawing.DrawingManager(options);
this.drawingManager.setMap(map);
google.maps.event.addListener(
this.drawingManager,
'overlaycomplete',
(event) => {
if (event.type === google.maps.drawing.OverlayType.POLYGON) {
const paths = event.overlay.getPaths();
for (let p = 0; p < paths.getLength(); p++) {
google.maps.event.addListener(
paths.getAt(p),
'set_at',
() => {
if (!event.overlay.drag) {
self.updatePointList(event.overlay.getPath());
}
}
);
google.maps.event.addListener(
paths.getAt(p),
'insert_at',
() => {
self.updatePointList(event.overlay.getPath());
}
);
google.maps.event.addListener(
paths.getAt(p),
'remove_at',
() => {
self.updatePointList(event.overlay.getPath());
}
);
}
self.updatePointList(event.overlay.getPath());
}
if (event.type !== google.maps.drawing.OverlayType.MARKER) {
// Switch back to non-drawing mode after drawing a shape.
self.drawingManager.setDrawingMode(null);
// To hide:
self.drawingManager.setOptions({
drawingControl: false,
});
}
}
);
}

13. Delete the current polygon

If in case you wish to delete the current selection, you just need to set the map as null.

deleteSelectedShape() {
if (this.selectedShape) {
this.selectedShape.setMap(null);
this.selectedArea = 0;
this.pointList = [];
// To show the controls:
this.drawingManager.setOptions({
drawingControl: true,
});
}
}

With the above steps done, the application would look similar to the following:

P.S. I have added some styling and a list view to show up the co-ordinates list in the component. Those details are omitted in the article. But you can find the complete code at:

If you like what you read and would like to hire me for a one-on-one consultation or get mentoring from me, reach out to me using

https://hiretheauthor.com/maria

--

--

Maria Zacharia

Co-Founder & CTO at Hire the Author. Want to have a 1–1 with me? Reach out to me at https://hiretheauthor.com/maria