【问题标题】:Event after modifying polygon in Google Maps API v3在 Google Maps API v3 中修改多边形后的事件
【发布时间】:2012-09-20 15:20:00
【问题描述】:

我制作了一个使用绘图管理器(并实现可选形状)的映射应用程序。程序的工作原理如下:当完成多边形的绘制,点击一个按钮后,一个路径会被映射到多边形上。

在此过程之后编辑多边形时,我希望再次调用映射函数。但是我无法让这部分工作:

我尝试使用以下代码,但我总是收到错误消息,因为添加此侦听器时尚未选择任何形状。我能做什么?

google.maps.event.addListener(selectedShape, 'set_at', function() {
    console.log("test");
});

google.maps.event.addListener(selectedShape, 'insert_at', function() {
    console.log("test");
});

重要的代码片段:

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);
        }
    });

【问题讨论】:

    标签: javascript events google-maps


    【解决方案1】:

    我通过调用 .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);
    });
    

    【讨论】:

    • 这可能适用于某些地图,但请注意,当对象被拖动时,这会触发大量触发事件。对于我的代码,太多无法处理!所以我只好坚持“点击”和“拖拽”事件。
    • 关于 jjwdesign 的评论:我遇到了同样的问题,并通过删除 dragstart 上的事件处理程序并在 dragend 上再次添加它们来解决它。乍一看似乎很有魅力。
    • {overlay}complete 事件监听器中添加监听器就可以了。
    • @erich 这在首次添加项目时有效,但一旦它在地图上并需要编辑,{overlay}complete 事件将不再触发。
    • @DavidMorton 在下面看到我的回答。
    【解决方案2】:
        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
        });
    

    上面的代码对我有用。其中set_at 在我们从突出显示的点(边缘)修改多边形区域时触发,insert_at 在我们拖动突出显示边缘之间的点时触发。

    我在polygoncomplete 事件中以及从数据库加载多边形之后使用了它们。对他们来说效果很好。

    【讨论】:

    • 这里的关键是这些函数必须在polgoncomplete中调用
    • 别忘了remove_at 监听器,它是在单击撤消按钮时触发的,在修改多边形时出现的按钮。
    【解决方案3】:

    为了避免 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();
        });
      });
    };
    

    它向多边形本身添加了一个“coordinates_changed”事件,因此其他代码可以只监听一个漂亮、单一、简化的事件。

    【讨论】:

    • 我已经尝试过了,但仍然出现错误,这与该形状的“鼠标悬停”事件有关。
    • 我在将鼠标悬停在可编辑形状上时收到 Uncaught TypeError: Cannot read property '__e3_' of null 错误,此错误会在一段时间后出现。我可以看到绘图管理器的每个实现中都存在此错误。
    【解决方案4】:

    chrismarx's answer 开始,下面是在 TypeScript 中使用新事件的示例。我做了一些小改动,删除了超类并更改了对“我”的引用,因为未定义的引用存在问题。

    在你的文件或全局配置文件等的顶部,使用:

    declare global {
        module google.maps {
            interface Polygon {
                enableCoordinatesChangedEvent();
            }
        }
    }
    

    然后定义扩展:

    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();
            });
        });
    };
    

    最后调用扩展并添加监听器:

      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');
            });
        });
    

    【讨论】:

    • 不错的代码,但是自定义的“coordinates_changed”和“dragend”有什么区别?不要在拖拽结束时都被解雇吗?
    【解决方案5】:

    从 Thomas 的 answer 开始,这里有一个实现,可以对使用 DrawingManager 创建的叠加层以及从 GeoJSON 添加的 Features 进行编辑。

    对我来说主要的困难是使用DrawingManager 创建的google.maps 前缀覆盖类型以及addFromGeoJson() 创建的类似名称的google.maps.Data Feature 类型。最终我忽略了内置的Data 对象,转而将所有内容存储为重新创建的叠加层,设置编辑事件侦听器,然后在绘制它们时单独调用setMap()。最初绘制的叠加层和加载的特征被丢弃。

    这个过程看起来像这样:

    1. 初始化地图。
    2. 添加addfeature 事件侦听器以检测何时添加功能。这将在addGeoJson() 期间为每个Feature 触发,获取其对应的覆盖类型和几何形状并将它们传递给实用函数addFeature() 以创建覆盖。
    3. 加载任何 GeoJSON。这将为加载的每个对象触发上面的事件侦听器。
    4. 初始化DrawingManager
    5. 为每种覆盖类型(polygonpolylinemarker)添加 {overlay}complete 事件侦听器。触发时,这些事件首先确定叠加层是否有效(例如,多边形的顶点数 >= 3),然后调用 addFeature(),传入叠加层类型和几何图形。

    调用时,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);
      });
    }
    

    https://jsfiddle.net/pqdu05s9/1/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-09
      • 2016-07-20
      • 1970-01-01
      • 1970-01-01
      • 2011-08-24
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多