Angular Google Maps: Boundary Data Driven Styling

Angular Google Maps: Boundary Data Driven Styling

·

4 min read

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.