以编程方式编辑多段线的路径会留下虚线
Programmatically editing the path of polyline leaves a ghost line
我在地图中有一些线,用户可以通过拖动它们的顶点来编辑这些线,发生这种情况时,我会检查用户移动的顶点是否靠近任何其他对象,在这种情况下,线必须附着在那个物体上。
更具体地说,当用户移动线条时,事件 "set_at" 被触发,并且在侦听器调用的函数中,线条以编程方式编辑以附加到最近的对象(如果有)。在该对象存在的情况下,该线会毫无问题地附加到该对象(这意味着该线已正确附加并且可以正常工作)。然而在地图中,用户通过移动原始线生成的线仍然可见,但它是半透明的。当在地图上执行其他操作时,该线最终会消失。
我已尝试清除路径 (path.clear()
)、创建新路径、将其从地图中删除 (setMap(null)
) 并重新放置 (setMap(LocationPicker.map.map
) ).但似乎没有任何效果。
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);
}
}
实际结果:https://cdn.pbrd.co/images/HUCyWwu.png
预期结果:https://cdn.pbrd.co/images/HUCxBfJ.png
代码片段:
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>
path.j
不是记录的 属性。不要使用未记录的属性,它们可以(并且将会)随着 API 的每个版本而改变。仅使用已记录的 properties/methods.
不要使用:
path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
一种选择是使用:
path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
像这样:
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);
}
请注意,您的问题似乎与修改“可编辑”的多段线路径有关。我发现删除“幽灵”路径的唯一方法是关闭编辑,修改多段线,然后重新打开编辑。
另一种选择(来自OP的评论):
使用标志来避免 'set at' 事件的无限循环。像这样:
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
代码片段:
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>
我在地图中有一些线,用户可以通过拖动它们的顶点来编辑这些线,发生这种情况时,我会检查用户移动的顶点是否靠近任何其他对象,在这种情况下,线必须附着在那个物体上。
更具体地说,当用户移动线条时,事件 "set_at" 被触发,并且在侦听器调用的函数中,线条以编程方式编辑以附加到最近的对象(如果有)。在该对象存在的情况下,该线会毫无问题地附加到该对象(这意味着该线已正确附加并且可以正常工作)。然而在地图中,用户通过移动原始线生成的线仍然可见,但它是半透明的。当在地图上执行其他操作时,该线最终会消失。
我已尝试清除路径 (path.clear()
)、创建新路径、将其从地图中删除 (setMap(null)
) 并重新放置 (setMap(LocationPicker.map.map
) ).但似乎没有任何效果。
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);
}
}
实际结果:https://cdn.pbrd.co/images/HUCyWwu.png 预期结果:https://cdn.pbrd.co/images/HUCxBfJ.png
代码片段:
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>
path.j
不是记录的 属性。不要使用未记录的属性,它们可以(并且将会)随着 API 的每个版本而改变。仅使用已记录的 properties/methods.
不要使用:
path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
一种选择是使用:
path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
像这样:
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);
}
请注意,您的问题似乎与修改“可编辑”的多段线路径有关。我发现删除“幽灵”路径的唯一方法是关闭编辑,修改多段线,然后重新打开编辑。
另一种选择(来自OP的评论):
使用标志来避免 'set at' 事件的无限循环。像这样:
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
代码片段:
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>