Angular Google Maps: Boundary Data Driven Styling
Introduction
With the integration of Google Maps in Angular applications, developers can build highly interactive map interfaces. The @angular/google-maps
package offers a comprehensive solution for embedding Google Maps, providing a rich set of features to enhance user experience. One advanced feature is boundary data-driven styling, which allows for dynamic styling of map boundaries based on data attributes.
In this article, we will walk through the implementation of boundary data-driven styling using @angular/google-maps
in an Angular application. We will demonstrate how to set up the map, load tiles, and apply custom styles to specific geographic boundaries based on place IDs.
Live Link: https://mapboundary.netlify.app/
GitHub Repo: https://github.com/babluroy/angular-google-maps-place-boundary
Prerequisites
To follow along with this tutorial, you will need:
An Angular application set up with
@angular/google-maps
installed.A Google Maps API key with appropriate permissions.
A generated map ID from the Google Cloud Platform with a custom map style applied.
Step-by-Step Implementation
1. Setup the Angular Component
First, we create an Angular component that will house our Google Map. We will use the @angular/google-maps
package to embed the map and manage its properties.
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { GoogleMap } from '@angular/google-maps';
@Component({
selector: 'app-root',
imports: [RouterOutlet, GoogleMap],
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
standalone: true,
})
export class AppComponent implements AfterViewInit {
@ViewChild(GoogleMap, { static: true }) map!: any;
center: google.maps.LatLngLiteral = { lat: 40.730610, lng: -73.935242 };
zoom = 10;
mapLoaded: boolean = false;
placeId: string = 'ChIJOwg_06VPwokRYv534QaPC8g'; // Default Place ID
constructor() { }
ngOnInit() { }
ngAfterViewInit(): void { }
/**
* @ngdoc controller
* @name tilesLoaded
* @description
* runs when tiles are loaded
**/
tilesLoaded($event: any) {
if (!this.mapLoaded) {
this.drawPlaceboundary();
this.mapLoaded = true;
}
}
/**
* @ngdoc controller
* @name drawPlaceboundary
* @description
* draws place boundary as per place id
**/
drawPlaceboundary() {
let featureLayer = this.map.googleMap.data.map.getFeatureLayer('LOCALITY');
const featureStyleOptions = {
strokeColor: "#810FCB",
strokeOpacity: 1.0,
strokeWeight: 3.0,
fillColor: "#810FCB",
fillOpacity: 0.5,
};
//@ts-ignore
featureLayer.style = (options) => {
if (options.feature.placeId == this.placeId) {
return featureStyleOptions;
}
};
}
/**
* @ngdoc controller
* @name setPlaceBoundary
* @description
* Sets a new place ID and redraws the boundary
**/
setPlaceBoundary(newPlaceId: string) {
this.placeId = newPlaceId;
this.drawPlaceboundary();
}
}
2. Template Configuration
Next, we configure the template for our component to include the google-map
directive. This directive will render the Google Map and bind our component's properties to the map's attributes.
<google-map
height="610px"
width="1340px"
[center]="center"
[zoom]="zoom"
(tilesloaded)="tilesLoaded($event)"
[mapId]="'a3efe1c035bad51b'"
></google-map>
3. Handling Tiles Loaded Event
The tilesLoaded
event is triggered when the map's tiles have finished loading. We utilize this event to ensure our boundary drawing function is only called once the map is fully loaded.
tilesLoaded($event: any) {
if (!this.mapLoaded) {
this.drawPlaceboundary();
this.mapLoaded = true;
}
}
4. Drawing Place Boundary
The drawPlaceboundary
method is where the magic happens. We use the Google Maps Data Layer API to access and style geographic features on the map. In this example, we target the 'LOCALITY' feature layer and apply custom styles to the boundary of a specific place ID.
drawPlaceboundary() {
let featureLayer = this.map.googleMap.data.map.getFeatureLayer('LOCALITY');
const featureStyleOptions = {
strokeColor: "#810FCB",
strokeOpacity: 1.0,
strokeWeight: 3.0,
fillColor: "#810FCB",
fillOpacity: 0.5,
};
//@ts-ignore
featureLayer.style = (options) => {
if (options.feature.placeId == this.placeId) {
return featureStyleOptions;
}
};
}
5. Setting Dynamic Place IDs
To dynamically change the place ID and update the map boundary, we add a method setPlaceBoundary
. This method allows us to pass a new place ID and redraw the boundary.
setPlaceBoundary(newPlaceId: string) {
this.placeId = newPlaceId;
this.drawPlaceboundary();
}
Making it Dynamic
We can make this functionality dynamic by passing different place IDs to the setPlaceBoundary
method. This allows us to show the boundaries of various places on the map. By integrating the Places API, we can retrieve place details dynamically and update the map accordingly.
Integrating and Testing
Ensure your Angular application is properly configured to use the @angular/google-maps
package, and that your Google Maps API key is valid and included in your environment configuration. Additionally, ensure you have generated a map ID from the Google Cloud Platform and applied a custom map style to it.
Once everything is set up, run your Angular application. You should see the Google Map rendered with the specified place boundary styled according to your configuration. Use the setPlaceBoundary
method to dynamically update the place boundary based on user input or other application logic.
Conclusion
By leveraging the power of @angular/google-maps
and the Google Maps Data Layer API, we can create dynamic and data-driven map interfaces in Angular applications. This tutorial demonstrated how to implement boundary data-driven styling, enabling developers to highlight specific geographic areas based on data attributes. Additionally, by passing dynamic place IDs, we can display boundaries of various places using the Places API to retrieve place details. Experiment with different styles and data attributes to create compelling map visualizations for your applications.
Subscribe to my newsletter
Read articles from Bablu Roy directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by