Programmatically editing the path of polyline leaves a ghost line












0















I have lines in the map that can be edited by the user by dragging their vertices, when this happens I check if the vertex that the user has moved is near to any other object, in that case the line has to be attached to that object.



More specifically, when the user moves the line, the event "set_at" is triggered, and in the function called by the listener the line is programmatically edited to be attached to the nearest object (if any). In the case that object exists, the line is attached to the object without any issue (meaning that the line is properly attached and it works). However in the map, the line that the user generated by moving the original one is still visible, but it is translucent. And that line disappears eventually when other operation is performed on the map.



I have tried to clear the path (path.clear()), to create a new path, to remove it from the map (setMap(null)) and place it again (setMap(LocationPicker.map.map)). But nothing seems to work.



google.maps.event.addListener(marker.getPath(), 'set_at', function(vertex, eventC) {
LocationPicker.controlVertexMovement(marker,vertex, eventC);
});

controlVertexMovement: function(marker, vertex, eventC) {
var path = marker.getPath();
var closest = LocationPicker.searchClosestObject(path.j[vertex].lat(), path.j[vertex].lng());
if(closest!=null){
path.j[vertex] = closest.latlng;
LocationPicker.map.overlays[overlayNum].setPath(path);
}
}


The actual result: https://cdn.pbrd.co/images/HUCyWwu.png
The expected result: https://cdn.pbrd.co/images/HUCxBfJ.png



example fiddle



code snippet:






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

var map = new google.maps.Map(document.getElementById('map'), mapOptions);

var 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)
];
var flightPath = new google.maps.Polyline({
path: flightPlanCoordinates,
editable: true,
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2,
map: map
});

var deleteMenu = new DeleteMenu();

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

google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) {
var path = flightPath.getPath();
path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
//marker.setMap(null);
flightPath.setPath(path);
//marker.setMap(LocationPicker.map.map);
});

}

/**
* A menu that lets a user delete a selected vertex of a path.
* @constructor
*/
function DeleteMenu() {
this.div_ = document.createElement('div');
this.div_.className = 'delete-menu';
this.div_.innerHTML = 'Delete';

var menu = this;
google.maps.event.addDomListener(this.div_, 'click', function() {
menu.removeVertex();
});
}
DeleteMenu.prototype = new google.maps.OverlayView();

DeleteMenu.prototype.onAdd = function() {
var deleteMenu = this;
var 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', function(e) {
if (e.target != deleteMenu.div_) {
deleteMenu.close();
}
}, true);
};

DeleteMenu.prototype.onRemove = function() {
google.maps.event.removeListener(this.divListener_);
this.div_.parentNode.removeChild(this.div_);

// clean up
this.set('position');
this.set('path');
this.set('vertex');
};

DeleteMenu.prototype.close = function() {
this.setMap(null);
};

DeleteMenu.prototype.draw = function() {
var position = this.get('position');
var projection = this.getProjection();

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

var 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.
*/
DeleteMenu.prototype.open = function(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.
*/
DeleteMenu.prototype.removeVertex = function() {
var path = this.get('path');
var vertex = this.get('vertex');

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

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

google.maps.event.addDomListener(window, 'load', initialize);

/* 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, .3);
margin-top: -10px;
margin-left: 10px;
cursor: pointer;
}

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

<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>












share|improve this question





























    0















    I have lines in the map that can be edited by the user by dragging their vertices, when this happens I check if the vertex that the user has moved is near to any other object, in that case the line has to be attached to that object.



    More specifically, when the user moves the line, the event "set_at" is triggered, and in the function called by the listener the line is programmatically edited to be attached to the nearest object (if any). In the case that object exists, the line is attached to the object without any issue (meaning that the line is properly attached and it works). However in the map, the line that the user generated by moving the original one is still visible, but it is translucent. And that line disappears eventually when other operation is performed on the map.



    I have tried to clear the path (path.clear()), to create a new path, to remove it from the map (setMap(null)) and place it again (setMap(LocationPicker.map.map)). But nothing seems to work.



    google.maps.event.addListener(marker.getPath(), 'set_at', function(vertex, eventC) {
    LocationPicker.controlVertexMovement(marker,vertex, eventC);
    });

    controlVertexMovement: function(marker, vertex, eventC) {
    var path = marker.getPath();
    var closest = LocationPicker.searchClosestObject(path.j[vertex].lat(), path.j[vertex].lng());
    if(closest!=null){
    path.j[vertex] = closest.latlng;
    LocationPicker.map.overlays[overlayNum].setPath(path);
    }
    }


    The actual result: https://cdn.pbrd.co/images/HUCyWwu.png
    The expected result: https://cdn.pbrd.co/images/HUCxBfJ.png



    example fiddle



    code snippet:






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

    var map = new google.maps.Map(document.getElementById('map'), mapOptions);

    var 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)
    ];
    var flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    editable: true,
    strokeColor: '#FF0000',
    strokeOpacity: 1.0,
    strokeWeight: 2,
    map: map
    });

    var deleteMenu = new DeleteMenu();

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

    google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) {
    var path = flightPath.getPath();
    path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
    //marker.setMap(null);
    flightPath.setPath(path);
    //marker.setMap(LocationPicker.map.map);
    });

    }

    /**
    * A menu that lets a user delete a selected vertex of a path.
    * @constructor
    */
    function DeleteMenu() {
    this.div_ = document.createElement('div');
    this.div_.className = 'delete-menu';
    this.div_.innerHTML = 'Delete';

    var menu = this;
    google.maps.event.addDomListener(this.div_, 'click', function() {
    menu.removeVertex();
    });
    }
    DeleteMenu.prototype = new google.maps.OverlayView();

    DeleteMenu.prototype.onAdd = function() {
    var deleteMenu = this;
    var 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', function(e) {
    if (e.target != deleteMenu.div_) {
    deleteMenu.close();
    }
    }, true);
    };

    DeleteMenu.prototype.onRemove = function() {
    google.maps.event.removeListener(this.divListener_);
    this.div_.parentNode.removeChild(this.div_);

    // clean up
    this.set('position');
    this.set('path');
    this.set('vertex');
    };

    DeleteMenu.prototype.close = function() {
    this.setMap(null);
    };

    DeleteMenu.prototype.draw = function() {
    var position = this.get('position');
    var projection = this.getProjection();

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

    var 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.
    */
    DeleteMenu.prototype.open = function(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.
    */
    DeleteMenu.prototype.removeVertex = function() {
    var path = this.get('path');
    var vertex = this.get('vertex');

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

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

    google.maps.event.addDomListener(window, 'load', initialize);

    /* 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, .3);
    margin-top: -10px;
    margin-left: 10px;
    cursor: pointer;
    }

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

    <div id="map"></div>
    <!-- Replace the value of the key parameter with your own API key. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>












    share|improve this question



























      0












      0








      0








      I have lines in the map that can be edited by the user by dragging their vertices, when this happens I check if the vertex that the user has moved is near to any other object, in that case the line has to be attached to that object.



      More specifically, when the user moves the line, the event "set_at" is triggered, and in the function called by the listener the line is programmatically edited to be attached to the nearest object (if any). In the case that object exists, the line is attached to the object without any issue (meaning that the line is properly attached and it works). However in the map, the line that the user generated by moving the original one is still visible, but it is translucent. And that line disappears eventually when other operation is performed on the map.



      I have tried to clear the path (path.clear()), to create a new path, to remove it from the map (setMap(null)) and place it again (setMap(LocationPicker.map.map)). But nothing seems to work.



      google.maps.event.addListener(marker.getPath(), 'set_at', function(vertex, eventC) {
      LocationPicker.controlVertexMovement(marker,vertex, eventC);
      });

      controlVertexMovement: function(marker, vertex, eventC) {
      var path = marker.getPath();
      var closest = LocationPicker.searchClosestObject(path.j[vertex].lat(), path.j[vertex].lng());
      if(closest!=null){
      path.j[vertex] = closest.latlng;
      LocationPicker.map.overlays[overlayNum].setPath(path);
      }
      }


      The actual result: https://cdn.pbrd.co/images/HUCyWwu.png
      The expected result: https://cdn.pbrd.co/images/HUCxBfJ.png



      example fiddle



      code snippet:






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

      var map = new google.maps.Map(document.getElementById('map'), mapOptions);

      var 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)
      ];
      var flightPath = new google.maps.Polyline({
      path: flightPlanCoordinates,
      editable: true,
      strokeColor: '#FF0000',
      strokeOpacity: 1.0,
      strokeWeight: 2,
      map: map
      });

      var deleteMenu = new DeleteMenu();

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

      google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) {
      var path = flightPath.getPath();
      path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
      //marker.setMap(null);
      flightPath.setPath(path);
      //marker.setMap(LocationPicker.map.map);
      });

      }

      /**
      * A menu that lets a user delete a selected vertex of a path.
      * @constructor
      */
      function DeleteMenu() {
      this.div_ = document.createElement('div');
      this.div_.className = 'delete-menu';
      this.div_.innerHTML = 'Delete';

      var menu = this;
      google.maps.event.addDomListener(this.div_, 'click', function() {
      menu.removeVertex();
      });
      }
      DeleteMenu.prototype = new google.maps.OverlayView();

      DeleteMenu.prototype.onAdd = function() {
      var deleteMenu = this;
      var 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', function(e) {
      if (e.target != deleteMenu.div_) {
      deleteMenu.close();
      }
      }, true);
      };

      DeleteMenu.prototype.onRemove = function() {
      google.maps.event.removeListener(this.divListener_);
      this.div_.parentNode.removeChild(this.div_);

      // clean up
      this.set('position');
      this.set('path');
      this.set('vertex');
      };

      DeleteMenu.prototype.close = function() {
      this.setMap(null);
      };

      DeleteMenu.prototype.draw = function() {
      var position = this.get('position');
      var projection = this.getProjection();

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

      var 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.
      */
      DeleteMenu.prototype.open = function(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.
      */
      DeleteMenu.prototype.removeVertex = function() {
      var path = this.get('path');
      var vertex = this.get('vertex');

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

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

      google.maps.event.addDomListener(window, 'load', initialize);

      /* 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, .3);
      margin-top: -10px;
      margin-left: 10px;
      cursor: pointer;
      }

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

      <div id="map"></div>
      <!-- Replace the value of the key parameter with your own API key. -->
      <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>












      share|improve this question
















      I have lines in the map that can be edited by the user by dragging their vertices, when this happens I check if the vertex that the user has moved is near to any other object, in that case the line has to be attached to that object.



      More specifically, when the user moves the line, the event "set_at" is triggered, and in the function called by the listener the line is programmatically edited to be attached to the nearest object (if any). In the case that object exists, the line is attached to the object without any issue (meaning that the line is properly attached and it works). However in the map, the line that the user generated by moving the original one is still visible, but it is translucent. And that line disappears eventually when other operation is performed on the map.



      I have tried to clear the path (path.clear()), to create a new path, to remove it from the map (setMap(null)) and place it again (setMap(LocationPicker.map.map)). But nothing seems to work.



      google.maps.event.addListener(marker.getPath(), 'set_at', function(vertex, eventC) {
      LocationPicker.controlVertexMovement(marker,vertex, eventC);
      });

      controlVertexMovement: function(marker, vertex, eventC) {
      var path = marker.getPath();
      var closest = LocationPicker.searchClosestObject(path.j[vertex].lat(), path.j[vertex].lng());
      if(closest!=null){
      path.j[vertex] = closest.latlng;
      LocationPicker.map.overlays[overlayNum].setPath(path);
      }
      }


      The actual result: https://cdn.pbrd.co/images/HUCyWwu.png
      The expected result: https://cdn.pbrd.co/images/HUCxBfJ.png



      example fiddle



      code snippet:






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

      var map = new google.maps.Map(document.getElementById('map'), mapOptions);

      var 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)
      ];
      var flightPath = new google.maps.Polyline({
      path: flightPlanCoordinates,
      editable: true,
      strokeColor: '#FF0000',
      strokeOpacity: 1.0,
      strokeWeight: 2,
      map: map
      });

      var deleteMenu = new DeleteMenu();

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

      google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) {
      var path = flightPath.getPath();
      path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
      //marker.setMap(null);
      flightPath.setPath(path);
      //marker.setMap(LocationPicker.map.map);
      });

      }

      /**
      * A menu that lets a user delete a selected vertex of a path.
      * @constructor
      */
      function DeleteMenu() {
      this.div_ = document.createElement('div');
      this.div_.className = 'delete-menu';
      this.div_.innerHTML = 'Delete';

      var menu = this;
      google.maps.event.addDomListener(this.div_, 'click', function() {
      menu.removeVertex();
      });
      }
      DeleteMenu.prototype = new google.maps.OverlayView();

      DeleteMenu.prototype.onAdd = function() {
      var deleteMenu = this;
      var 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', function(e) {
      if (e.target != deleteMenu.div_) {
      deleteMenu.close();
      }
      }, true);
      };

      DeleteMenu.prototype.onRemove = function() {
      google.maps.event.removeListener(this.divListener_);
      this.div_.parentNode.removeChild(this.div_);

      // clean up
      this.set('position');
      this.set('path');
      this.set('vertex');
      };

      DeleteMenu.prototype.close = function() {
      this.setMap(null);
      };

      DeleteMenu.prototype.draw = function() {
      var position = this.get('position');
      var projection = this.getProjection();

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

      var 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.
      */
      DeleteMenu.prototype.open = function(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.
      */
      DeleteMenu.prototype.removeVertex = function() {
      var path = this.get('path');
      var vertex = this.get('vertex');

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

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

      google.maps.event.addDomListener(window, 'load', initialize);

      /* 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, .3);
      margin-top: -10px;
      margin-left: 10px;
      cursor: pointer;
      }

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

      <div id="map"></div>
      <!-- Replace the value of the key parameter with your own API key. -->
      <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>








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

      var map = new google.maps.Map(document.getElementById('map'), mapOptions);

      var 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)
      ];
      var flightPath = new google.maps.Polyline({
      path: flightPlanCoordinates,
      editable: true,
      strokeColor: '#FF0000',
      strokeOpacity: 1.0,
      strokeWeight: 2,
      map: map
      });

      var deleteMenu = new DeleteMenu();

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

      google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) {
      var path = flightPath.getPath();
      path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
      //marker.setMap(null);
      flightPath.setPath(path);
      //marker.setMap(LocationPicker.map.map);
      });

      }

      /**
      * A menu that lets a user delete a selected vertex of a path.
      * @constructor
      */
      function DeleteMenu() {
      this.div_ = document.createElement('div');
      this.div_.className = 'delete-menu';
      this.div_.innerHTML = 'Delete';

      var menu = this;
      google.maps.event.addDomListener(this.div_, 'click', function() {
      menu.removeVertex();
      });
      }
      DeleteMenu.prototype = new google.maps.OverlayView();

      DeleteMenu.prototype.onAdd = function() {
      var deleteMenu = this;
      var 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', function(e) {
      if (e.target != deleteMenu.div_) {
      deleteMenu.close();
      }
      }, true);
      };

      DeleteMenu.prototype.onRemove = function() {
      google.maps.event.removeListener(this.divListener_);
      this.div_.parentNode.removeChild(this.div_);

      // clean up
      this.set('position');
      this.set('path');
      this.set('vertex');
      };

      DeleteMenu.prototype.close = function() {
      this.setMap(null);
      };

      DeleteMenu.prototype.draw = function() {
      var position = this.get('position');
      var projection = this.getProjection();

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

      var 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.
      */
      DeleteMenu.prototype.open = function(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.
      */
      DeleteMenu.prototype.removeVertex = function() {
      var path = this.get('path');
      var vertex = this.get('vertex');

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

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

      google.maps.event.addDomListener(window, 'load', initialize);

      /* 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, .3);
      margin-top: -10px;
      margin-left: 10px;
      cursor: pointer;
      }

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

      <div id="map"></div>
      <!-- Replace the value of the key parameter with your own API key. -->
      <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>





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

      var map = new google.maps.Map(document.getElementById('map'), mapOptions);

      var 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)
      ];
      var flightPath = new google.maps.Polyline({
      path: flightPlanCoordinates,
      editable: true,
      strokeColor: '#FF0000',
      strokeOpacity: 1.0,
      strokeWeight: 2,
      map: map
      });

      var deleteMenu = new DeleteMenu();

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

      google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) {
      var path = flightPath.getPath();
      path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
      //marker.setMap(null);
      flightPath.setPath(path);
      //marker.setMap(LocationPicker.map.map);
      });

      }

      /**
      * A menu that lets a user delete a selected vertex of a path.
      * @constructor
      */
      function DeleteMenu() {
      this.div_ = document.createElement('div');
      this.div_.className = 'delete-menu';
      this.div_.innerHTML = 'Delete';

      var menu = this;
      google.maps.event.addDomListener(this.div_, 'click', function() {
      menu.removeVertex();
      });
      }
      DeleteMenu.prototype = new google.maps.OverlayView();

      DeleteMenu.prototype.onAdd = function() {
      var deleteMenu = this;
      var 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', function(e) {
      if (e.target != deleteMenu.div_) {
      deleteMenu.close();
      }
      }, true);
      };

      DeleteMenu.prototype.onRemove = function() {
      google.maps.event.removeListener(this.divListener_);
      this.div_.parentNode.removeChild(this.div_);

      // clean up
      this.set('position');
      this.set('path');
      this.set('vertex');
      };

      DeleteMenu.prototype.close = function() {
      this.setMap(null);
      };

      DeleteMenu.prototype.draw = function() {
      var position = this.get('position');
      var projection = this.getProjection();

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

      var 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.
      */
      DeleteMenu.prototype.open = function(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.
      */
      DeleteMenu.prototype.removeVertex = function() {
      var path = this.get('path');
      var vertex = this.get('vertex');

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

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

      google.maps.event.addDomListener(window, 'load', initialize);

      /* 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, .3);
      margin-top: -10px;
      margin-left: 10px;
      cursor: pointer;
      }

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

      <div id="map"></div>
      <!-- Replace the value of the key parameter with your own API key. -->
      <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>






      javascript google-maps google-maps-api-3 google-polyline






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 3 at 17:01









      geocodezip

      127k10146176




      127k10146176










      asked Jan 2 at 19:08









      AngelAngel

      813




      813
























          1 Answer
          1






          active

          oldest

          votes


















          0














          path.j is not a documented property. Don't use undocumented properties, they can (and will) change with each release of the API. Only use documented properties/methods.



          Don't use:



          path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);


          One option is to use:



          path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));


          Like this:



          google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

          function processSetAt(vertex, eventC) {
          // turn off editing
          flightPath.setEditable(false);
          // update the path
          var path = flightPath.getPath();
          path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
          flightPath.setPath(path);
          // turn editing back on
          flightPath.setEditable(true);
          google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
          }


          proof of concept fiddle



          Note that your issue seems to be related to modifying the path of the polyline while it is "editable". The only way I found to remove the "ghost" path was to turn off editing, modify the polyline, then turn editing back on.



          Another option (from the OP's comment):



          Use a flag to avoid an infinite loop on the 'set at' event. Like this:



          google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) { 
          if(!changingPath){
          var path = flightPath.getPath();
          changingPath = true;
          path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
          changingPath = false;
          }
          });


          fiddle



          code snippet:






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

          var map = new google.maps.Map(document.getElementById('map'), mapOptions);

          var 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)
          ];
          var flightPath = new google.maps.Polyline({
          path: flightPlanCoordinates,
          editable: true,
          strokeColor: '#FF0000',
          strokeOpacity: 1.0,
          strokeWeight: 2,
          map: map
          });

          var deleteMenu = new DeleteMenu();

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

          google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

          function processSetAt(vertex, eventC) {
          // turn off editing
          flightPath.setEditable(false);
          // update the path
          var path = flightPath.getPath();
          path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
          flightPath.setPath(path);
          // turn editing back on
          flightPath.setEditable(true);
          google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
          }
          }

          /**
          * A menu that lets a user delete a selected vertex of a path.
          * @constructor
          */
          function DeleteMenu() {
          this.div_ = document.createElement('div');
          this.div_.className = 'delete-menu';
          this.div_.innerHTML = 'Delete';

          var menu = this;
          google.maps.event.addDomListener(this.div_, 'click', function() {
          menu.removeVertex();
          });
          }
          DeleteMenu.prototype = new google.maps.OverlayView();

          DeleteMenu.prototype.onAdd = function() {
          var deleteMenu = this;
          var 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', function(e) {
          if (e.target != deleteMenu.div_) {
          deleteMenu.close();
          }
          }, true);
          };

          DeleteMenu.prototype.onRemove = function() {
          google.maps.event.removeListener(this.divListener_);
          this.div_.parentNode.removeChild(this.div_);

          // clean up
          this.set('position');
          this.set('path');
          this.set('vertex');
          };

          DeleteMenu.prototype.close = function() {
          this.setMap(null);
          };

          DeleteMenu.prototype.draw = function() {
          var position = this.get('position');
          var projection = this.getProjection();

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

          var 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.
          */
          DeleteMenu.prototype.open = function(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.
          */
          DeleteMenu.prototype.removeVertex = function() {
          var path = this.get('path');
          var vertex = this.get('vertex');

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

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

          google.maps.event.addDomListener(window, 'load', initialize);

          #map {
          height: 100%;
          }

          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, .3);
          margin-top: -10px;
          margin-left: 10px;
          cursor: pointer;
          }

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

          <div id="map"></div>
          <!-- Replace the value of the key parameter with your own API key. -->
          <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>








          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54011870%2fprogrammatically-editing-the-path-of-polyline-leaves-a-ghost-line%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            path.j is not a documented property. Don't use undocumented properties, they can (and will) change with each release of the API. Only use documented properties/methods.



            Don't use:



            path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);


            One option is to use:



            path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));


            Like this:



            google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

            function processSetAt(vertex, eventC) {
            // turn off editing
            flightPath.setEditable(false);
            // update the path
            var path = flightPath.getPath();
            path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
            flightPath.setPath(path);
            // turn editing back on
            flightPath.setEditable(true);
            google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
            }


            proof of concept fiddle



            Note that your issue seems to be related to modifying the path of the polyline while it is "editable". The only way I found to remove the "ghost" path was to turn off editing, modify the polyline, then turn editing back on.



            Another option (from the OP's comment):



            Use a flag to avoid an infinite loop on the 'set at' event. Like this:



            google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) { 
            if(!changingPath){
            var path = flightPath.getPath();
            changingPath = true;
            path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
            changingPath = false;
            }
            });


            fiddle



            code snippet:






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

            var map = new google.maps.Map(document.getElementById('map'), mapOptions);

            var 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)
            ];
            var flightPath = new google.maps.Polyline({
            path: flightPlanCoordinates,
            editable: true,
            strokeColor: '#FF0000',
            strokeOpacity: 1.0,
            strokeWeight: 2,
            map: map
            });

            var deleteMenu = new DeleteMenu();

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

            google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

            function processSetAt(vertex, eventC) {
            // turn off editing
            flightPath.setEditable(false);
            // update the path
            var path = flightPath.getPath();
            path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
            flightPath.setPath(path);
            // turn editing back on
            flightPath.setEditable(true);
            google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
            }
            }

            /**
            * A menu that lets a user delete a selected vertex of a path.
            * @constructor
            */
            function DeleteMenu() {
            this.div_ = document.createElement('div');
            this.div_.className = 'delete-menu';
            this.div_.innerHTML = 'Delete';

            var menu = this;
            google.maps.event.addDomListener(this.div_, 'click', function() {
            menu.removeVertex();
            });
            }
            DeleteMenu.prototype = new google.maps.OverlayView();

            DeleteMenu.prototype.onAdd = function() {
            var deleteMenu = this;
            var 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', function(e) {
            if (e.target != deleteMenu.div_) {
            deleteMenu.close();
            }
            }, true);
            };

            DeleteMenu.prototype.onRemove = function() {
            google.maps.event.removeListener(this.divListener_);
            this.div_.parentNode.removeChild(this.div_);

            // clean up
            this.set('position');
            this.set('path');
            this.set('vertex');
            };

            DeleteMenu.prototype.close = function() {
            this.setMap(null);
            };

            DeleteMenu.prototype.draw = function() {
            var position = this.get('position');
            var projection = this.getProjection();

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

            var 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.
            */
            DeleteMenu.prototype.open = function(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.
            */
            DeleteMenu.prototype.removeVertex = function() {
            var path = this.get('path');
            var vertex = this.get('vertex');

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

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

            google.maps.event.addDomListener(window, 'load', initialize);

            #map {
            height: 100%;
            }

            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, .3);
            margin-top: -10px;
            margin-left: 10px;
            cursor: pointer;
            }

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

            <div id="map"></div>
            <!-- Replace the value of the key parameter with your own API key. -->
            <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>








            share|improve this answer






























              0














              path.j is not a documented property. Don't use undocumented properties, they can (and will) change with each release of the API. Only use documented properties/methods.



              Don't use:



              path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);


              One option is to use:



              path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));


              Like this:



              google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

              function processSetAt(vertex, eventC) {
              // turn off editing
              flightPath.setEditable(false);
              // update the path
              var path = flightPath.getPath();
              path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
              flightPath.setPath(path);
              // turn editing back on
              flightPath.setEditable(true);
              google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
              }


              proof of concept fiddle



              Note that your issue seems to be related to modifying the path of the polyline while it is "editable". The only way I found to remove the "ghost" path was to turn off editing, modify the polyline, then turn editing back on.



              Another option (from the OP's comment):



              Use a flag to avoid an infinite loop on the 'set at' event. Like this:



              google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) { 
              if(!changingPath){
              var path = flightPath.getPath();
              changingPath = true;
              path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
              changingPath = false;
              }
              });


              fiddle



              code snippet:






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

              var map = new google.maps.Map(document.getElementById('map'), mapOptions);

              var 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)
              ];
              var flightPath = new google.maps.Polyline({
              path: flightPlanCoordinates,
              editable: true,
              strokeColor: '#FF0000',
              strokeOpacity: 1.0,
              strokeWeight: 2,
              map: map
              });

              var deleteMenu = new DeleteMenu();

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

              google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

              function processSetAt(vertex, eventC) {
              // turn off editing
              flightPath.setEditable(false);
              // update the path
              var path = flightPath.getPath();
              path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
              flightPath.setPath(path);
              // turn editing back on
              flightPath.setEditable(true);
              google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
              }
              }

              /**
              * A menu that lets a user delete a selected vertex of a path.
              * @constructor
              */
              function DeleteMenu() {
              this.div_ = document.createElement('div');
              this.div_.className = 'delete-menu';
              this.div_.innerHTML = 'Delete';

              var menu = this;
              google.maps.event.addDomListener(this.div_, 'click', function() {
              menu.removeVertex();
              });
              }
              DeleteMenu.prototype = new google.maps.OverlayView();

              DeleteMenu.prototype.onAdd = function() {
              var deleteMenu = this;
              var 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', function(e) {
              if (e.target != deleteMenu.div_) {
              deleteMenu.close();
              }
              }, true);
              };

              DeleteMenu.prototype.onRemove = function() {
              google.maps.event.removeListener(this.divListener_);
              this.div_.parentNode.removeChild(this.div_);

              // clean up
              this.set('position');
              this.set('path');
              this.set('vertex');
              };

              DeleteMenu.prototype.close = function() {
              this.setMap(null);
              };

              DeleteMenu.prototype.draw = function() {
              var position = this.get('position');
              var projection = this.getProjection();

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

              var 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.
              */
              DeleteMenu.prototype.open = function(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.
              */
              DeleteMenu.prototype.removeVertex = function() {
              var path = this.get('path');
              var vertex = this.get('vertex');

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

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

              google.maps.event.addDomListener(window, 'load', initialize);

              #map {
              height: 100%;
              }

              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, .3);
              margin-top: -10px;
              margin-left: 10px;
              cursor: pointer;
              }

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

              <div id="map"></div>
              <!-- Replace the value of the key parameter with your own API key. -->
              <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>








              share|improve this answer




























                0












                0








                0







                path.j is not a documented property. Don't use undocumented properties, they can (and will) change with each release of the API. Only use documented properties/methods.



                Don't use:



                path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);


                One option is to use:



                path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));


                Like this:



                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

                function processSetAt(vertex, eventC) {
                // turn off editing
                flightPath.setEditable(false);
                // update the path
                var path = flightPath.getPath();
                path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
                flightPath.setPath(path);
                // turn editing back on
                flightPath.setEditable(true);
                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
                }


                proof of concept fiddle



                Note that your issue seems to be related to modifying the path of the polyline while it is "editable". The only way I found to remove the "ghost" path was to turn off editing, modify the polyline, then turn editing back on.



                Another option (from the OP's comment):



                Use a flag to avoid an infinite loop on the 'set at' event. Like this:



                google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) { 
                if(!changingPath){
                var path = flightPath.getPath();
                changingPath = true;
                path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
                changingPath = false;
                }
                });


                fiddle



                code snippet:






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

                var map = new google.maps.Map(document.getElementById('map'), mapOptions);

                var 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)
                ];
                var flightPath = new google.maps.Polyline({
                path: flightPlanCoordinates,
                editable: true,
                strokeColor: '#FF0000',
                strokeOpacity: 1.0,
                strokeWeight: 2,
                map: map
                });

                var deleteMenu = new DeleteMenu();

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

                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

                function processSetAt(vertex, eventC) {
                // turn off editing
                flightPath.setEditable(false);
                // update the path
                var path = flightPath.getPath();
                path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
                flightPath.setPath(path);
                // turn editing back on
                flightPath.setEditable(true);
                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
                }
                }

                /**
                * A menu that lets a user delete a selected vertex of a path.
                * @constructor
                */
                function DeleteMenu() {
                this.div_ = document.createElement('div');
                this.div_.className = 'delete-menu';
                this.div_.innerHTML = 'Delete';

                var menu = this;
                google.maps.event.addDomListener(this.div_, 'click', function() {
                menu.removeVertex();
                });
                }
                DeleteMenu.prototype = new google.maps.OverlayView();

                DeleteMenu.prototype.onAdd = function() {
                var deleteMenu = this;
                var 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', function(e) {
                if (e.target != deleteMenu.div_) {
                deleteMenu.close();
                }
                }, true);
                };

                DeleteMenu.prototype.onRemove = function() {
                google.maps.event.removeListener(this.divListener_);
                this.div_.parentNode.removeChild(this.div_);

                // clean up
                this.set('position');
                this.set('path');
                this.set('vertex');
                };

                DeleteMenu.prototype.close = function() {
                this.setMap(null);
                };

                DeleteMenu.prototype.draw = function() {
                var position = this.get('position');
                var projection = this.getProjection();

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

                var 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.
                */
                DeleteMenu.prototype.open = function(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.
                */
                DeleteMenu.prototype.removeVertex = function() {
                var path = this.get('path');
                var vertex = this.get('vertex');

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

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

                google.maps.event.addDomListener(window, 'load', initialize);

                #map {
                height: 100%;
                }

                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, .3);
                margin-top: -10px;
                margin-left: 10px;
                cursor: pointer;
                }

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

                <div id="map"></div>
                <!-- Replace the value of the key parameter with your own API key. -->
                <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>








                share|improve this answer















                path.j is not a documented property. Don't use undocumented properties, they can (and will) change with each release of the API. Only use documented properties/methods.



                Don't use:



                path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);


                One option is to use:



                path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));


                Like this:



                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

                function processSetAt(vertex, eventC) {
                // turn off editing
                flightPath.setEditable(false);
                // update the path
                var path = flightPath.getPath();
                path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
                flightPath.setPath(path);
                // turn editing back on
                flightPath.setEditable(true);
                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
                }


                proof of concept fiddle



                Note that your issue seems to be related to modifying the path of the polyline while it is "editable". The only way I found to remove the "ghost" path was to turn off editing, modify the polyline, then turn editing back on.



                Another option (from the OP's comment):



                Use a flag to avoid an infinite loop on the 'set at' event. Like this:



                google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) { 
                if(!changingPath){
                var path = flightPath.getPath();
                changingPath = true;
                path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
                changingPath = false;
                }
                });


                fiddle



                code snippet:






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

                var map = new google.maps.Map(document.getElementById('map'), mapOptions);

                var 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)
                ];
                var flightPath = new google.maps.Polyline({
                path: flightPlanCoordinates,
                editable: true,
                strokeColor: '#FF0000',
                strokeOpacity: 1.0,
                strokeWeight: 2,
                map: map
                });

                var deleteMenu = new DeleteMenu();

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

                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

                function processSetAt(vertex, eventC) {
                // turn off editing
                flightPath.setEditable(false);
                // update the path
                var path = flightPath.getPath();
                path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
                flightPath.setPath(path);
                // turn editing back on
                flightPath.setEditable(true);
                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
                }
                }

                /**
                * A menu that lets a user delete a selected vertex of a path.
                * @constructor
                */
                function DeleteMenu() {
                this.div_ = document.createElement('div');
                this.div_.className = 'delete-menu';
                this.div_.innerHTML = 'Delete';

                var menu = this;
                google.maps.event.addDomListener(this.div_, 'click', function() {
                menu.removeVertex();
                });
                }
                DeleteMenu.prototype = new google.maps.OverlayView();

                DeleteMenu.prototype.onAdd = function() {
                var deleteMenu = this;
                var 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', function(e) {
                if (e.target != deleteMenu.div_) {
                deleteMenu.close();
                }
                }, true);
                };

                DeleteMenu.prototype.onRemove = function() {
                google.maps.event.removeListener(this.divListener_);
                this.div_.parentNode.removeChild(this.div_);

                // clean up
                this.set('position');
                this.set('path');
                this.set('vertex');
                };

                DeleteMenu.prototype.close = function() {
                this.setMap(null);
                };

                DeleteMenu.prototype.draw = function() {
                var position = this.get('position');
                var projection = this.getProjection();

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

                var 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.
                */
                DeleteMenu.prototype.open = function(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.
                */
                DeleteMenu.prototype.removeVertex = function() {
                var path = this.get('path');
                var vertex = this.get('vertex');

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

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

                google.maps.event.addDomListener(window, 'load', initialize);

                #map {
                height: 100%;
                }

                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, .3);
                margin-top: -10px;
                margin-left: 10px;
                cursor: pointer;
                }

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

                <div id="map"></div>
                <!-- Replace the value of the key parameter with your own API key. -->
                <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>








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

                var map = new google.maps.Map(document.getElementById('map'), mapOptions);

                var 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)
                ];
                var flightPath = new google.maps.Polyline({
                path: flightPlanCoordinates,
                editable: true,
                strokeColor: '#FF0000',
                strokeOpacity: 1.0,
                strokeWeight: 2,
                map: map
                });

                var deleteMenu = new DeleteMenu();

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

                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

                function processSetAt(vertex, eventC) {
                // turn off editing
                flightPath.setEditable(false);
                // update the path
                var path = flightPath.getPath();
                path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
                flightPath.setPath(path);
                // turn editing back on
                flightPath.setEditable(true);
                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
                }
                }

                /**
                * A menu that lets a user delete a selected vertex of a path.
                * @constructor
                */
                function DeleteMenu() {
                this.div_ = document.createElement('div');
                this.div_.className = 'delete-menu';
                this.div_.innerHTML = 'Delete';

                var menu = this;
                google.maps.event.addDomListener(this.div_, 'click', function() {
                menu.removeVertex();
                });
                }
                DeleteMenu.prototype = new google.maps.OverlayView();

                DeleteMenu.prototype.onAdd = function() {
                var deleteMenu = this;
                var 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', function(e) {
                if (e.target != deleteMenu.div_) {
                deleteMenu.close();
                }
                }, true);
                };

                DeleteMenu.prototype.onRemove = function() {
                google.maps.event.removeListener(this.divListener_);
                this.div_.parentNode.removeChild(this.div_);

                // clean up
                this.set('position');
                this.set('path');
                this.set('vertex');
                };

                DeleteMenu.prototype.close = function() {
                this.setMap(null);
                };

                DeleteMenu.prototype.draw = function() {
                var position = this.get('position');
                var projection = this.getProjection();

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

                var 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.
                */
                DeleteMenu.prototype.open = function(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.
                */
                DeleteMenu.prototype.removeVertex = function() {
                var path = this.get('path');
                var vertex = this.get('vertex');

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

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

                google.maps.event.addDomListener(window, 'load', initialize);

                #map {
                height: 100%;
                }

                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, .3);
                margin-top: -10px;
                margin-left: 10px;
                cursor: pointer;
                }

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

                <div id="map"></div>
                <!-- Replace the value of the key parameter with your own API key. -->
                <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>





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

                var map = new google.maps.Map(document.getElementById('map'), mapOptions);

                var 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)
                ];
                var flightPath = new google.maps.Polyline({
                path: flightPlanCoordinates,
                editable: true,
                strokeColor: '#FF0000',
                strokeOpacity: 1.0,
                strokeWeight: 2,
                map: map
                });

                var deleteMenu = new DeleteMenu();

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

                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

                function processSetAt(vertex, eventC) {
                // turn off editing
                flightPath.setEditable(false);
                // update the path
                var path = flightPath.getPath();
                path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
                flightPath.setPath(path);
                // turn editing back on
                flightPath.setEditable(true);
                google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
                }
                }

                /**
                * A menu that lets a user delete a selected vertex of a path.
                * @constructor
                */
                function DeleteMenu() {
                this.div_ = document.createElement('div');
                this.div_.className = 'delete-menu';
                this.div_.innerHTML = 'Delete';

                var menu = this;
                google.maps.event.addDomListener(this.div_, 'click', function() {
                menu.removeVertex();
                });
                }
                DeleteMenu.prototype = new google.maps.OverlayView();

                DeleteMenu.prototype.onAdd = function() {
                var deleteMenu = this;
                var 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', function(e) {
                if (e.target != deleteMenu.div_) {
                deleteMenu.close();
                }
                }, true);
                };

                DeleteMenu.prototype.onRemove = function() {
                google.maps.event.removeListener(this.divListener_);
                this.div_.parentNode.removeChild(this.div_);

                // clean up
                this.set('position');
                this.set('path');
                this.set('vertex');
                };

                DeleteMenu.prototype.close = function() {
                this.setMap(null);
                };

                DeleteMenu.prototype.draw = function() {
                var position = this.get('position');
                var projection = this.getProjection();

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

                var 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.
                */
                DeleteMenu.prototype.open = function(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.
                */
                DeleteMenu.prototype.removeVertex = function() {
                var path = this.get('path');
                var vertex = this.get('vertex');

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

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

                google.maps.event.addDomListener(window, 'load', initialize);

                #map {
                height: 100%;
                }

                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, .3);
                margin-top: -10px;
                margin-left: 10px;
                cursor: pointer;
                }

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

                <div id="map"></div>
                <!-- Replace the value of the key parameter with your own API key. -->
                <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jan 3 at 20:11

























                answered Jan 3 at 16:58









                geocodezipgeocodezip

                127k10146176




                127k10146176
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54011870%2fprogrammatically-editing-the-path-of-polyline-leaves-a-ghost-line%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Mossoró

                    Error while reading .h5 file using the rhdf5 package in R

                    Pushsharp Apns notification error: 'InvalidToken'