Programmatically editing the path of polyline leaves a ghost line
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>javascript google-maps google-maps-api-3 google-polyline
add a comment |
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>javascript google-maps google-maps-api-3 google-polyline
add a comment |
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>javascript google-maps google-maps-api-3 google-polyline
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
javascript google-maps google-maps-api-3 google-polyline
edited Jan 3 at 17:01
geocodezip
127k10146176
127k10146176
asked Jan 2 at 19:08
AngelAngel
813
813
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
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>add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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>add a comment |
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>add a comment |
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>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>edited Jan 3 at 20:11
answered Jan 3 at 16:58
geocodezipgeocodezip
127k10146176
127k10146176
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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