Google maps component for vue with 2-way data binding

Last update: May 25, 2022

vue-google-maps

Demo:

Demo in production

Showcase with a lot of features

Presentation

If you want to write google map this way :

<map
  :center="{lat:10, lng:10}"
  :map-type-id="terrain"
  :zoom="7"
>map>

Or use the power of Vue.js within a google map like this:

<template>
  <map
    :center="center"
    :zoom="7"
  >
    <marker 
      v-for="m in markers"
      :position.sync="m.position"
      :clickable="true"
      :draggable="true"
      @g-click="center=m.position"
    >marker>
  map>
template>

<script>
  import {load, Map, Marker} from 'vue-google-maps'
  
  load('YOUR_API_TOKEN','OPTIONAL VERSION NUMBER')
  
  export default {
    data () {
      return {
        center: {lat: 10.0, lng: 10.0},
        markers: [{
          position: {lat: 10.0, lng: 10.0}
        }, {
          position: {lat: 11.0, lng: 11.0}
        }]
      }
    }
  }
script>

Example Project

You can see an project example here.

It uses webpack and vue-loader and was "forked" from the vue-loader-example project

Installation

With npm (Recommended)

npm install vue-google-maps

You can append --save or --save-dev to add it to your depency (if yor project also uses npm)

Manually

Just download the index.js file on the root directory of this repository

Basic usage

Reference vue-google-maps into your project

If you are using a cool bundler (recommended) you can just do :

import {load, Map, Marker} from 'vue-google-maps'

Or if you prefer the older ES5 syntax:

const VueGoogleMap = require('vue-google-maps')

Standalone / CDN

If you are not using any bundler (and you should feel bad). You can just reference the file in a script tag. The library will be available in a global object called VueGoogleMap. However you will need to include Vue and Lodash beforehand:

<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.17/vue.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js">script>
<script src="dist/vue-google-maps.js">script>

head>
<body>

<google-map style="width: 100%; height: 100%; position: absolute; left:0; top:0"
    :center="{lat: 1.38, lng: 103.8}"
    :zoom="12"
>

google-map>

<script>
VueGoogleMap.load({
    'key': 'YOUR_API_KEY',
})
Vue.component('google-map', VueGoogleMap.Map);
new Vue({
    el: 'body',
});

script>

body>

Set your api key

To enable any vue-google-maps components you need to set your api token:

load({
  key: 'YOUR_API_TOKEN',
  v: '3.24',                // Google Maps API version
  // libraries: 'places',   // If you want to use places input
})
// OR (depending on how you refereced it)
VueGoogleMap.load({ ... })

The parameters are passed in the query string to the Google Maps API, e.g. to set the version, libraries, or for localisation.

Full documentation

Note on events

All events are prefixed with g-. Example : g-click so it does not interfere with DOM events.

Documentation is up to date: take a look at the wiki

Sponsor

This component is sponsored by PapayaPods. Feel free to check out vue-google-maps in production !!

GitHub

https://github.com/GuillaumeLeclerc/vue-google-maps
Comments
  • 1. Marker icons?

    Just wanted to double-check the functionality of this/how it works. Right now I've got:

    markers: [{ position: {lat: 41.585095, lng: -93.624523}, ifw:false, content:'', icon: { path: google.maps.SymbolPath.CIRCLE } }]

    The marker shows up on the map if I leave off the icon argument, but when I include it, I get google is not defined. I've also tried using https://github.com/ethanclevenger91/fontawesome-markers, which has worked for me in the past using the vanilla maps library, so it ends up looking like this:

    path: fontawesome.markers.EXCLAMATION_CIRCLE

    And in that case, I just get the regular old icon. Any advice on this?

    Reviewed by ethanclevenger91 at 2016-03-04 23:32
  • 2. Fit bounds

    Hello, How can i center the map when dealing with bunch of marker? i.e I have 3 markers how can i center the map and set the right bounds for them? I can't call map.fitBounds(), 'coz i don't have access to map object itself.

    Reviewed by dominikveils at 2016-04-04 15:58
  • 3. Create superclass for map components

    Hi! It's this PR again.

    The notable changes are as follows:

    1. A Vue plugin (DeferredReady) which creates a new hook called deferredReady, and a mixin called DeferredReadyMixin. DeferredReadyMixin is a general-purpose mixin intended for components that depend on certain resources from their parents, including resources that may require asynchronous loading (hence Promises). Classes that contain DeferredReadyMixin will fire deferredReady at some point after ready. If there are no ancestors containing DeferredReadyMixin then it will fire immediately after ready. Otherwise, classes will wait for ancestors' deferredReady to complete before firing. If deferredReady returns a Promise, then descendent components' deferredReady will only fire after the promise resolves.
    2. A MapComponent class that contains DeferredReadyMixin. This class handles signalling between the map and its components. It guarantees that when deferredReady on a subclass is called, a new property $map has been created on the vm which points to the Google Maps object.

    Example: the Map component is a top-level DeferredReadyMixin. deferredReady is fired immediately after ready. However, it returns a promise that waits for the Google Maps API to be fully loaded. Therefore, in the descendents none of the deferredReady are fired until the Google Maps API has been loaded, because they wait for the promise to be resolved.

    Similarly, in the Marker class, deferredReady creates an instance of google.maps.Marker. If the marker has a descendent InfoWindow, the info window's deferredReady is called only after the Google API's Marker instance has been created; so the info window has no problem attaching itself to the marker.

    This way, we can eliminate most signals in the component classes.

    Reviewed by xkjyeah at 2016-03-25 15:31
  • 4. Issues when combined with (global) mixins

    I'm trying to include this component into my project, but every time I load the / a map I get an error:

    Uncaught TypeError: Cannot read property 'accessToken' of undefined

    Where accessToken is defined in data object from my global mixins file (where I basically have a simple vue resource http call function I use throughout my project).

    I checked to see if I could get a map working in a different environment (eg: without mixins) and this seems to not be an issue at all.

    Is the advice to re-factor my mixins - to not use that at all, or is something else going on?

    code snippets: http://pastebin.com/s0aLxXAV

    Reviewed by jvv at 2016-03-22 15:44
  • 5. Adds Circle

    Hey,

    I hope I have done this properly. I've added circles.

    Please feel free to let me know if the code isn't perfect. I am still learning Vue.

    npm run build

    <map :center.sync="center" :zoom.sync="zoom">
    
            <circle
                :center="" // object {lat: 52.36901277156986, lng: -2.7150990068912506}, required, twoWay
                :radius.sync="" // number, default: 1000 (metres), twoWay
                :clickable="" //bool
                :draggable="" //bool
                :editable="" //bool
                :fill-color="" // string
                :fill-opacity="" // number
                :stroke-color="" //string
                :stroke-opacity="" // number
                :stroke-position="" // string - CENTER, INSIDE, OUTSIDE
                :stroke-weight="" // number
                :visible="" // bool
                :z-index="" // string
            >
            </circle>
    
    </map>
    
    Reviewed by t2thec at 2016-01-14 16:18
  • 6. VueJs 2 compatibility

    All components are updated to be compatible with VueJs 2.0 All Properties with twoWay configuration are merged in a single object Objects to represent this components was created and com be used to create then

    Reviewed by khenam at 2016-10-30 22:54
  • 7. Issue with Cluster and Markers update

    Hi !

    So I have a map with markers on it. I can paginate through the markers and they are added/removed from the map. It works perfectly until I tried to add the cluster...

    It looks like there's something wrong on the update of the markers, the Google Maps SDK is throwing this error :

    screenshot from 2016-01-21 14 21 51

    Here is the interesting part of the code of my vue file :

    https://gist.github.com/smartpierre/b69426dcd9098c803ab3

    In setMarkers, I compare the old markers with the new ones, I remove the old markers that are not in the new list and add the new that are missing (so it does not make all the markers DROP each time I refresh the map)

    If you have any idea, I'll take it. Maybe I'm doing something wrong ? In the meantime I'll do without the cluster :D

    Reviewed by smartpierre at 2016-01-21 13:25
  • 8. Map not showing

    When following the example in the readme I can't get my map to load. The map component is resolved to a <div class="vue-map-container"> and a <div class="vue-map"> and the code from the Google maps API is loaded but the map never shows, only a light brown square that fills the space.

    Here is my code:

    <template>
    <map
      :center="{lat:10, lng:10}"
      :map-type-id="terrain"
      :zoom="7"
    ></map>
    </template>
    
    <script>
    import {load, Map} from 'vue-google-maps'
    
    load('MY_KEY', '3.24');
    
    export default {
      components: {
        Map
      }
    }
    </script>
    

    I'm using vue-google-maps version 0.1.16 and Vue version 1.0.20. I use Vueify with Browserify in gulp to compile .vue components. Any ideas what can be wrong? I suppose it has something to do with the bundling.

    Reviewed by perkola at 2016-03-30 13:00
  • 9. [Poll] API change proposition

    I have a (slightly breaking) API change to propose to the community. Please tell me what you think about it.

    Instead of having Vue as a dependency (that leads to some problem with duplicate instance of Vue some times and two build for vue-google-maps (one for bundlers and the other for "normal" JavaScript). We might want to turn it into a Vue plugin. Here are the changes for users:

    before

    //ES6
    import {load} from `vue-google-maps`
    load('token', ['places'])
    //ES5
    VueGoogleMaps.load('token', ['places'])
    

    after

    //ES6
    import Vue from 'vue'
    import VueGoogleMaps from `vue-google-maps`
    //ES5 + ES6 
    Vue.use(VueGoogleMaps, {
      token: 'token',
      libraries: ['places']
    })
    

    On the other hand, I don't think there would be any changes in the the way we use components.

    This way we could remove all dependencies of vue-google-maps and we would be sure there is no duplication of vue. We could also think about globally registered components.

    What do you think ?

    Reviewed by GuillaumeLeclerc at 2016-04-10 10:21
  • 10. How to close info windows when clicked on a new marker?

    Is there any way to close all info windows so i only have the one i clicked on open?.

    So if i click on a marker the info window open but close the other?

    Reviewed by FWSimon at 2016-04-08 09:22
  • 11. Standardize how MapComponents are created

    In this PR, every component inherits from MapComponent (MapComponent.extend({...})).

    MapComponent provides a $mapPromise and a $map property. In the ready() handler of MapComponent, it dispatches the register-component event. When this event is received by the map container, it emits the map-ready event on the child. MapComponent responds to the map-ready event by resolving $mapPromise.

    Components that require a google.maps.Map object should wait on $mapPromise before initializing their google maps components.

    By extending MapComponent, a user can create new components (e.g. HeatMaps, Overlays). An example (Ground Overlay) has been provided. This example is not idiomatic -- it does not use eventBinding or propBinding, but suffices to demonstrate how child components can get access to their Google Map object via vm.$map.

    In addition to $map, components' *Object properties have been renamed to $*Object in the more idiomatic Vue way to avoid conflicts with data properties of the same name.

    Reviewed by xkjyeah at 2016-03-05 06:23
  • 12. Overlaying an Image Map Type

    Hi, I'm trying to use image tiles to overlay an image that represents the interior of a building onto the map. Is there any way I can achieve that with Vue-google-maps? https://developers.google.com/maps/documentation/javascript/examples/maptype-image-overlay#maps_maptype_image_overlay-javascript Thanks, Arash

    Reviewed by Arash-sad at 2021-11-22 23:41
  • 13. Open infowindow on polyline

    I'm trying to open an infowindow on the polylines position, i've tried to open it on the mouse position but it opens in the middle of the polyline shape.

    Here's my code:

    Vue

    <template>
      <div class="ilfind__map">
        <!-- <div class="ilfind__map-buttons">
            <button
                v-show="locations.length > 1"
                @click="searchOpen = !searchOpen;categoriesOpen = false;search = ''"
            >Søg</button>
            v-show="searchOpen"
        </div> -->
        <div class="ilfind__map-search">
          <div class="ilfind__map-search-input">
    				<!-- Søgefelt som binder sig til funktionen search via v-model  -->
            <input type="search" placeholder="Søg" v-model="search">
          </div>
    			<!-- Div som indeholder alle søge resultater, vises kun hvis der er nogle -->
          <div class="ilfind__map-search-results" v-show="searchResults.length > 0">
    				<!-- Looper igennem alle søgeresultater -->
            <a
              v-for="result in searchResults"
              :key="result.ID"
              :href="result.permalink"
            >{{result.coordinate_sets[0].texts.danish.title}}</a>
          </div>
        </div>
    
    		<!-- Viser menu hvor man kan vælge sprog -->
        <div
          class="ilfind__map-choose-language"
          v-show="showLanguageChooser"
        >
          <h2>Vælg ønsket sprog</h2>
          <div>
    				<!-- Looper over de sprog man kan vælge imellem og viser dem -->
            <div
              class="ilfind__map-choose-language-button"
              v-for="(languageName, languageIndex) in languages"
              :key="languageIndex"
              @click="chooseLangauge(languageIndex)"
            >
    					<!-- Billedet er binded til alle flag som tilhøre de sprog man kan vælge imellem -->
              <img :src="languageImage(languageIndex)" :alt="languageName">
            </div>
          </div>
        </div>
    
    		<!-- Viser nuværende sprog -->
        <div
          v-show="language"
          class="ilfind__map-current-language"
          @click="showLanguageChooser = !showLanguageChooser"
        >
          <img :src="languageImage(language)" :alt="language">
        </div>
    
        <GmapMap ref="map" :center="center" :zoom="zoom" map-type-id="hybrid">
    
    			<!-- Laver info vindue som vises når man klikker på en lokation, den modtager objekterne infoOptions, infoWindowPos og infoWinOpen. Viser infoContent som html -->
          <GmapInfoWindow
            :options="infoOptions"
            :position="infoWindowPos"
            :opened="infoWinOpen"
            @closeclick="infoWinOpen=false">
    
            <div v-html="infoContent"></div>
          </GmapInfoWindow>
    			<!-- Looper over alle lokationer som brugeren gerne vil se -->
          <span v-for="(location, index) in filteredLocations" :key="index">
            <span
              v-for="(coordinate_set, coordinate_set_index) in location.coordinate_sets"
              :key="coordinate_set_index"
            >
              <div>{{ coordinate_set }}</div>
    					<!-- Looper over alle markøre og placerer dem på kortet, og bliver binded til de tilhørende ikoner -->
              <GmapMarker
                v-for="(marker, marker_index) in coordinate_set.drawings.markers"
                :key="index + '_' + coordinate_set_index + '_marker_' + marker_index"
                :position="marker"
                @click="toggleInfoWindowNy(marker, index, coordinate_set_index, '_marker_'+ marker_index)"
                :icon="{url: changeMarkerIcon(location.categories.map(category => category.name)), scaledSize:{width: 50,height: 50}}"
              ></GmapMarker>
    
    					<!-- Looper over alle polygoner og placerer dem på kortet -->
              <GmapPolygon
                v-for="(polygon, polygon_index) in coordinate_set.drawings.polygons"
                :key="index + '_' + coordinate_set_index + '_polygon_' + polygon_index"
                :paths="polygon"
                @click="toggleInfoWindow($event, index, coordinate_set_index, '_polygon_'+ marker_index)"
                :options="strokeOptions(coordinate_set.drawings_options.polygons[polygon_index].color)"
              ></GmapPolygon>
    					<!-- Looper over alle cirkler og placerer dem på kortet -->
              <GmapCircle
                v-for="(circle, circle_index) in coordinate_set.drawings.circles"
                :key="index + '_' + coordinate_set_index + '_circle_' + circle_index"
                :radius="circle.radius"
                :center="circle.center"
                @click="toggleInfoWindow($event, index, coordinate_set_index, '_circle_'+ marker_index)"
                :options="strokeOptions(coordinate_set.drawings_options.circles[circle_index].color)"
              ></GmapCircle>
    					<!-- Looper over alle polylines (stier) og placerer dem på kortet -->
              <GmapPolyline
                v-for="(polyline, polyline_index) in coordinate_set.drawings.polylines"
                :key="index + '_' + coordinate_set_index + '_polyline_' + polyline_index"
                :path="polyline"
                @click="toggleInfoWindowPolyline($event, polyline, index, coordinate_set_index, '_polyline_'+ index)"
                :options="strokeOptions(coordinate_set.drawings_options.polylines[polyline_index].color)"
              ></GmapPolyline>
    
    					<!-- Looper over alle rektangler på placerer dem på kortet -->
              <GmapRectangle
                v-for="(rectangle, rectangle_index) in coordinate_set.drawings.rectangles"
                :key="index + '_' + coordinate_set_index + '_rectangle_' + rectangle_index"
                :bounds="rectangle"
                @click="toggleInfoWindow($event, index, coordinate_set_index, '_rectangle_'+ marker_index)"
                :options="strokeOptions(coordinate_set.drawings_options.rectangles[rectangle_index].color )"
              ></GmapRectangle>
            </span>
          </span>
        </GmapMap>
        <div class="ilfind__map-infowindow">
          <h2 class="catH2">Kategorier</h2>
          <div class="flex">
    				<!-- Looper over alle kategorier -->
            <div
            class="catList"
            v-for="category in categories"
            :key="category.term_id"
          >
    				<!-- Viser alle kategorier med tilhørende markør og checkbox så man kan vælge / fravælge kategorier -->
            <label :form="`category${category.term_id}`">
              <input class="checkbox"
                type="checkbox"
                :id="`category${category.term_id}`"
                :value="category.term_id"
                v-model="selectedCategories"
              >
              <img class="markerCheck" :src="'../wp-content/plugins/ilfind-master/icon/icons/nyny/' + category.name.toLowerCase().replace('/', '-') + '.svg'" alt="">
              {{ category.name }}
            </label>
          </div>
          </div>
        </div>
      </div>
    </template>
    
    Reviewed by Mar10n at 2020-11-04 12:53
  • 14. How to add Cluster to Vue-google-maps?

    Like title. I try to add Cluster to my vue2-goole-map, now i'm already install @google/markerclusterer, but I can't import to my project. Dose anyone can tall me, thx plz.

    I want function like this.

    Reviewed by RexHung0302 at 2019-07-03 10:03
  • 15. Clusters exponentially multiply after dramatic marker reduction

    I have found that my marker clusters go from 30 clusters to 1700 cluster for a split second, when I dramatically change number of markers.

    So when I am displaying about 162 markers, it creates about 30 cluster and then when I click on one of the markers to zoom in and view just the one. The number of clusters goes to 1700 and creates a strange shadow-like illusion, before they disappear.

    Has anyone found the same issue?

    cluster-shadows

    Reviewed by jousi592 at 2018-04-04 20:27
Related tags
A wrapper component for consuming Google Maps API built on top of VueJs v2.

A wrapper component for consuming Google Maps API built on top of VueJs v2. Fork of the popular vue-google-maps plugin.

Jun 30, 2022
Integrate Google Maps in your Vue application
Integrate Google Maps in your Vue application

vue-googlemaps Integrate Google Maps in your Vue application in a "Vue-way". This library is Work In Progress. More components will be available in th

Jun 27, 2022
A lightweight Google Maps plugin for Vue
A lightweight Google Maps plugin for Vue

x5-gmaps (Live Demo) This is a lightweight Google Maps plugin for Vue. Samples/examples/tutorials Tutorial creating a COVID Heatmap Address Autocomple

Apr 22, 2022
A set of composable components for easy use of Google Maps in your Vue 3 projects.

A set of composable components for easy use of Google Maps in your Vue 3 projects.

Jun 24, 2022
Reactive Vue 3 components for Google maps

Vue 3 Google maps Components Set of mostly used Google Maps components for Vue.js. Why this library exists? We heavily use Google Maps in our projects

Jul 3, 2022
Using Google Maps with Vue.js

stores-map Project setup npm install Compiles and hot-reloads for development npm run serve Compiles and minifies for production npm run build Run

Apr 22, 2022
📍 Vue composable for Google Maps Places Autocomplete.

v-use-places-autocomplete ?? Vue composable for Google Maps Places Autocomplete. Though not a fork, this composable is fully inspired by react-google-

Jun 28, 2022
Yandex Maps Component for VueJS
Yandex Maps Component for VueJS

vue-yandex-maps Documentation: RU, EN Contributors ✨ Thanks goes to these wonderful people (emoji key): Wormaster ?? Nikitenko Andrey ?? Kamil ?? Alex

Jun 24, 2022
Vue 2 components for Leaflet maps
Vue 2 components for Leaflet maps

Vue2Leaflet Vue2Leaflet is a JavaScript library for the Vue framework that wraps Leaflet making it easy to create reactive maps. How to install npm in

Jun 22, 2022
Integrate Azure Maps in your Vue application

Vue Azure Maps Vue Azure Maps is a library for Vue.js that integrates Azure Maps. It offers several Vue components out of the box and supports custom

May 19, 2022
Annotate maps and generate GeoJSON in Kirby by drawing markers, paths and shapes
Annotate maps and generate GeoJSON in Kirby by drawing markers, paths and shapes

Kirby Mapnotator Annotate maps and generate GeoJSON in Kirby by drawing markers, paths and shapes. Overview This plugin is completely free and publish

Jun 5, 2022
A quick way to start a web map application with Vue.js using MapLibre GL JS.
A quick way to start a web map application with Vue.js using MapLibre GL JS.

Vue.js map using MapLibre GL JS A quick way to start a web map application with Vue.js using MapLibre GL JS. A simple fullscreen map application is us

May 28, 2022
vue google map custom marker component
vue google map custom marker component

vue2-gmap-custom-marker This component allows you to display custom HTML content on the map using Overlay. This component is an adaptation of the Goog

May 17, 2022
a simple component to generate an static google map
a simple component to generate an static google map

vue-static-map a simple component to generate an static google map Google Documentation Demo SandBox JSBin example Requirements Vue 2.X.X Usage Instal

May 17, 2022
🔍 Google Place Autocomplete Search - Renderless component + Wrappers for Bulma, Bootstrap and more...
🔍 Google Place Autocomplete Search - Renderless component + Wrappers for Bulma, Bootstrap and more...

vue-custom-google-autocomplete Installation You need Vue.js version 2.0+ and an Google PLACE API key. This plugin is a renderless component. It comes

Apr 11, 2022
Traveliko - Travel with Friends ~ Web application prepared using Google Street View API that allows you to real-time travel with your friends in the same place in street view mode.
Traveliko - Travel with Friends ~ Web application prepared using Google Street View API that allows you to real-time travel with your friends in the same place in street view mode.

Traveliko - Travel with Friends! You can create a room with your friends and travel in street view mode and navigate the map. The application basicall

Mar 3, 2022
A Vue JS component for displaying dynamic data on a world map.

This is no longer being maintained, please do not open issues or PRs. Vue World Map A Vue JS Component for displaying dynamic data on a world map. Map

May 10, 2022
Render every single road in any city, The data is fetched from OpenStreetMap using overpass API.
Render every single road in any city, The data is fetched from OpenStreetMap using overpass API.

Render every single road in any city, The data is fetched from OpenStreetMap using overpass API.

Jun 28, 2022
A Vue.js component for Mapbox GL JS

Mapbox GL JS Vue.js A simple lightweight (9kb/3kb gzipped) Mapbox GL JS Vue component. Demo Installation Setup Props Events Plugins Popups Development

Jul 5, 2022