Skip to main content

Overview

The GroundOverlay component displays an image overlay bound to specific geographic coordinates. The image will scale and rotate with the map, making it perfect for displaying floor plans, historical maps, or other geographic imagery.

Import

import { GroundOverlay } from '@react-google-maps/api'

Props

url
string
required
The URL of the image to display as the overlay.
bounds
google.maps.LatLngBoundsLiteral
required
The geographic bounds to which the image will be scaled. Must include north, south, east, and west properties.
options
google.maps.GroundOverlayOptions
Additional options for the ground overlay. See Google Maps GroundOverlayOptions for available options.
opacity
number
default:"1"
The opacity of the overlay, expressed as a number between 0 (fully transparent) and 1 (fully opaque).
visible
boolean
Whether the overlay is visible. When set to false, the overlay’s opacity is set to 0.
onClick
(e: google.maps.MapMouseEvent) => void
Callback fired when the ground overlay is clicked.
onDblClick
(e: google.maps.MapMouseEvent) => void
Callback fired when the ground overlay is double-clicked.
onLoad
(groundOverlay: google.maps.GroundOverlay) => void
Callback invoked when the ground overlay instance has loaded. Receives the google.maps.GroundOverlay instance.
onUnmount
(groundOverlay: google.maps.GroundOverlay) => void
Callback invoked when the component unmounts. Receives the google.maps.GroundOverlay instance.

Basic Usage

Simple Image Overlay

import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function MyMapComponent() {
  const bounds = {
    north: 40.773941,
    south: 40.712216,
    east: -74.12544,
    west: -74.22655
  }

  return (
    <GoogleMap
      center={{ lat: 40.743, lng: -74.176 }}
      zoom={12}
    >
      <GroundOverlay
        url="https://example.com/historical-map.png"
        bounds={bounds}
      />
    </GoogleMap>
  )
}

Semi-Transparent Overlay

import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function TransparentOverlay() {
  const bounds = {
    north: 51.52,
    south: 51.48,
    east: -0.08,
    west: -0.14
  }

  return (
    <GoogleMap
      center={{ lat: 51.5, lng: -0.11 }}
      zoom={13}
    >
      <GroundOverlay
        url="https://example.com/zone-map.png"
        bounds={bounds}
        opacity={0.6}
      />
    </GoogleMap>
  )
}

Interactive Overlay

import { useState } from 'react'
import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function InteractiveOverlay() {
  const [overlayRef, setOverlayRef] = useState<google.maps.GroundOverlay | null>(null)

  const bounds = {
    north: 37.785,
    south: 37.745,
    east: -122.4,
    west: -122.45
  }

  const handleClick = (e: google.maps.MapMouseEvent) => {
    console.log('Overlay clicked at:', e.latLng?.toString())
    alert('You clicked the overlay!')
  }

  const handleLoad = (overlay: google.maps.GroundOverlay) => {
    setOverlayRef(overlay)
    console.log('Ground overlay loaded')
  }

  return (
    <GoogleMap
      center={{ lat: 37.765, lng: -122.425 }}
      zoom={13}
    >
      <GroundOverlay
        url="https://example.com/campus-map.png"
        bounds={bounds}
        onClick={handleClick}
        onLoad={handleLoad}
      />
    </GoogleMap>
  )
}

Togglable Overlay

import { useState } from 'react'
import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function TogglableOverlay() {
  const [visible, setVisible] = useState(true)

  const bounds = {
    north: 34.06,
    south: 34.04,
    east: -118.23,
    west: -118.25
  }

  return (
    <div>
      <button onClick={() => setVisible(!visible)}>
        {visible ? 'Hide' : 'Show'} Overlay
      </button>
      <GoogleMap
        center={{ lat: 34.05, lng: -118.24 }}
        zoom={14}
      >
        <GroundOverlay
          url="https://example.com/building-floor-plan.png"
          bounds={bounds}
          visible={visible}
        />
      </GoogleMap>
    </div>
  )
}

Common Patterns

Multiple Overlays (Historical Map Comparison)

import { useState } from 'react'
import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function HistoricalMapComparison() {
  const [selectedYear, setSelectedYear] = useState('2020')

  const bounds = {
    north: 48.865,
    south: 48.845,
    east: 2.35,
    west: 2.33
  }

  const maps = {
    '1900': 'https://example.com/paris-1900.png',
    '1950': 'https://example.com/paris-1950.png',
    '2020': 'https://example.com/paris-2020.png',
  }

  return (
    <div>
      <div style={{ marginBottom: '10px' }}>
        {Object.keys(maps).map((year) => (
          <button
            key={year}
            onClick={() => setSelectedYear(year)}
            style={{
              marginRight: '5px',
              fontWeight: selectedYear === year ? 'bold' : 'normal'
            }}
          >
            {year}
          </button>
        ))}
      </div>
      <GoogleMap
        center={{ lat: 48.855, lng: 2.34 }}
        zoom={14}
      >
        <GroundOverlay
          url={maps[selectedYear]}
          bounds={bounds}
          opacity={0.7}
        />
      </GoogleMap>
    </div>
  )
}

Floor Plan Overlay

import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function BuildingFloorPlan() {
  // Precisely align floor plan to building coordinates
  const buildingBounds = {
    north: 37.422422,
    south: 37.421922,
    east: -122.083831,
    west: -122.084331
  }

  return (
    <GoogleMap
      center={{ lat: 37.422172, lng: -122.084081 }}
      zoom={20}
      mapTypeId="satellite"
    >
      <GroundOverlay
        url="https://example.com/building-floor-1.png"
        bounds={buildingBounds}
        opacity={0.8}
        onClick={(e) => {
          console.log('Floor plan clicked:', e.latLng?.toJSON())
        }}
      />
    </GoogleMap>
  )
}

Weather Radar Overlay

import { useState, useEffect } from 'react'
import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function WeatherRadarOverlay() {
  const [radarUrl, setRadarUrl] = useState('https://example.com/radar/latest.png')

  // Update radar image every 5 minutes
  useEffect(() => {
    const interval = setInterval(() => {
      setRadarUrl(`https://example.com/radar/latest.png?t=${Date.now()}`)
    }, 5 * 60 * 1000)

    return () => clearInterval(interval)
  }, [])

  const radarBounds = {
    north: 42.0,
    south: 40.0,
    east: -70.0,
    west: -75.0
  }

  return (
    <GoogleMap
      center={{ lat: 41.0, lng: -72.5 }}
      zoom={7}
    >
      <GroundOverlay
        url={radarUrl}
        bounds={radarBounds}
        opacity={0.6}
      />
    </GoogleMap>
  )
}

Dynamically Positioned Overlay

import { useState } from 'react'
import { GoogleMap, GroundOverlay } from '@react-google-maps/api'

function DynamicOverlay() {
  const [bounds, setBounds] = useState({
    north: 35.7,
    south: 35.6,
    east: 139.8,
    west: 139.7
  })

  const handleMapClick = (e: google.maps.MapMouseEvent) => {
    if (e.latLng) {
      const lat = e.latLng.lat()
      const lng = e.latLng.lng()
      
      // Center the overlay on the clicked location
      setBounds({
        north: lat + 0.05,
        south: lat - 0.05,
        east: lng + 0.05,
        west: lng - 0.05
      })
    }
  }

  return (
    <GoogleMap
      center={{ lat: 35.65, lng: 139.75 }}
      zoom={11}
      onClick={handleMapClick}
    >
      <GroundOverlay
        url="https://example.com/marker-area.png"
        bounds={bounds}
        opacity={0.5}
      />
    </GoogleMap>
  )
}

Notes

  • Images should be properly georeferenced or you need to know the exact bounds
  • The image will automatically scale and rotate with the map
  • Supported image formats include PNG, JPEG, and GIF
  • For best performance, optimize your image file size
  • The bounds object must have all four properties: north, south, east, west
  • Use opacity for semi-transparent overlays that let the base map show through
  • Ground overlays render in the OVERLAY_LAYER pane of the map
  • Changing the url or bounds props will update the overlay dynamically

Build docs developers (and LLMs) love