Skip to content

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 ​

bash
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:

ini
VITE_GOOGLE_MAP_API_KEY=your_api_key_here

WARNING

If publishing API key to repo and when using in production, make sure that domain restrictions are applied.

Usage ​

Examples
vue
<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 ​

PropTypeDefaultDescription
center{ lat: number; lng: number }{ lat: 0, lng: 0 }Map center coordinates
zoomnumber10Initial zoom level (1-21)
markersTOvMapMarker[][]Array of markers to display on the map
autoCenterbooleantrueAuto-center map on detected location
autoLocationbooleantrueAutomatically detect user's current location
widthstring'100%'Container width (CSS value)
heightstring'100%'Container height (CSS value)

Events ​

EventPayloadDescription
centered{ lat: number; lng: number }Emitted when map center changes
zoomednumberEmitted when zoom level changes
located{ lat: number; lng: number }Emitted when user location is detected
markedTOvMapMarker[]Emitted when markers are added, removed, or updated
clicked{ lat: number; lng: number }Emitted when map is clicked with coordinates
loadingbooleanEmitted when geolocation loading state changes

Exposed Methods and Properties ​

NameTypeDescription
location{ lat: number; lng: number }Current user's detected location
loadingbooleanGeolocation loading state
getMarkers()() => TOvMapMarker[]Returns current array of markers
setMarkers(markers)(markers: TOvMapMarker[]) => voidAdd or update markers (merges with existing)
delMarkers(markers)(markers: TOvMapMarker[]) => voidRemove markers by matching coordinates

Marker Type ​

typescript
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 ​

typescript
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