It's the 15th anniversary of Google Maps Platform - Check out the latest news and announcements

Adding Controls to the Map

This example demonstrates vertex deletion. Right-click on a vertex to show a "Delete" menu.

Read the documentation.

TypeScript

function initialize() {
  const mapOptions = {
    zoom: 3,
    center: new google.maps.LatLng(0, -180),
    mapTypeId: "terrain"
  };

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    mapOptions
  );

  const flightPlanCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
  ];

  const flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    editable: true,
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 2,
    map: map
  });

  /**
   * A menu that lets a user delete a selected vertex of a path.
   */
  class DeleteMenu extends google.maps.OverlayView {
    private div_: HTMLDivElement;
    private divListener_?: google.maps.MapsEventListener;

    constructor() {
      super();
      this.div_ = document.createElement("div");
      this.div_.className = "delete-menu";
      this.div_.innerHTML = "Delete";

      const menu = this;
      google.maps.event.addDomListener(this.div_, "click", () => {
        menu.removeVertex();
      });
    }

    onAdd() {
      const deleteMenu = this;
      const map = this.getMap();
      this.getPanes().floatPane.appendChild(this.div_);

      // mousedown anywhere on the map except on the menu div will close the
      // menu.
      this.divListener_ = google.maps.event.addDomListener(
        // @ts-ignore TODO(jpoehnelt) fix typings
        map.getDiv(),
        "mousedown",
        (e: Event) => {
          if (e.target != deleteMenu.div_) {
            deleteMenu.close();
          }
        },
        true
      );
    }

    onRemove() {
      if (this.divListener_) {
        google.maps.event.removeListener(this.divListener_);
      }

      (this.div_.parentNode as HTMLElement).removeChild(this.div_);

      // clean up
      this.set("position", null);
      this.set("path", null);
      this.set("vertex", null);
    }

    close() {
      this.setMap(null);
    }

    draw() {
      const position = this.get("position");
      const projection = this.getProjection();

      if (!position || !projection) {
        return;
      }

      const point = projection.fromLatLngToDivPixel(position);
      this.div_.style.top = point.y + "px";
      this.div_.style.left = point.x + "px";
    }

    /**
     * Opens the menu at a vertex of a given path.
     */
    open(
      map: google.maps.Map,
      path: google.maps.MVCArray<google.maps.LatLng>,
      vertex: number
    ) {
      this.set("position", path.getAt(vertex));
      this.set("path", path);
      this.set("vertex", vertex);
      this.setMap(map);
      this.draw();
    }

    /**
     * Deletes the vertex from the path.
     */
    removeVertex() {
      const path = this.get("path");
      const vertex = this.get("vertex");

      if (!path || vertex == undefined) {
        this.close();
        return;
      }

      path.removeAt(vertex);
      this.close();
    }
  }

  const deleteMenu = new DeleteMenu();

  google.maps.event.addListener(flightPath, "rightclick", (e: any) => {
    // Check if click was on a vertex control point
    if (e.vertex == undefined) {
      return;
    }
    deleteMenu.open(map, flightPath.getPath(), e.vertex);
  });
}

JavaScript

function initialize() {
  const mapOptions = {
    zoom: 3,
    center: new google.maps.LatLng(0, -180),
    mapTypeId: "terrain"
  };
  const map = new google.maps.Map(document.getElementById("map"), mapOptions);
  const flightPlanCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
  ];
  const flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    editable: true,
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 2,
    map: map
  });

  /**
   * A menu that lets a user delete a selected vertex of a path.
   */
  class DeleteMenu extends google.maps.OverlayView {
    constructor() {
      super();
      this.div_ = document.createElement("div");
      this.div_.className = "delete-menu";
      this.div_.innerHTML = "Delete";
      const menu = this;
      google.maps.event.addDomListener(this.div_, "click", () => {
        menu.removeVertex();
      });
    }
    onAdd() {
      const deleteMenu = this;
      const map = this.getMap();
      this.getPanes().floatPane.appendChild(this.div_);
      // mousedown anywhere on the map except on the menu div will close the
      // menu.
      this.divListener_ = google.maps.event.addDomListener(
        map.getDiv(),
        "mousedown",
        e => {
          if (e.target != deleteMenu.div_) {
            deleteMenu.close();
          }
        },
        true
      );
    }
    onRemove() {
      if (this.divListener_) {
        google.maps.event.removeListener(this.divListener_);
      }
      this.div_.parentNode.removeChild(this.div_);
      // clean up
      this.set("position", null);
      this.set("path", null);
      this.set("vertex", null);
    }
    close() {
      this.setMap(null);
    }
    draw() {
      const position = this.get("position");
      const projection = this.getProjection();

      if (!position || !projection) {
        return;
      }
      const point = projection.fromLatLngToDivPixel(position);
      this.div_.style.top = point.y + "px";
      this.div_.style.left = point.x + "px";
    }
    /**
     * Opens the menu at a vertex of a given path.
     */
    open(map, path, vertex) {
      this.set("position", path.getAt(vertex));
      this.set("path", path);
      this.set("vertex", vertex);
      this.setMap(map);
      this.draw();
    }
    /**
     * Deletes the vertex from the path.
     */
    removeVertex() {
      const path = this.get("path");
      const vertex = this.get("vertex");

      if (!path || vertex == undefined) {
        this.close();
        return;
      }
      path.removeAt(vertex);
      this.close();
    }
  }
  const deleteMenu = new DeleteMenu();
  google.maps.event.addListener(flightPath, "rightclick", e => {
    // Check if click was on a vertex control point
    if (e.vertex == undefined) {
      return;
    }
    deleteMenu.open(map, flightPath.getPath(), e.vertex);
  });
}

CSS

/* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
#map {
  height: 100%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

.delete-menu {
  position: absolute;
  background: white;
  padding: 3px;
  color: #666;
  font-weight: bold;
  border: 1px solid #999;
  font-family: sans-serif;
  font-size: 12px;
  box-shadow: 1px 3px 3px rgba(0, 0, 0, 0.3);
  margin-top: -10px;
  margin-left: 10px;
  cursor: pointer;
}

.delete-menu:hover {
  background: #eee;
}

HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Deleting a Vertex</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initialize&libraries=&v=weekly"
      defer
    ></script>
    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script src="./app.js"></script>
  </head>
  <body>
    <div id="map"></div>
  </body>
</html>

All

<!DOCTYPE html>
<html>
  <head>
    <title>Deleting a Vertex</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initialize&libraries=&v=weekly"
      defer
    ></script>
    <style type="text/css">
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }

      /* Optional: Makes the sample page fill the window. */
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }

      .delete-menu {
        position: absolute;
        background: white;
        padding: 3px;
        color: #666;
        font-weight: bold;
        border: 1px solid #999;
        font-family: sans-serif;
        font-size: 12px;
        box-shadow: 1px 3px 3px rgba(0, 0, 0, 0.3);
        margin-top: -10px;
        margin-left: 10px;
        cursor: pointer;
      }

      .delete-menu:hover {
        background: #eee;
      }
    </style>
    <script>
      "use strict";

      function initialize() {
        const mapOptions = {
          zoom: 3,
          center: new google.maps.LatLng(0, -180),
          mapTypeId: "terrain"
        };
        const map = new google.maps.Map(
          document.getElementById("map"),
          mapOptions
        );
        const flightPlanCoordinates = [
          new google.maps.LatLng(37.772323, -122.214897),
          new google.maps.LatLng(21.291982, -157.821856),
          new google.maps.LatLng(-18.142599, 178.431),
          new google.maps.LatLng(-27.46758, 153.027892)
        ];
        const flightPath = new google.maps.Polyline({
          path: flightPlanCoordinates,
          editable: true,
          strokeColor: "#FF0000",
          strokeOpacity: 1.0,
          strokeWeight: 2,
          map: map
        });
        /**
         * A menu that lets a user delete a selected vertex of a path.
         */

        class DeleteMenu extends google.maps.OverlayView {
          constructor() {
            super();
            this.div_ = document.createElement("div");
            this.div_.className = "delete-menu";
            this.div_.innerHTML = "Delete";
            const menu = this;
            google.maps.event.addDomListener(this.div_, "click", () => {
              menu.removeVertex();
            });
          }

          onAdd() {
            const deleteMenu = this;
            const map = this.getMap();
            this.getPanes().floatPane.appendChild(this.div_); // mousedown anywhere on the map except on the menu div will close the
            // menu.

            this.divListener_ = google.maps.event.addDomListener(
              map.getDiv(),
              "mousedown",
              e => {
                if (e.target != deleteMenu.div_) {
                  deleteMenu.close();
                }
              },
              true
            );
          }

          onRemove() {
            if (this.divListener_) {
              google.maps.event.removeListener(this.divListener_);
            }

            this.div_.parentNode.removeChild(this.div_); // clean up

            this.set("position", null);
            this.set("path", null);
            this.set("vertex", null);
          }

          close() {
            this.setMap(null);
          }

          draw() {
            const position = this.get("position");
            const projection = this.getProjection();

            if (!position || !projection) {
              return;
            }

            const point = projection.fromLatLngToDivPixel(position);
            this.div_.style.top = point.y + "px";
            this.div_.style.left = point.x + "px";
          }
          /**
           * Opens the menu at a vertex of a given path.
           */

          open(map, path, vertex) {
            this.set("position", path.getAt(vertex));
            this.set("path", path);
            this.set("vertex", vertex);
            this.setMap(map);
            this.draw();
          }
          /**
           * Deletes the vertex from the path.
           */

          removeVertex() {
            const path = this.get("path");
            const vertex = this.get("vertex");

            if (!path || vertex == undefined) {
              this.close();
              return;
            }

            path.removeAt(vertex);
            this.close();
          }
        }

        const deleteMenu = new DeleteMenu();
        google.maps.event.addListener(flightPath, "rightclick", e => {
          // Check if click was on a vertex control point
          if (e.vertex == undefined) {
            return;
          }

          deleteMenu.open(map, flightPath.getPath(), e.vertex);
        });
      }
    </script>
  </head>
  <body>
    <div id="map"></div>
  </body>
</html>
"use strict"; function initialize() { const mapOptions = { zoom: 3, center: new google.maps.LatLng(0, -180), mapTypeId: "terrain" }; const map = new google.maps.Map(document.getElementById("map"), mapOptions); const flightPlanCoordinates = [ new google.maps.LatLng(37.772323, -122.214897), new google.maps.LatLng(21.291982, -157.821856), new google.maps.LatLng(-18.142599, 178.431), new google.maps.LatLng(-27.46758, 153.027892) ]; const flightPath = new google.maps.Polyline({ path: flightPlanCoordinates, editable: true, strokeColor: "#FF0000", strokeOpacity: 1.0, strokeWeight: 2, map: map }); /** * A menu that lets a user delete a selected vertex of a path. */ class DeleteMenu extends google.maps.OverlayView { constructor() { super(); this.div_ = document.createElement("div"); this.div_.className = "delete-menu"; this.div_.innerHTML = "Delete"; const menu = this; google.maps.event.addDomListener(this.div_, "click", () => { menu.removeVertex(); }); } onAdd() { const deleteMenu = this; const map = this.getMap(); this.getPanes().floatPane.appendChild(this.div_); // mousedown anywhere on the map except on the menu div will close the // menu. this.divListener_ = google.maps.event.addDomListener( map.getDiv(), "mousedown", e => { if (e.target != deleteMenu.div_) { deleteMenu.close(); } }, true ); } onRemove() { if (this.divListener_) { google.maps.event.removeListener(this.divListener_); } this.div_.parentNode.removeChild(this.div_); // clean up this.set("position", null); this.set("path", null); this.set("vertex", null); } close() { this.setMap(null); } draw() { const position = this.get("position"); const projection = this.getProjection(); if (!position || !projection) { return; } const point = projection.fromLatLngToDivPixel(position); this.div_.style.top = point.y + "px"; this.div_.style.left = point.x + "px"; } /** * Opens the menu at a vertex of a given path. */ open(map, path, vertex) { this.set("position", path.getAt(vertex)); this.set("path", path); this.set("vertex", vertex); this.setMap(map); this.draw(); } /** * Deletes the vertex from the path. */ removeVertex() { const path = this.get("path"); const vertex = this.get("vertex"); if (!path || vertex == undefined) { this.close(); return; } path.removeAt(vertex); this.close(); } } const deleteMenu = new DeleteMenu(); google.maps.event.addListener(flightPath, "rightclick", e => { // Check if click was on a vertex control point if (e.vertex == undefined) { return; } deleteMenu.open(map, flightPath.getPath(), e.vertex); }); }
/* Always set the map height explicitly to define the size of the div * element that contains the map. */ #map { height: 100%; } /* Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } .delete-menu { position: absolute; background: white; padding: 3px; color: #666; font-weight: bold; border: 1px solid #999; font-family: sans-serif; font-size: 12px; box-shadow: 1px 3px 3px rgba(0, 0, 0, 0.3); margin-top: -10px; margin-left: 10px; cursor: pointer; } .delete-menu:hover { background: #eee; }
<!DOCTYPE html> <html> <head> <title>Deleting a Vertex</title> <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCb1xprYSpXd0q_yDsJ1W2UGhfl9_YGKU0&callback=initialize&libraries=&v=weekly" defer ></script> <!-- jsFiddle will insert css and js --> </head> <body> <div id="map"></div> </body> </html>