Javascript 在 Google Maps API v3 中修改多边形后的事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12515748/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Event after modifying polygon in Google Maps API v3
提问by Thomas
I made a mapping application that uses the drawing manager (and implements selectable shapes). The program works as follows: when finishing drawing the polygon after clicking a button a path, is mapped on the polygon.
我制作了一个使用绘图管理器(并实现可选形状)的地图应用程序。该程序的工作原理如下:单击按钮后完成绘制多边形时,将在多边形上映射一条路径。
When the polygon is edited after this process I want the mapping function to be called again. However I can't get this part working:
在此过程之后编辑多边形时,我希望再次调用映射函数。但是我无法让这部分工作:
I tried using following code, but I always get an error because no shape is selected yet when this listener is added. What can I do?
我尝试使用以下代码,但我总是收到错误消息,因为添加此侦听器时尚未选择任何形状。我能做什么?
google.maps.event.addListener(selectedShape, 'set_at', function() {
console.log("test");
});
google.maps.event.addListener(selectedShape, 'insert_at', function() {
console.log("test");
});
Important pieces of code:
重要的代码片段:
function showDrawingManager(){
var managerOptions = {
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [google.maps.drawing.OverlayType.MARKER, google.maps.drawing.OverlayType.POLYLINE, google.maps.drawing.OverlayType.POLYGON]
},
markerOptions: {
editable: true,
icon: '/largeTDGreenIcons/blank.png'
},
polygonOptions: {
fillColor: "#1E90FF",
strokeColor: "#1E90FF",
},
polylineOptions: {
strokeColor: "#FF273A"
}
}
var drawingManager = new google.maps.drawing.DrawingManager(managerOptions);
drawingManager.setMap(map);
return drawingManager;
}
function clearSelection() {
if (selectedShape) {
console.log("clearSelection");
selectedShape.setEditable(false);
selectedShape = null;
numberOfShapes--;
}
}
function setSelection(shape) {
console.log("setSelection");
clearSelection();
selectedShape = shape;
shape.setEditable(true);
numberOfShapes++;
//getInformation(shape);
}
function initialize(){
//....
var drawingManager = showDrawingManager();
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
if (e.type != google.maps.drawing.OverlayType.MARKER) {
// Switch back to non-drawing mode after drawing a shape.
drawingManager.setDrawingMode(null);
// Add an event listener that selects the newly-drawn shape when the user
// mouses down on it.
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, 'click', function() {
setSelection(newShape);
});
setSelection(newShape);
}
});
回答by Thomas
I solved it by calling .getPath() and putting the listener inside the listener which is called every time a shape is clicked. I think the Google API documentation is not very clear on how to use the set_at so it may be useful for other people too.
我通过调用 .getPath() 并将侦听器放入每次单击形状时调用的侦听器来解决它。我认为 Google API 文档对如何使用 set_at 不是很清楚,因此它可能对其他人也有用。
// Add an event listener that selects the newly-drawn shape when the user
// mouses down on it.
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, 'click', function() {
google.maps.event.addListener(newShape.getPath(), 'set_at', function() {
console.log("test");
});
google.maps.event.addListener(newShape.getPath(), 'insert_at', function() {
console.log("test");
});
setSelection(newShape);
});
回答by Raza Ahmed
google.maps.event.addListener(yourPolygon.getPath(), 'insert_at', function(index, obj) {
//polygon object: yourPolygon
});
google.maps.event.addListener(yourPolygon.getPath(), 'set_at', function(index, obj) {
//polygon object: yourPolygon
});
The above code is working for me. Where set_at
is fired when we modify a polygon area from a highlighted dot (edges) and insert_at
is fired when we drag point that is between highlighted edges.
上面的代码对我有用。set_at
当我们从突出显示的点(边)修改多边形区域时触发where,insert_at
当我们拖动突出显示边缘之间的点时触发。
I used them in the polygoncomplete
event and after loading a polygon from the database. It is working fine for them.
我在polygoncomplete
事件中和从数据库加载多边形后使用它们。这对他们来说很好。
回答by chrismarx
To avoid the problems mentioned with set_at and dragging, I added the following, which disables event broadcasting for set_at when the drawing is being dragged. I created a class that extends the polygon class, and added this method:
为避免 set_at 和拖动中提到的问题,我添加了以下内容,在拖动绘图时禁用 set_at 的事件广播。我创建了一个扩展多边形类的类,并添加了这个方法:
ExtDrawingPolygon.prototype.enableCoordinatesChangedEvent = function(){
var me = this,
superClass = me.superClass,
isBeingDragged = false,
triggerCoordinatesChanged = function(){
//broadcast normalized event
google.maps.event.trigger(superClass, 'coordinates_changed');
};
// If the overlay is being dragged, set_at gets called repeatedly,
// so either we can debounce that or ignore while dragging,
// ignoring is more efficient.
google.maps.event.addListener(superClass, 'dragstart', function(){
isBeingDragged = true;
});
// If the overlay is dragged
google.maps.event.addListener(superClass, 'dragend', function(){
triggerCoordinatesChanged();
isBeingDragged = false;
});
// Or vertices are added to any of the possible paths, or deleted
var paths = superClass.getPaths();
paths.forEach(function(path, i){
google.maps.event.addListener(path, "insert_at", function(){
triggerCoordinatesChanged();
});
google.maps.event.addListener(path, "set_at", function(){
if(!isBeingDragged){
triggerCoordinatesChanged();
}
});
google.maps.event.addListener(path, "remove_at", function(){
triggerCoordinatesChanged();
});
});
};
It added a "coordinates_changed" event to the polygon itself, so other code can just listen for a nice, single, simplified event.
它向多边形本身添加了一个“coordinates_changed”事件,因此其他代码可以只侦听一个不错的、单一的、简化的事件。
回答by Karol Odachowski
Starting from chrismarx's answer, below is an example of using a new event in TypeScript. I have done a small change of removing superclass and changing references to "me", because there was a problem with undefined reference.
从chrismarx's answer 开始,下面是在 TypeScript 中使用新事件的示例。我做了一个小的更改,删除超类并更改对“我”的引用,因为未定义引用存在问题。
At the top of your file or global configuration file, etc., use:
在您的文件或全局配置文件等的顶部,使用:
declare global {
module google.maps {
interface Polygon {
enableCoordinatesChangedEvent();
}
}
}
Then define extension:
然后定义扩展:
google.maps.Polygon.prototype.enableCoordinatesChangedEvent = function () {
var me = this,
isBeingDragged = false,
triggerCoordinatesChanged = function () {
// Broadcast normalized event
google.maps.event.trigger(me, 'coordinates_changed');
};
// If the overlay is being dragged, set_at gets called repeatedly,
// so either we can debounce that or igore while dragging,
// ignoring is more efficient
google.maps.event.addListener(me, 'dragstart', function () {
isBeingDragged = true;
});
// If the overlay is dragged
google.maps.event.addListener(me, 'dragend', function () {
triggerCoordinatesChanged();
isBeingDragged = false;
});
// Or vertices are added to any of the possible paths, or deleted
var paths = me.getPaths();
paths.forEach(function (path, i) {
google.maps.event.addListener(path, "insert_at", function () {
triggerCoordinatesChanged();
});
google.maps.event.addListener(path, "set_at", function () {
if (!isBeingDragged) {
triggerCoordinatesChanged();
}
});
google.maps.event.addListener(path, "remove_at", function () {
triggerCoordinatesChanged();
});
});
};
Finally call extension and add listener:
最后调用扩展并添加侦听器:
google.maps.event.addListener(drawingManager, 'overlaycomplete', function (event) {
event.overlay.enableCoordinatesChangedEvent();
google.maps.event.addListener(event.overlay, 'coordinates_changed', function (index, obj) {
// Polygon object: yourPolygon
console.log('coordinates_changed');
});
});
回答by Erich
Starting from Thomas' answer, here is an implementation that enables edits to overlays created with DrawingManager
, as well as to Feature
s added from GeoJSON.
从 Thomas 的回答开始,这里有一个实现,它允许对使用创建的覆盖进行编辑DrawingManager
,以及Feature
从 GeoJSON 添加的 s。
The main struggle for me was using the google.maps
-prefixed overlay types created by DrawingManager
alongside similarly named google.maps.Data
Feature
types created by addFromGeoJson()
. Ultimately I ignored the built-in Data
object in favor storing everything as a re-created overlay, setting edit event listeners, and then calling setMap()
on them individually as they were drawn. The originally drawn overlays and loaded features are discarded.
对我来说,主要的斗争使用是google.maps
通过创建-prefixed覆盖类型DrawingManager
一起类似命名google.maps.Data
Feature
的创建类型addFromGeoJson()
。最终我忽略了内置Data
对象,而是将所有内容存储为重新创建的叠加层,设置编辑事件侦听器,然后setMap()
在绘制它们时单独调用它们。最初绘制的叠加层和加载的要素将被丢弃。
The process looks something like this:
该过程如下所示:
- Initialize the map.
- Add an
addfeature
event listener to detect whenever a feature is added. This will get fired duringaddGeoJson()
for eachFeature
, getting its corresponding overlay type and geometry and passing them to a utility functionaddFeature()
to create the overlay. - Load any GeoJSON. This will fire the event listener above for every object loaded in.
- Initialize the
DrawingManager
. - Add
{overlay}complete
event listeners for each type of overlay (polygon
,polyline
, andmarker
). When fired, these events first determine if the overlay is valid (e.g. polygons have >= 3 vertices) and then calladdFeature()
, passing in the overlay type and geometry.
- 初始化地图。
- 添加
addfeature
事件侦听器以检测何时添加功能。这将在addGeoJson()
for each期间被触发Feature
,获取其相应的覆盖类型和几何形状并将它们传递给实用程序函数addFeature()
以创建覆盖。 - 加载任何 GeoJSON。这将为加载的每个对象触发上面的事件侦听器。
- 初始化
DrawingManager
. - 添加
{overlay}complete
事件侦听器为每种类型的叠加(polygon
,polyline
,和marker
)。触发时,这些事件首先确定叠加层是否有效(例如,多边形具有 >= 3 个顶点),然后调用addFeature()
,传入叠加层类型和几何形状。
When called, addFeature()
re-creates the overlay and sets all applicable event listeners. Finally, the overlay is stored in the array and displayed on the map.
调用时,addFeature()
重新创建覆盖并设置所有适用的事件侦听器。最后,叠加层存储在数组中并显示在地图上。
// GeoJSON containing previously stored data (optional)
var imported = {
type: "FeatureCollection",
features: [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-73.985603, 40.748429
],
},
properties: {
activity: "Entry",
}
}, ]
};
// this will fill with map data as you import it from geojson or draw
var features = {
polygons: [],
lines: [],
markers: []
};
// set default drawing styles
var styles = {
polygon: {
fillColor: '#00ff80',
fillOpacity: 0.3,
strokeColor: '#008840',
strokeWeight: 1,
clickable: true,
editable: true,
zIndex: 1
},
polyline: {
strokeColor: '#ffff00',
strokeWeight: 3,
clickable: true,
editable: true,
zIndex: 2
},
marker: {
clickable: true,
draggable: true,
zIndex: 3
}
}
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: 40.748429,
lng: -73.985603
},
zoom: 18,
noClear: true,
mapTypeId: 'satellite',
navigationControl: true,
mapTypeControl: false,
streetViewControl: false,
tilt: 0
});
// add this listener BEFORE loading from GeoJSON
map.data.addListener('addfeature', featureAdded);
// load map features from geojson
map.data.addGeoJson(imported);
// initialize drawing tools
var drawingManager = new google.maps.drawing.DrawingManager({
// uncomment below line to set default drawing mode
// drawingMode: 'marker',
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: ['polygon', 'polyline', 'marker']
},
polygonOptions: styles.polygon,
polylineOptions: styles.polyline,
markerOptions: styles.marker
});
drawingManager.setMap(map);
// for each drawing mode, set a listener for end of drawing
drawingManager.addListener('polygoncomplete', function(polygon) {
// delete drawing if doesn't have enough points
if (polygon.getPath().getLength() < 3) {
alert('Polygons must have 3 or more points.');
polygon.getPath().clear();
}
// otherwise create new feature and delete drawing
else {
addFeature('Polygon', polygon.getPath());
polygon.setMap(null);
}
});
drawingManager.addListener('polylinecomplete', function(line) {
// delete drawing if doesn't have enough points
if (line.getPath().getLength() < 2) {
alert('Lines must have 2 or more points.');
line.getPath().clear();
}
// otherwise create new feature and delete drawing
else {
addFeature('Polyline', line.getPath());
line.setMap(null);
}
});
drawingManager.addListener('markercomplete', function(marker) {
// point geometries have only one point by definition,
// so create new feature and delete drawing
addFeature('Point', marker.getPosition());
marker.setMap(null);
updateGeoJSON();
});
}
// this function gets called when GeoJSON gets loaded
function featureAdded(e) {
switch (e.feature.getGeometry().getType()) {
case 'Polygon':
addFeature('Polygon', e.feature.getGeometry().getAt(0).getArray());
break;
case 'LineString':
addFeature('Polyline', e.feature.getGeometry().getArray());
break;
case 'Point':
addFeature('Point', e.feature.getGeometry().get());
}
map.data.remove(e.feature);
}
function addFeature(type, path) {
switch (type) {
case 'Polygon':
var polygon = new google.maps.Polygon(styles.polygon);
polygon.setPath(path);
// listeners for detecting geometry changes
polygon.getPath().addListener('insert_at', someFunction)
polygon.getPath().addListener('set_at', someFunction);
polygon.getPath().addListener('remove_at', someFunction);
polygon.getPath().addListener('dragend', someFunction);
// delete vertex using right click
polygon.addListener('rightclick', function(e) {
if (e.vertex == undefined) return;
if (polygon.getPath().getLength() == 3) {
polygon.setMap(null);
features.polygons = features.polygons.filter(isValid);
} else {
polygon.getPath().removeAt(e.vertex);
outputAsGeoJSON();
}
});
// add it to our list of features
features.polygons.push(polygon);
// and display it on the map
polygon.setMap(map);
break;
case 'Polyline':
var line = new google.maps.Polyline(styles.polyline);
line.setPath(path);
line.getPath().addListener('insert_at', someOtherFunction);
line.getPath().addListener('set_at', someOtherFunction);
line.getPath().addListener('remove_at', someOtherFunction);
line.getPath().addListener('dragend', someOtherFunction);
// allow right-click vertex deletion
line.addListener('rightclick', function(e) {
if (e.vertex == undefined) return;
if (line.getPath().getLength() == 2) {
line.setMap(null);
features.lines = features.lines.filter(isValid);
} else {
line.getPath().removeAt(e.vertex);
outputAsGeoJSON();
}
});
// add it to our list of features
features.lines.push(line);
// and display it on the map
line.setMap(map);
break;
case 'Point':
var marker = new google.maps.Marker(styles.marker);
marker.setPosition(path);
// make a splashy entrance
marker.setAnimation(google.maps.Animation.DROP);
// detect modifications
marker.addListener('drag', function(e) {
// unnecessary bouncing just to throw you off
marker.setAnimation(google.maps.Animation.BOUNCE);
});
marker.addListener('dragend', function(e) {
// make the bouncing stop
marker.setAnimation(null);
})
// allow right-click deletion
marker.addListener('rightclick', function(e) {
marker.setMap(null);
features.markers = features.markers.filter(isValid);
outputAsGeoJSON();
});
// add it to our list of features
features.markers.push(marker);
// and display it on the map
marker.setMap(map);
break;
}
outputAsGeoJSON();
}
function someFunction() {
// do stuff
}
function someOtherFunction() {
// do other stuff
}
// utility function for reuse any time someone right clicks
function isValid(f) {
return f.getMap() != null;
}
function outputAsGeoJSON() {
// we're only using the Data type here because it can export as GeoJSON
var data = new google.maps.Data;
// add all the polygons in our list of features
features.polygons.forEach(function(polygon, i) {
data.add({
geometry: new google.maps.Data.Polygon([polygon.getPath().getArray()]),
properties: {
description: 'I am a polygon'
}
});
});
// and add all the lines
features.lines.forEach(function(line, i) {
data.add({
geometry: new google.maps.Data.LineString(line.getPath().getArray()),
properties: {
description: 'I am a line'
}
});
});
// and finally any markers
features.markers.forEach(function(marker, i) {
data.add({
geometry: new google.maps.Data.Point(marker.getPosition()),
properties: {
description: 'I am a marker'
}
});
});
// GeoJSONify it
data.toGeoJson(function(json) {
document.getElementById('geojson').value = JSON.stringify(json);
});
}