Map
Interactive map component powered by Google Maps with marker management, geolocation support, and customizable center/zoom controls.
Overview
VOvMap provides a Vue 3 wrapper around the Google Maps JavaScript API with advanced features like automatic geolocation, marker management, and real-time event handling. The component supports marker creation, deletion, info windows, and automatic centering based on user location.
Features:
- Google Maps integration with custom styling
- Automatic geolocation with optional auto-centering
- Marker management (add, remove, retrieve)
- Advanced markers with info windows
- Customizable center, zoom, and marker colors
- Event emission for map interactions (click, zoom, center, locate)
- Full TypeScript support
- Responsive sizing with custom width/height
Dependencies
pnpm add vue3-google-map- vue3-google-map: Vue 3 Google Maps wrapper with Advanced Markers support
Configuration
Set your Google Maps API key in the environment .env variables:
VITE_GOOGLE_MAP_API_KEY=your_api_key_hereWARNING
If publishing API key to repo and when using in production, make sure that domain restrictions are applied.
Usage
Examples
<template>
<v-defaults-provider :defaults="{ VBtn: { class: 'ma-1' } }">
<v-container fluid>
<v-row>
<v-col cols="12" lg="6" class="map-column">
<v-ov-map
ref="map"
width="100%"
height="400px"
:zoom
:center
:markers
@marked="markersChanged"
@centered="centerChanged"
@zoomed="zoomChanged"
@located="locationChanged"
@loading="loadingChanged"
@clicked="clickChanged"
/>
</v-col>
<v-col cols="12" lg="6">
Zoom: {{ zoom }}
<br />
<v-btn @click="zoom++">Zoom in</v-btn>
<v-btn @click="zoom--">Zoom out</v-btn>
<hr class="mt-4 mb-4" />
Location: {{ location }}
<br />
<v-btn @click="center = { lat: 0, lng: 0 }">Center</v-btn>
<v-btn
@click="
center = {
lat: map?.location.lat ?? center.lat,
lng: map?.location.lng ?? center.lng,
}
"
>Current</v-btn
>
<v-btn @click="center = { lat: 40.7128, lng: -74.006 }">New York</v-btn>
<v-btn @click="center = { lat: 34.0522, lng: -118.2437 }">Los Angeles</v-btn>
<hr class="mt-4 mb-4" />
In LA:
<br />
<v-btn @click="markerAtLA(true)">Add marker</v-btn>
<v-btn @click="markerAtLA(false)">Remove marker</v-btn>
</v-col>
</v-row>
</v-container>
</v-defaults-provider>
</template>
<script setup lang="ts">
definePage({
meta: {
visibility: 'with-role',
access: 'with-role',
roles: ['developer'],
},
})
const map = ref<VOvMapInstance | null>(null)
const center = ref({ lat: 34.0522, lng: -118.2437 })
const location = computed(() => `lat: ${center.value.lat}, lng: ${center.value.lng}`)
const zoom = ref(10)
const markers = ref<TOvMapMarker[]>([
{
lat: 40.689253,
lng: -74.046689,
title: 'Statue of Liberty',
color: 'blue',
info: 'The <strong>Statue of Liberty</strong> is a colossal neoclassical sculpture on Liberty Island in New York Harbor in New York City, in the United States.',
},
{ lat: 40.748817, lng: -73.985428, title: 'Empire State Building', color: 'red' },
{ lat: 40.712776, lng: -74.005974, title: 'One World Trade Center', color: 'green' },
])
function centerChanged(newCenter: { lat: number; lng: number }) {
console.log('centerChanged', newCenter)
}
function zoomChanged(newZoom: number) {
console.log('zoomChanged', newZoom)
zoom.value = newZoom
}
function locationChanged(newLocation: { lat: number; lng: number }) {
console.log('locationChanged', newLocation)
}
function markersChanged(newMarkers: TOvMapMarker[]) {
console.log('markersChanged', newMarkers)
}
function loadingChanged(newLoading: boolean) {
console.log('loadingChanged', newLoading)
}
function clickChanged(newLocation: { lat: number; lng: number }) {
console.log('clickChanged', newLocation)
}
function markerAtLA(isSet: boolean) {
if (!map.value) return
center.value = { lat: 34.0522, lng: -118.2437 }
const laMarker: TOvMapMarker = {
lat: 34.0522,
lng: -118.2437,
title: 'Los Angeles',
color: 'orange',
}
if (isSet) {
map.value.setMarkers([laMarker])
} else {
map.value.delMarkers([laMarker])
}
}
</script>API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
center | { lat: number; lng: number } | { lat: 0, lng: 0 } | Map center coordinates |
zoom | number | 10 | Initial zoom level (1-21) |
markers | TOvMapMarker[] | [] | Array of markers to display on the map |
autoCenter | boolean | true | Auto-center map on detected location |
autoLocation | boolean | true | Automatically detect user's current location |
width | string | '100%' | Container width (CSS value) |
height | string | '100%' | Container height (CSS value) |
Events
| Event | Payload | Description |
|---|---|---|
centered | { lat: number; lng: number } | Emitted when map center changes |
zoomed | number | Emitted when zoom level changes |
located | { lat: number; lng: number } | Emitted when user location is detected |
marked | TOvMapMarker[] | Emitted when markers are added, removed, or updated |
clicked | { lat: number; lng: number } | Emitted when map is clicked with coordinates |
loading | boolean | Emitted when geolocation loading state changes |
Exposed Methods and Properties
| Name | Type | Description |
|---|---|---|
location | { lat: number; lng: number } | Current user's detected location |
loading | boolean | Geolocation loading state |
getMarkers() | () => TOvMapMarker[] | Returns current array of markers |
setMarkers(markers) | (markers: TOvMapMarker[]) => void | Add or update markers (merges with existing) |
delMarkers(markers) | (markers: TOvMapMarker[]) => void | Remove markers by matching coordinates |
Marker Type
interface TOvMapMarker {
lat: number // Latitude coordinate
lng: number // Longitude coordinate
title?: string // Marker title (displayed on hover)
color?: string // Pin background color (CSS color name or hex)
info?: string // HTML content displayed in info window on click
}Component Instance Type
interface VOvMapInstance {
location: { lat: number; lng: number }
getMarkers: () => TOvMapMarker[]
setMarkers: (markers: TOvMapMarker[]) => void
delMarkers: (markers: TOvMapMarker[]) => void
loading: boolean
}Behavior
Geolocation
When autoLocation is true, the component automatically requests the user's current location on mount using the Geolocation API. If successful, it emits the located event and optionally centers the map if autoCenter is true. If autoLocation is false, the map displays at the specified center coordinates.
Marker Management
- setMarkers: Adds new markers or updates existing ones. Deduplicates markers with identical coordinates.
- delMarkers: Removes markers matching the provided latitude/longitude coordinates.
- getMarkers: Returns the current array of all markers.
Marker Info Windows
Markers can display clickable info windows containing HTML content via the info property. The HTML content is rendered directly, allowing for rich formatting.
Marker Colors
Markers use Advanced Markers with customizable pin colors. Common color values: blue, red, green, purple, yellow, etc.
Notes
- The map requires a valid Google Maps API key with Maps JavaScript API and Geolocation API enabled
- Geolocation requests require HTTPS in production environments
- Marker info windows display on marker click
- The component uses ResizeObserver patterns internally for responsive behavior
- Map interactions (pan, zoom, click) are properly debounced for performance
- Marker deduplication uses latitude/longitude values as unique identifiers