drawing-manager
Description
This component helps you to drawing shapes on over the map.
For more information read the Google Maps documentation for drawing manager.
It is exported with the name GmapDrawingManager.
Variables
This component save the original drawing manager object provided by Google Maps in a property
called $drawingManagerObject, as the example below.
  this.$drawingManagerObject = new google.maps.drawing.DrawingManager(...);
Source code
Click to se the source code of 
drawing-manager.vue component<template>
  <div>
    <slot
      v-bind:setDrawingMode="setDrawingMode"
      v-bind:deleteSelection="deleteSelection"
    />
  </div>
</template>
<script>
import MapElementMixin from '../mixins/map-element';
import { drawingManagerMappedProps } from '../utils/mapped-props-by-map-element';
import { bindProps, getPropsValues } from '../utils/helpers';
export default {
  mixins: [MapElementMixin],
  props: {
    circleOptions: {
      type: Object,
    },
    markerOptions: {
      type: Object,
    },
    polygonOptions: {
      type: Object,
    },
    polylineOptions: {
      type: Object,
    },
    rectangleOptions: {
      type: Object,
    },
    position: {
      type: String,
    },
    shapes: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      selectedShape: null,
      drawingModes: [],
      options: {
        drawingMode: null,
        drawingControl: true,
        drawingControlOptions: {},
      },
    };
  },
  methods: {
    setDrawingMode(mode) {
      this.$drawingManagerObject.setDrawingMode(mode);
    },
    drawAll() {
      const shapeType = {
        circle: google.maps.Circle,
        marker: google.maps.Marker,
        polygon: google.maps.Polygon,
        polyline: google.maps.Polyline,
        rectangle: google.maps.Rectangle,
      };
      const self = this;
      this.shapes.forEach((shape) => {
        const shapeDrawing = new shapeType[shape.type](shape.overlay);
        shapeDrawing.setMap(this.$map);
        shape.overlay = shapeDrawing;
        google.maps.event.addListener(shapeDrawing, 'click', () => {
          self.setSelection(shape);
        });
      });
    },
    clearAll() {
      this.clearSelection();
      this.shapes.forEach((shape) => {
        shape.overlay.setMap(null);
      });
    },
    clearSelection() {
      if (this.selectedShape) {
        this.selectedShape.overlay.set('fillColor', '#777');
        this.selectedShape.overlay.set('strokeColor', '#999');
        this.selectedShape.overlay.setEditable(false);
        this.selectedShape.overlay.setDraggable(false);
        this.selectedShape = null;
      }
    },
    setSelection(shape) {
      this.clearSelection();
      this.selectedShape = shape;
      shape.overlay.setEditable(true);
      shape.overlay.setDraggable(true);
      this.selectedShape.overlay.set('fillColor', '#555');
      this.selectedShape.overlay.set('strokeColor', '#777');
    },
    deleteSelection() {
      if (this.selectedShape) {
        this.selectedShape.overlay.setMap(null);
        const index = this.shapes.indexOf(this.selectedShape);
        if (index > -1) {
          this.shapes.splice(index, 1);
        }
      }
    },
    addShape(shape) {
      this.setDrawingMode(null);
      this.shapes.push(shape);
      const self = this;
      google.maps.event.addListener(shape.overlay, 'click', () => {
        self.setSelection(shape);
      });
      google.maps.event.addListener(shape.overlay, 'rightclick', () => {
        self.deleteSelection();
      });
      this.setSelection(shape);
    },
  },
  watch: {
    position(position) {
      if (this.$drawingManagerObject) {
        const drawingControlOptions = {
          position:
            position && google.maps.ControlPosition[position]
              ? google.maps.ControlPosition[position]
              : google.maps.ControlPosition.TOP_LEFT,
          drawingModes: this.drawingModes,
        };
        this.$drawingManagerObject.setOptions({ drawingControlOptions });
      }
    },
    circleOptions(circleOptions) {
      if (this.$drawingManagerObject) {
        this.$drawingManagerObject.setOptions({ circleOptions });
      }
    },
    markerOptions(markerOptions) {
      if (this.$drawingManagerObject) {
        this.$drawingManagerObject.setOptions({ markerOptions });
      }
    },
    polygonOptions(polygonOptions) {
      if (this.$drawingManagerObject) {
        this.$drawingManagerObject.setOptions({ polygonOptions });
      }
    },
    polylineOptions(polylineOptions) {
      if (this.$drawingManagerObject) {
        this.$drawingManagerObject.setOptions({ polylineOptions });
      }
    },
    rectangleOptions(rectangleOptions) {
      if (this.$drawingManagerObject) {
        this.$drawingManagerObject.setOptions({ rectangleOptions });
      }
    },
  },
  provide() {
    // Infowindow needs this to be immediately available
    const promise = await this.$mapPromise
      .then((map) => {
        this.$map = map;
        // Initialize the maps with the given options
        const initialOptions = {
          ...this.options,
          map,
          ...getPropsValues(this, drawingManagerMappedProps),
        };
        const { options: extraOptions, ...finalOptions } = initialOptions;
        this.drawingModes = Object.keys(finalOptions).reduce((modes, opt) => {
          const val = opt.split('Options');
          if (val.length > 1) {
            modes.push(val[0]);
          }
          return modes;
        }, []);
        const position =
          this.position && google.maps.ControlPosition[this.position]
            ? google.maps.ControlPosition[this.position]
            : google.maps.ControlPosition.TOP_LEFT;
        finalOptions.drawingMode = null;
        finalOptions.drawingControl = !this.$scopedSlots.default;
        finalOptions.drawingControlOptions = {
          drawingModes: this.drawingModes,
          position,
        };
        // https://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
        this.$drawingManagerObject = new google.maps.drawing.DrawingManager(
          finalOptions
        );
        bindProps(this, this.$drawingManagerObject, drawingManagerMappedProps);
        this.$drawingManagerObject.addListener('overlaycomplete', (e) =>
          this.addShape(e)
        );
        this.$map.addListener('click', this.clearSelection);
        if (this.shapes.length) {
          this.drawAll();
        }
        return this.$drawingManagerObject;
      })
      .catch((error) => {
        throw error;
      });
    this.$drawingManagerPromise = promise;
    return { $drawingManagerPromise: promise };
  },
  destroyed() {
    this.clearAll();
    // Note: not all Google Maps components support maps
    if (this.$drawingManagerObject && this.$drawingManagerObject.setMap) {
      this.$drawingManagerObject.setMap(null);
    }
  },
};
</script>
If you need to know what are mappedProps please read the general concepts of this
application here.
Mapped Props of 
GmapDrawingManager component
export const drawingManagerMappedProps = {
  circleOptions: {
    type: Object,
    twoWay: false,
    noBind: true,
  },
  markerOptions: {
    type: Object,
    twoWay: false,
    noBind: true,
  },
  polygonOptions: {
    type: Object,
    twoWay: false,
    noBind: true,
  },
  polylineOptions: {
    type: Object,
    twoWay: false,
    noBind: true,
  },
  rectangleOptions: {
    type: Object,
    twoWay: false,
    noBind: true,
  },
};
How to use it
<template>
  <gmap-map
    ref="mapRef"
    :center="mapCenter"
    :zoom="7"
    map-type-id="roadmap"
    style="width: 100%; height: 800px"
    :options="{
        zoomControl: true,
        mapTypeControl: true,
        scaleControl: false,
        streetViewControl: false,
        rotateControl: false,
        fullscreenControl: false,
        disableDefaultUi: false,
        draggable: mapDraggable,
        draggableCursor: mapCursor
      }"
  >
    <!-- use the default slot to pass markers to it -->
    <gmap-drawing-manager></gmap-drawing-manager>
  </gmap-map>
</template>
<template>
  <gmap-map
    ref="mapRef"
    :center="mapCenter"
    :zoom="7"
    map-type-id="roadmap"
    style="width: 100%; height: 800px"
    :options="{
        zoomControl: true,
        mapTypeControl: true,
        scaleControl: false,
        streetViewControl: false,
        rotateControl: false,
        fullscreenControl: false,
        disableDefaultUi: false,
        draggable: mapDraggable,
        draggableCursor: mapCursor
      }"
  >
    <!-- or with an slot -->
    <gmap-drawing-manager>
      <template v-slot="on">
        <your-toolbar-component
          @drawingmode_changed="on.setDrawingMode($event)"
          @delete_selection="on.deleteSelection()"
          @save="mapMode='ready'"
        />
      </template>
    </gmap-drawing-manager>
  </gmap-map>
</template>
If you need to know the API of this component please read it here.
HTML examples
HTML example
<body>
  <div id="root">
    <h1>Drawing Manager Example</h1>
    <div style="width:100%; display: flex; justify-content: center;">
      <span style="width:auto" />
      {{ mapMode }} - {{ toolbarPosition }}
      <span style="width:auto" />
      <button @click="setPos">Position</button>
      <button @click="mapMode='edit'">Edit</button>
    </div>
    <br />
    <gmap-map
      ref="mapRef"
      :center="mapCenter"
      :zoom="7"
      map-type-id="roadmap"
      style="width: 100%; height: 800px"
      :options="{
          zoomControl: true,
          mapTypeControl: true,
          scaleControl: false,
          streetViewControl: false,
          rotateControl: false,
          fullscreenControl: false,
          disableDefaultUi: false,
          draggable: mapDraggable,
          draggableCursor: mapCursor
        }"
    >
      <template #visible>
        <gmap-drawing-manager
          v-if="mapMode==='edit'"
          :position="toolbarPosition"
          :rectangle-options="rectangleOptions"
          :circle-options="circleOptions"
          :polyline-options="polylineOptions"
          :shapes="shapes"
        />
      </template>
    </gmap-map>
  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gmap-vue@1.2.2/dist/gmap-vue.min.js"></script>
  <script>
    Vue.use(GmapVue, {
      load: {
        key: 'AIzaSyDf43lPdwlF98RCBsJOFNKOkoEjkwxb5Sc',
        libraries: 'places,drawing'
      }
    });
    document.addEventListener('DOMContentLoaded', function() {
      new Vue({
        el: '#root',
        data: {
          mapCenter: { lat: 4.5, lng: 99 },
          mapMode: null,
          toolbarPosition: 'TOP_CENTER',
          mapDraggable: true,
          mapCursor: null,
          shapes: [],
          rectangleOptions: {
            fillColor: '#777',
            fillOpacity: 0.4,
            strokeWeight: 2,
            strokeColor: '#999',
            draggable: false,
            editable: false,
            clickable: true
          },
          circleOptions: {
            fillColor: '#777',
            fillOpacity: 0.4,
            strokeWeight: 2,
            strokeColor: '#999',
            draggable: false,
            editable: false,
            clickable: true
          },
          polylineOptions: {
            fillColor: '#777',
            fillOpacity: 0.4,
            strokeWeight: 2,
            strokeColor: '#999',
            draggable: false,
            editable: false,
            clickable: true
          }
        },
        watch: {
          mapMode(newMode, oldMode) {
            if (newMode === 'ready') {
              if (oldMode === 'edit') {
                this.mapDraggable = true;
                this.mapCursor = null;
                return;
              }
            }
            if (newMode === 'edit') {
              this.mapDraggable = false;
              this.mapCursor = 'default';
            }
          }
        },
        mounted() {
          this.mapMode = 'ready';
        },
        methods: {
          setPos() {
            const posTypes = [
              'TOP_CENTER',
              'TOP_LEFT',
              'TOP_RIGHT',
              'LEFT_TOP',
              'RIGHT_TOP',
              'LEFT_CENTER',
              'RIGHT_CENTER',
              'LEFT_BOTTOM',
              'RIGHT_BOTTOM',
              'BOTTOM_CENTER',
              'BOTTOM_LEFT',
              'BOTTOM_RIGHT'
            ];
            this.toolbarPosition =
              posTypes[Math.floor(Math.random() * posTypes.length)];
          }
        }
      });
    });
  </script>
</body>
HML examples with slot
<body>
  <div id="root">
    <h1>Drawing Manager Example</h1>
    <div style="width:100%; display: flex; justify-content: center;">
      <span style="width: auto;" />
      {{ mapMode }}
      <span style="width: auto;" />
      <button @click="mapMode='edit'">Edit</button>
    </div>
    <br />
    <gmap-map
      ref="mapRef"
      :center="mapCenter"
      :zoom="7"
      map-type-id="roadmap"
      style="width: 100%; height: 800px; display:flex; justify-content: center; align-items: flex-start;"
      :options="{
        zoomControl: true,
        mapTypeControl: true,
        scaleControl: false,
        streetViewControl: false,
        rotateControl: false,
        fullscreenControl: false,
        disableDefaultUi: false,
        draggable: mapDraggable,
        draggableCursor: mapCursor
      }"
    >
      <template #visible>
        <gmap-drawing-manager
          v-if="mapMode==='edit'"
          :rectangle-options="rectangleOptions"
          :circle-options="circleOptions"
          :polyline-options="polylineOptions"
          :polygon-options="polygonOptions"
          :shapes="shapes"
        >
          <template v-slot="on">
            <drawing-toolbar
              @drawingmode_changed="on.setDrawingMode($event)"
              @delete_selection="on.deleteSelection()"
              @save="mapMode='ready'"
            />
          </template>
        </gmap-drawing-manager>
      </template>
    </gmap-map>
  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/gmap-vue@1.2.2/dist/gmap-vue.min.js"></script>
  <script>
    // Only for example purposes
    // In a real application you would simply create a separate component
    const toolbarTemplate =
      '<div style="background-color: #040404; display: flex; position: absolute; padding: 8px">' +
      "  <div><button @click=\"$emit('drawingmode_changed', 'rectangle')\">Rectangle</button></div>" +
      "  <div><button @click=\"$emit('drawingmode_changed', 'circle')\">Circle</button></div>" +
      "  <div><button @click=\"$emit('drawingmode_changed', 'polyline')\">Line</button></div>" +
      "  <div><button @click=\"$emit('drawingmode_changed', 'polygon')\">Polygon</button></div>" +
      "  <div><button @click=\"$emit('delete_selection')\">Delete</button></div>" +
      "  <div><button @click=\"$emit('save')\">Save</button></div>" +
      "</div>";
    Vue.use(GmapVue, {
      load: {
        key: 'AIzaSyDf43lPdwlF98RCBsJOFNKOkoEjkwxb5Sc',
        libraries: 'places,drawing'
      }
    });
    document.addEventListener('DOMContentLoaded', function() {
      new Vue({
        el: '#root',
        components: {
          drawingToolbar: {
            template: toolbarTemplate
          }
        },
        data: {
          mapCenter: { lat: 4.5, lng: 99 },
          mapMode: null,
          mapDraggable: true,
          mapCursor: null,
          shapes: [],
          rectangleOptions: {
            fillColor: '#777',
            fillOpacity: 0.4,
            strokeWeight: 2,
            strokeColor: '#999',
            draggable: false,
            editable: false,
            clickable: true
          },
          circleOptions: {
            fillColor: '#777',
            fillOpacity: 0.4,
            strokeWeight: 2,
            strokeColor: '#999',
            draggable: false,
            editable: false,
            clickable: true
          },
          polylineOptions: {
            fillColor: '#777',
            fillOpacity: 0.4,
            strokeWeight: 2,
            strokeColor: '#999',
            draggable: false,
            editable: false,
            clickable: true
          },
          polygonOptions: {
            fillColor: '#777',
            fillOpacity: 0.4,
            strokeWeight: 2,
            strokeColor: '#999',
            draggable: false,
            editable: false,
            clickable: true
          }
        },
        watch: {
          mapMode(newMode, oldMode) {
            if (newMode === 'ready') {
              if (oldMode === 'edit') {
                this.mapDraggable = true;
                this.mapCursor = null;
                return;
              }
            }
            if (newMode === 'edit') {
              this.mapDraggable = false;
              this.mapCursor = 'default';
            }
          }
        },
        mounted() {
          this.mapMode = 'ready';
        }
      });
    });
  </script>
</body>
warning
If you are using the runtime-only build the template on toolbarTemplate will not work, instead of that
you need to pre-compile the templates into render functions, or use the compiler-included build.
Test the component
Click to see the HTML example in action
Click to see the HTML example with slot in action