The DrawingManager component provides drawing tools that allow users to draw shapes (markers, polylines, polygons, rectangles, circles) directly on the map. Both DrawingManager and DrawingManagerF variants are available and functionally identical.
Import
import { DrawingManager } from '@react-google-maps/api'
// or
import { DrawingManagerF } from '@react-google-maps/api'
The DrawingManager requires the drawing library to be loaded. You must include libraries={['drawing']} in your useJsApiLoader or LoadScript configuration.
Basic Usage
import { GoogleMap, DrawingManager, useJsApiLoader } from '@react-google-maps/api'
function MyMap() {
const { isLoaded } = useJsApiLoader({
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY,
libraries: ['drawing'] // Required!
})
if (!isLoaded) return <div>Loading...</div>
return (
<GoogleMap
center={{ lat: 40.7128, lng: -74.0060 }}
zoom={12}
>
<DrawingManager />
</GoogleMap>
)
}
Props
options
google.maps.drawing.DrawingManagerOptions
Drawing manager configuration options including drawing modes, controls, and styling for each shape type.
drawingMode
google.maps.drawing.OverlayType | null
The current drawing mode. Options:
google.maps.drawing.OverlayType.MARKER
google.maps.drawing.OverlayType.POLYLINE
google.maps.drawing.OverlayType.POLYGON
google.maps.drawing.OverlayType.RECTANGLE
google.maps.drawing.OverlayType.CIRCLE
null (hand/pan mode)
Events
onCircleComplete
(circle: google.maps.Circle) => void
Fired when the user finishes drawing a circle.
onMarkerComplete
(marker: google.maps.Marker) => void
Fired when the user finishes drawing a marker.
onPolygonComplete
(polygon: google.maps.Polygon) => void
Fired when the user finishes drawing a polygon.
onPolylineComplete
(polyline: google.maps.Polyline) => void
Fired when the user finishes drawing a polyline.
onRectangleComplete
(rectangle: google.maps.Rectangle) => void
Fired when the user finishes drawing a rectangle.
onOverlayComplete
(e: google.maps.drawing.OverlayCompleteEvent) => void
Fired when any overlay is completed. The event contains the overlay type and instance.
onLoad
(drawingManager: google.maps.drawing.DrawingManager) => void
Callback invoked when the DrawingManager instance has loaded.
onUnmount
(drawingManager: google.maps.drawing.DrawingManager) => void
Callback invoked when the DrawingManager is unmounted.
Examples
import { useState } from 'react'
import { GoogleMap, DrawingManager } from '@react-google-maps/api'
function DrawingTools() {
const [shapes, setShapes] = useState([])
return (
<GoogleMap
center={{ lat: 40.7128, lng: -74.0060 }}
zoom={12}
>
<DrawingManager
options={{
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.MARKER,
google.maps.drawing.OverlayType.CIRCLE,
google.maps.drawing.OverlayType.POLYGON,
google.maps.drawing.OverlayType.POLYLINE,
google.maps.drawing.OverlayType.RECTANGLE
]
}
}}
onOverlayComplete={(e) => {
setShapes([...shapes, e])
console.log('Shape drawn:', e.type)
}}
/>
</GoogleMap>
)
}
Custom Styled Shapes
<DrawingManager
options={{
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.POLYGON,
google.maps.drawing.OverlayType.CIRCLE
]
},
circleOptions: {
fillColor: '#FF0000',
fillOpacity: 0.3,
strokeWeight: 2,
strokeColor: '#FF0000',
clickable: true,
editable: true,
draggable: true
},
polygonOptions: {
fillColor: '#0000FF',
fillOpacity: 0.3,
strokeWeight: 2,
strokeColor: '#0000FF',
clickable: true,
editable: true,
draggable: true
}
}}
/>
Controlled Drawing Mode
import { useState } from 'react'
import { GoogleMap, DrawingManager } from '@react-google-maps/api'
function ControlledDrawing() {
const [drawingMode, setDrawingMode] = useState(null)
return (
<div>
<div style={{ marginBottom: '10px' }}>
<button onClick={() => setDrawingMode(google.maps.drawing.OverlayType.MARKER)}>
Draw Marker
</button>
<button onClick={() => setDrawingMode(google.maps.drawing.OverlayType.POLYGON)}>
Draw Polygon
</button>
<button onClick={() => setDrawingMode(google.maps.drawing.OverlayType.CIRCLE)}>
Draw Circle
</button>
<button onClick={() => setDrawingMode(null)}>
Stop Drawing
</button>
</div>
<GoogleMap center={{ lat: 40.7128, lng: -74.0060 }} zoom={12}>
<DrawingManager
drawingMode={drawingMode}
options={{
drawingControl: false // Hide default controls
}}
onOverlayComplete={(e) => {
console.log('Completed:', e.type)
setDrawingMode(null) // Reset to pan mode after drawing
}}
/>
</GoogleMap>
</div>
)
}
Save Drawn Shapes
import { useState } from 'react'
import { GoogleMap, DrawingManager } from '@react-google-maps/api'
function SaveShapes() {
const [shapes, setShapes] = useState([])
const handleOverlayComplete = (e) => {
const newShape = {
type: e.type,
overlay: e.overlay
}
setShapes([...shapes, newShape])
// Extract coordinates based on shape type
if (e.type === google.maps.drawing.OverlayType.POLYGON) {
const path = e.overlay.getPath()
const coordinates = []
for (let i = 0; i < path.getLength(); i++) {
const point = path.getAt(i)
coordinates.push({ lat: point.lat(), lng: point.lng() })
}
console.log('Polygon coordinates:', coordinates)
}
if (e.type === google.maps.drawing.OverlayType.CIRCLE) {
const center = e.overlay.getCenter()
const radius = e.overlay.getRadius()
console.log('Circle:', {
center: { lat: center.lat(), lng: center.lng() },
radius
})
}
}
const clearShapes = () => {
shapes.forEach(shape => shape.overlay.setMap(null))
setShapes([])
}
return (
<div>
<button onClick={clearShapes}>Clear All Shapes</button>
<div>Total shapes: {shapes.length}</div>
<GoogleMap center={{ lat: 40.7128, lng: -74.0060 }} zoom={12}>
<DrawingManager onOverlayComplete={handleOverlayComplete} />
</GoogleMap>
</div>
)
}
Delete Shapes on Right-Click
import { useState } from 'react'
import { GoogleMap, DrawingManager } from '@react-google-maps/api'
function EditableDrawing() {
const [shapes, setShapes] = useState([])
const handleOverlayComplete = (e) => {
const shape = e.overlay
// Add right-click listener to delete
google.maps.event.addListener(shape, 'rightclick', () => {
shape.setMap(null)
setShapes(shapes.filter(s => s !== shape))
})
setShapes([...shapes, shape])
}
return (
<GoogleMap center={{ lat: 40.7128, lng: -74.0060 }} zoom={12}>
<DrawingManager
options={{
polygonOptions: { editable: true, draggable: true },
circleOptions: { editable: true, draggable: true },
rectangleOptions: { editable: true, draggable: true },
polylineOptions: { editable: true, draggable: true }
}}
onOverlayComplete={handleOverlayComplete}
/>
</GoogleMap>
)
}
import { useState } from 'react'
import { GoogleMap, DrawingManager } from '@react-google-maps/api'
function AreaMeasurement() {
const [area, setArea] = useState(0)
const calculateArea = (polygon) => {
const path = polygon.getPath()
const area = google.maps.geometry.spherical.computeArea(path)
return area // in square meters
}
return (
<div>
<div>Area: {(area / 1000000).toFixed(2)} km²</div>
<GoogleMap center={{ lat: 40.7128, lng: -74.0060 }} zoom={12}>
<DrawingManager
options={{
drawingControl: true,
drawingControlOptions: {
drawingModes: [google.maps.drawing.OverlayType.POLYGON]
},
polygonOptions: {
fillColor: '#4285F4',
fillOpacity: 0.3,
strokeWeight: 2,
editable: true
}
}}
onPolygonComplete={(polygon) => {
setArea(calculateArea(polygon))
// Update area when edited
google.maps.event.addListener(polygon.getPath(), 'set_at', () => {
setArea(calculateArea(polygon))
})
google.maps.event.addListener(polygon.getPath(), 'insert_at', () => {
setArea(calculateArea(polygon))
})
}}
/>
</GoogleMap>
</div>
)
}
Drawing with Snap to Roads
import { useState } from 'react'
import { GoogleMap, DrawingManager, Polyline } from '@react-google-maps/api'
function RouteDrawing() {
const [routes, setRoutes] = useState([])
return (
<GoogleMap center={{ lat: 40.7128, lng: -74.0060 }} zoom={12}>
<DrawingManager
options={{
drawingControl: true,
drawingControlOptions: {
drawingModes: [google.maps.drawing.OverlayType.POLYLINE]
},
polylineOptions: {
strokeColor: '#4285F4',
strokeWeight: 4,
editable: true
}
}}
onPolylineComplete={(polyline) => {
const path = polyline.getPath()
const coordinates = []
for (let i = 0; i < path.getLength(); i++) {
const point = path.getAt(i)
coordinates.push({ lat: point.lat(), lng: point.lng() })
}
setRoutes([...routes, coordinates])
console.log('Route drawn:', coordinates)
}}
/>
</GoogleMap>
)
}
Common Options
The options prop accepts a google.maps.drawing.DrawingManagerOptions object:
{
drawingControl: boolean,
drawingControlOptions: {
position: google.maps.ControlPosition,
drawingModes: google.maps.drawing.OverlayType[]
},
markerOptions: google.maps.MarkerOptions,
polylineOptions: google.maps.PolylineOptions,
rectangleOptions: google.maps.RectangleOptions,
circleOptions: google.maps.CircleOptions,
polygonOptions: google.maps.PolygonOptions
}
Drawing Modes
Available overlay types:
google.maps.drawing.OverlayType.MARKER - Single point marker
google.maps.drawing.OverlayType.POLYLINE - Connected line segments
google.maps.drawing.OverlayType.POLYGON - Closed polygon shape
google.maps.drawing.OverlayType.RECTANGLE - Rectangular area
google.maps.drawing.OverlayType.CIRCLE - Circular area
Required Library
Don’t forget to include the drawing library:const { isLoaded } = useJsApiLoader({
googleMapsApiKey: 'YOUR_API_KEY',
libraries: ['drawing']
})
Component Variants
Both DrawingManager and DrawingManagerF are available and functionally identical:
DrawingManager - Default export
DrawingManagerF - Functional component variant (same implementation)
import { DrawingManager } from '@react-google-maps/api'
// or
import { DrawingManagerF } from '@react-google-maps/api'