在Google Maps API v3中修改多边形后的事件

问题描述 投票:24回答:5

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

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

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

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
5个回答
27
投票

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

18
投票
    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事件中以及从数据库加载多边形后使用它们。它对他们来说很好。


10
投票

为了避免set_at和拖动中提到的问题,我添加了以下内容,它在拖动绘图时禁用set_at的事件广播。我创建了一个扩展polygon类的类,并添加了这个方法:

 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”事件,因此其他代码可以只监听一个漂亮的单一简化事件。


3
投票

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

0
投票

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

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

该过程看起来像这样:

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

© www.soinside.com 2019 - 2024. All rights reserved.