Angular Google Maps (@angular/google-maps) integration for interactive map features...
GoogleMapsModule from @angular/google-mapsindex.html with API key@types/google.maps for TypeScript types<google-map> component with [center], [zoom], [options] bindingsgoogle-map element (required for display)google.maps.LatLngLiteral type for positions: { lat: number, lng: number }(mapClick), (mapDrag), (zoomChanged)<map-marker> component inside <google-map>[position], [label], [title], [options](mapClick), (mapDragend)<map-info-window> component for marker popups@ViewChild(MapInfoWindow)infoWindow.open() to display, infoWindow.close() to hide<map-polygon> for polygon shapes with [paths] and [options]<map-polyline> for lines with [path] and [options]<map-circle> for circles with [center], [radius], [options]fillColor, strokeColor, opacity, strokeWeightgoogle.maps.Geocoder for address/coordinate conversionAngular Google Maps provides official Angular bindings for Google Maps JavaScript API, enabling declarative map integration with markers, polygons, info windows, and geocoding services.
Activate this skill when you need to:
npm install @angular/google-maps
# Types for TypeScript
npm install @types/google.maps
<!-- index.html -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
import { Component } from '@angular/core';
import { GoogleMapsModule } from '@angular/google-maps';
@Component({
selector: 'app-map',
standalone: true,
imports: [GoogleMapsModule],
template: `
<google-map
[center]="center"
[zoom]="zoom"
[options]="options"
(mapClick)="onMapClick($event)">
<map-marker
*ngFor="let marker of markers"
[position]="marker.position"
[label]="marker.label"
[title]="marker.title"
(mapClick)="onMarkerClick(marker)">
</map-marker>
</google-map>
`,
styles: [`
google-map {
height: 400px;
width: 100%;
}
`]
})
export class MapComponent {
center: google.maps.LatLngLiteral = { lat: 25.033, lng: 121.565 }; // Taipei
zoom = 12;
options: google.maps.MapOptions = {
mapTypeId: 'roadmap',
disableDefaultUI: false,
zoomControl: true,
scrollwheel: true
};
markers: Marker[] = [
{ position: { lat: 25.033, lng: 121.565 }, label: 'A', title: 'Taipei 101' }
];
onMapClick(event: google.maps.MapMouseEvent) {
if (event.latLng) {
const newMarker = {
position: event.latLng.toJSON(),
label: String.fromCharCode(65 + this.markers.length),
title: 'New Location'
};
this.markers.push(newMarker);
}
}
onMarkerClick(marker: Marker) {
console.log('Marker clicked:', marker);
}
}
interface Marker {
position: google.maps.LatLngLiteral;
label?: string;
title?: string;
}
@Component({
template: `
<google-map [center]="center" [zoom]="zoom">
<map-marker
*ngFor="let marker of markers"
[position]="marker.position"
(mapClick)="openInfo(marker, infoWindow)">
</map-marker>
<map-info-window #infoWindow>
<div *ngIf="selectedMarker">
<h3>{{ selectedMarker.title }}</h3>
<p>{{ selectedMarker.description }}</p>
</div>
</map-info-window>
</google-map>
`
})
export class MapWithInfoComponent {
@ViewChild(MapInfoWindow) infoWindow!: MapInfoWindow;
selectedMarker: any;
openInfo(marker: any, infoWindow: MapInfoWindow) {
this.selectedMarker = marker;
infoWindow.open();
}
}
import { MarkerClusterer } from '@googlemaps/markerclusterer';
@Component({
template: `
<google-map #map [center]="center" [zoom]="zoom">
<map-marker
*ngFor="let marker of markers"
[position]="marker.position">
</map-marker>
</google-map>
`
})
export class ClusteredMapComponent implements AfterViewInit {
@ViewChild('map') mapComponent!: GoogleMap;
markers: Marker[] = [];
ngAfterViewInit() {
if (this.mapComponent.googleMap) {
const markerClusterer = new MarkerClusterer({
map: this.mapComponent.googleMap,
markers: this.getGoogleMarkers()
});
}
}
private getGoogleMarkers(): google.maps.Marker[] {
return this.markers.map(m =>
new google.maps.Marker({ position: m.position })
);
}
}
@Component({
template: `
<google-map [center]="center" [zoom]="zoom">
<map-polygon
[paths]="polygonPaths"
[options]="polygonOptions">
</map-polygon>
<map-polyline
[path]="polylinePath"
[options]="polylineOptions">
</map-polyline>
<map-circle
[center]="circleCenter"
[radius]="circleRadius"
[options]="circleOptions">
</map-circle>
</google-map>
`
})
export class DrawingMapComponent {
polygonPaths: google.maps.LatLngLiteral[] = [
{ lat: 25.033, lng: 121.565 },
{ lat: 25.035, lng: 121.567 },
{ lat: 25.031, lng: 121.569 }
];
polygonOptions: google.maps.PolygonOptions = {
fillColor: '#FF0000',
fillOpacity: 0.3,
strokeColor: '#FF0000',
strokeOpacity: 1,
strokeWeight: 2
};
polylinePath: google.maps.LatLngLiteral[] = [
{ lat: 25.030, lng: 121.560 },
{ lat: 25.035, lng: 121.565 }
];
polylineOptions: google.maps.PolylineOptions = {
strokeColor: '#0000FF',
strokeOpacity: 1.0,
strokeWeight: 3
};
circleCenter: google.maps.LatLngLiteral = { lat: 25.033, lng: 121.565 };
circleRadius = 1000; // meters
circleOptions: google.maps.CircleOptions = {
fillColor: '#00FF00',
fillOpacity: 0.2,
strokeColor: '#00FF00',
strokeOpacity: 0.8,
strokeWeight: 2
};
}
import { Injectable } from '@angular/core';
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class GeocodingService {
private geocoder = new google.maps.Geocoder();
geocodeAddress(address: string): Observable<google.maps.LatLngLiteral | null> {
return from(
this.geocoder.geocode({ address })
).pipe(
map(response => {
if (response.results && response.results[0]) {
const location = response.results[0].geometry.location;
return { lat: location.lat(), lng: location.lng() };
}
return null;
})
);
}
reverseGeocode(location: google.maps.LatLngLiteral): Observable<string | null> {
return from(
this.geocoder.geocode({ location })
).pipe(
map(response => {
if (response.results && response.results[0]) {
return response.results[0].formatted_address;
}
return null;
})
);
}
}