Event after modifying polygon in Google Maps API v3

前端 未结 5 1771
借酒劲吻你
借酒劲吻你 2020-12-13 19:09

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 clickin

相关标签:
5条回答
  • 2020-12-13 19:14
        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.

    I used them in the polygoncomplete event and after loading a polygon from the database. It is working fine for them.

    0 讨论(0)
  • 2020-12-13 19:17

    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:

     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.

    0 讨论(0)
  • 2020-12-13 19:24

    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.

    // 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);
    });
    
    0 讨论(0)
  • 2020-12-13 19:28

    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.

    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');
            });
        });
    
    0 讨论(0)
  • Starting from Thomas' answer, here is an implementation that enables edits to overlays created with DrawingManager, as well as to Features added from GeoJSON.

    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.

    The process looks something like this:

    1. Initialize the map.
    2. Add an addfeature event listener to detect whenever a feature is added. This will get fired during addGeoJson() for each Feature, getting its corresponding overlay type and geometry and passing them to a utility function addFeature() to create the overlay.
    3. Load any GeoJSON. This will fire the event listener above for every object loaded in.
    4. Initialize the DrawingManager.
    5. Add {overlay}complete event listeners for each type of overlay (polygon, polyline, and marker). When fired, these events first determine if the overlay is valid (e.g. polygons have >= 3 vertices) and then call addFeature(), passing in the overlay type and geometry.

    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.

    // 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/

    0 讨论(0)
提交回复
热议问题