A Vue 3 library for drawing shapes on Google Maps with edge snapping support
npm install vue-map-drawingA Vue 3 library for drawing polygons, circles, rectangles, and custom shapes on Google Maps with edge snapping and undo/redo support.
- Vue 3 Composition API: Full integration with reactive composables
- Shape Drawing: Polygon, Circle, Rectangle, Polyline and custom shapes
- Edge Snapping: Automatic snapping to edges of other shapes
- Editing: Edit drawn shapes by dragging vertices
- Shape Labels: Display and edit custom names on shapes
- Deletion: Delete shapes with a single click or keyboard
- Undo/Redo: Undo and redo all operations (Ctrl+Z / Ctrl+Y)
- TypeScript Ready: Full type support
``bash`
npm install vue-map-drawing
- Vue 3.3+
- Google Maps JavaScript API
`html`
Or use the Dynamic Library Import (recommended for Vue):
`javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
// Load Google Maps API asynchronously
async function loadGoogleMaps() {
const { Map } = await google.maps.importLibrary("maps")
const { Polygon, Circle, Rectangle, Polyline, Marker } = await google.maps.importLibrary("marker")
return { Map, Polygon, Circle, Rectangle, Polyline, Marker }
}
createApp(App).mount('#app')
`
`vue
v-for="shape in shapes"
:key="shape.id"
class="shape-item"
:class="{ active: activeShape?.id === shape.id }"
>
{{ shape.type }} - {{ shape.id }}
`
Main composable. Used with a Google Maps instance.
#### Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| map | Ref | Google Maps instance ref |options
| | DrawingOptions | Configuration options |
#### Options
`typescript
interface DrawingOptions {
snapping?: {
enabled?: boolean // Default: true
threshold?: number // Default: 10 (pixels)
showIndicator?: boolean // Default: true
}
history?: {
enabled?: boolean // Default: true
maxSteps?: number // Default: 50
}
styles?: {
drawing?: ShapeStyle // While drawing
completed?: ShapeStyle // Completed shape
hover?: ShapeStyle // Hover state
selected?: ShapeStyle // Selected state
}
}
interface ShapeStyle {
strokeColor?: string
strokeWeight?: number
strokeOpacity?: number
fillColor?: string
fillOpacity?: number
}
`
#### Return Values (Reactive)
`javascript
// Reactive State
shapes // All shapes array
activeShape // Active/selected shape or null
isDrawing // Is drawing mode active
drawingType // Active drawing type ('polygon', 'circle', etc.)
drawingHint // Helper text for current drawing mode
pointCount // Number of points drawn
canUndo // Can undo
canRedo // Can redo
snapActive // Is snap point detected
snappingEnabled // Is snapping enabled
// Drawing Methods
startDrawing(type) // Start drawing ('polygon', 'circle', 'rectangle', 'polyline')
stopDrawing() // Cancel current drawing
completeDrawing() // Complete current drawing
// Shape Methods
deleteShape(id) // Delete shape by ID
deleteActiveShape() // Delete currently active shape
clearAll() // Delete all shapes
selectShape(id) // Select a shape
deselectShape() // Deselect current shape
getShapeById(id) // Get shape data by ID
updateShapeName(id, name) // Update shape label
// History
undo() // Undo last action
redo() // Redo last undone action
// Snapping
setSnapping({ enabled, threshold }) // Configure snapping
toggleSnapping() // Toggle snapping on/off
// Event Callbacks
onShapeCreated(callback) // Called when shape is created
onShapeUpdated(callback) // Called when shape is modified
onShapeDeleted(callback) // Called when shape is deleted
onSnapDetected(callback) // Called when snap point is detected
`
`javascript`
// Shape object structure
{
id: 'shape_1', // Unique identifier
name: 'Shape 1', // Custom label (editable)
type: 'polygon', // 'polygon' | 'circle' | 'rectangle' | 'polyline'
path: [...], // Array of {lat, lng} for polygon/polyline
center: { lat, lng }, // Center point for circle
radius: 1000, // Radius in meters for circle
bounds: { north, south, east, west }, // Bounds for rectangle
area: 50000 // Area in square meters
}
Main composable - detailed above.
Helper composable for shape styling.
`vue
`
Composable for event handling.
`vue`
Edge snapping automatically snaps the cursor to edges of other shapes while drawing.
``
┌─────────────────┐
│ │
│ Shape 1 │
│ │
└────────●────────┘ ← Snap point
│
│ (snap indicator)
│
○ ← Mouse cursor
1. When the mouse approaches an edge within threshold distance, snap activates
2. The point is automatically projected onto the edge
3. Visual indicator provides feedback to the user
`vue
🎯 Snap active
`
| Shortcut | Action |
|----------|--------|
| Ctrl + Z | Undo |Ctrl + Y
| / Ctrl + Shift + Z | Redo |Delete
| / Backspace | Delete selected shape |Escape
| | Cancel active drawing |Enter
| | Complete polygon/polyline drawing |
`vue
Total shapes: {{ shapes.length }}
`
`vue
Total Area: {{ (totalArea / 1000000).toFixed(2) }} km² Selected Area: {{ (selectedArea / 1000000).toFixed(4) }} km²
`
`vue
v-for="shape in shapes"
:key="shape.id"
class="shape-item"
>
{{ shape.name }}
{{ shape.type }}
Browser Support
- Chrome 80+
- Firefox 75+
- Safari 14+
- Edge 80+
License
MIT
Contributing
1. Fork the repository
2. Create a feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'feat: add amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)