Editable lines in Google Maps using the Javascript v3 API

The Google Maps Javascript API v3 provides overlays for drawing shapes, such as Polygons, Circles, Polylines and Rectangles. The shapes are not implicitly interactive in the respect that you cannot tell the shape to be ‘editable’ as you could in the Javascript v2 API (here’s an example).

To simulate the behavior using functionality provided by maps v3 API, you’ll need to find an element that supports the drag event, such as the Marker object. A marker has a position, a shape and provides events such as click, dragstart, drag and dragend.

The code

First off, we need to load the google maps API and specify which version to use. The code uses some extra goodies to calculate the length of the line, which is provided in the geometry library and it looks like this is available in the v3.3 of the API. Here’s how to do specify this:

   <script type="text/javascript" src="http://maps.google.com/maps/api/js?libraries=geometry&sensor=false&v=3.3"></script>

The complete code looks like:

<!DOCTYPE html>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
    <style type="text/css">
        html {
            height: 100%

        body {
            height: 100%;
            margin: 0px;
            padding: 0px

        #map_canvas {
            height: 100%
    <script type="text/javascript"
    <script type="text/javascript">
        var g = google.maps;
        function initialize() {
            var latlng = new g.LatLng(62.397, 12.644);
            var myOptions = {
                zoom: 4,
                center: latlng,
                mapTypeId: g.MapTypeId.ROADMAP
            var map = new g.Map(document.getElementById("map_canvas"), myOptions);

        function registerMapDragHandler(aMap) {

            var map = aMap;

            g.event.addListener(map, 'click', function(event) {
                createLineBeingDragged(map, event.latLng);

            function createLineBeingDragged(map, pos) {
                var line = new g.Polyline({map: map, path: [pos, pos]});
                g.event.addListener(map, 'mousemove', function(event) {
                    line.getPath().setAt(1, event.latLng);
                g.event.addListener(line, 'click', function(event) {
                    g.event.clearListeners(map, 'mousemove');
                    g.event.clearListeners(line, 'click');
                    createMarkersForLine(map, line);

                function createMarkersForLine(map, line) {
                    var startMarker = createMarker(line, 0);
                    var endMarker = createMarker(line, 1);
                    startMarker.nextMarker = endMarker;
                    endMarker.previousMarker = startMarker;

                function createMarker(line, pathPos) {
                    var position = line.getPath().getAt(pathPos);
                    var marker = new g.Marker({map: map, position: position, visible: true, flat: true, draggable: true, raiseOnDrag: false});

                    // Marker functions
                    marker.getPathIndex = function() {
                        if (this.previousMarker != null) {
                            return this.previousMarker.getPathIndex() + 1;
                        } else {
                            return 0;

                    marker.startDrag = function(pos) {
                        if (!marker.previousMarker || !marker.nextMarker) {
                            line.getPath().insertAt(marker.getPathIndex(), pos);
                            var newMarker = createMarker(line, marker.getPathIndex());
                            if (marker.nextMarker) {
                                newMarker.previousMarker = marker;
                                newMarker.nextMarker = marker.nextMarker;
                                newMarker.nextMarker.previousMarker = newMarker;
                                marker.nextMarker = newMarker;
                            } else {
                                newMarker.nextMarker = marker;
                                newMarker.previousMarker = marker.previousMarker;
                                newMarker.previousMarker.nextMarker = newMarker;
                                marker.previousMarker = newMarker;

                    marker.beingDragged = function() {
                        line.getPath().setAt(marker.getPathIndex(), marker.getPosition());

                    // Listeners
                    g.event.addListener(marker, 'dragstart', function(event) {

                    g.event.addListener(marker, 'drag', function(event) {

                    g.event.addListener(marker, 'click', function(event) {
                        var length = g.geometry.spherical.computeLength(line.getPath()) / 1000;
                        var infoWindow = new g.InfoWindow(
                            content: "<ul><li>Line length: " + length.toFixed(2) + " km</li>"+
                                    "<li>Latitude: " + marker.getPosition().lat().toFixed(6) + "</li>"+
                                    "<li>Longitude: " + marker.getPosition().lng().toFixed(6) + "</ul>"
                        infoWindow.open(map, marker);

                    return marker;
<body onload="initialize()">
<div id="map_canvas" style="width:100%; height:100%"></div>

To start drawing, click on the map to specify the starting point and move the mouse to the end point.

The highlighted function is the most interesting. It creates a marker representing one segment of the path of a PolyLine. The marker knows about the previous and next marker and calculates its position in the MVCArray of the path so that it updates the geo-position of the correct segment. This is done by the getPathIndex() function added to the marker.

The Marker.dragStart() function checks whether the marker is the first or last marker in the path. If it is, a segment is added to the PolyLine at the geo-position where the drag starts, and a new marker is created representing the new segment. This means that the line is extended when dragging the end markers.

The Marker.beingDragged() function updates the position of the segment for the PolyLine to the geo-position for the marker, which makes the segment ‘editable’.

When clicking on a marker, the length of the line is computed using the google.maps.geometry.spherical.computeLength() function and an InfoWindow is shown displaying the length and the longitude/latitude for the selected marker.


It is possible to simulate the older Google Maps Javascript V2 functionality for editing shapes but it requires you to write your own editing functionality. The code above is just a proof-of-concept and needs a lot more love and caring to be useful.

This Post Has 6 Comments

  1. Erwin

    It seems Google has updated the V3 API. You can now set the property “editable” in a polygon or polyline making them user editable. However, I am still trying to figure out how to delete a point… (as a user, not in code).

  2. Alexander Nemsadze

    Perfect, thanks.

  3. Naveen

    Hi Tobais,

    I am trying to edit a selected polygon to edit from all loaded polygons so that the selected polygon can be updated.

    can you help me


  4. akram

    thaaaaaaaaaaaaaaaaaaaaaaaaaanks :) :D

    @naveen :
    you can do that by setting the option editable:true for that polygon

  5. aida

    perfect.thank you so much.

Leave a Reply