Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/449.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在Google Maps API v3中修改多边形后发生的事件_Javascript_Events_Google Maps - Fatal编程技术网

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

Javascript 在Google Maps API v3中修改多边形后发生的事件,javascript,events,google-maps,Javascript,Events,Google Maps,我制作了一个使用绘图管理器(并实现可选形状)的映射应用程序。该程序的工作原理如下:在完成绘制多边形时,单击按钮后,路径将映射到多边形上 在此过程之后编辑多边形时,我希望再次调用映射函数。但是,我无法使此部件正常工作: 我尝试使用以下代码,但我总是得到一个错误,因为在添加此侦听器时尚未选择任何形状。我能做什么 google.maps.event.addListener(selectedShape, 'set_at', function() { console.log("test"); })

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

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

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

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

我通过调用.getPath()并将侦听器放在侦听器中解决了这个问题,每次单击形状时都会调用该侦听器。我认为GoogleAPI文档并不是很清楚如何使用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);
});
上面的代码对我有用。其中,当我们从高亮显示的点(边)修改多边形区域时,将激发
set_at
;当我们拖动高亮显示的边之间的点时,将激发
insert_at


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

为了避免与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”事件,因此其他代码可以只侦听一个简单的事件。

从开始,下面是在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');
        });
    });
从Thomas'开始,这里有一个实现,可以编辑使用
DrawingManager
创建的覆盖,以及从GeoJSON添加的
功能

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

该过程如下所示:

  • 初始化映射
  • 添加
    addfeature
    事件侦听器,以便在添加功能时进行检测。这将在每个
    功能的
    addGeoJson()
    过程中触发,获取其相应的覆盖类型和几何图形,并将它们传递给实用程序函数
    addFeature()
    ,以创建覆盖
  • 加载任何GeoJSON。这将为加载的每个对象触发上面的事件侦听器
  • 初始化
    绘图管理器
  • 为每种类型的覆盖(
    多边形
    多段线
    ,和
    标记
    )添加
    {overlay}完整的
    事件侦听器。触发时,这些事件首先确定覆盖是否有效(例如多边形具有>=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);
      });
    }
    
    //包含以前存储的数据的GeoJSON(可选)
    导入的变量={
    类型:“FeatureCollection”,
    特点:[{
    “类型”:“功能”,
    “几何学”:{
    “类型”:“点”,
    “坐标”:[
    -73.985603, 40.748429
    ],
    },
    特性:{
    活动:“进入”,
    }
    }, ]
    };
    //这将在您从geojson或draw导入地图数据时填充地图数据
    变量特征={
    多边形:[],
    行:[],
    标记:[]
    };
    //设置默认图形样式
    变量样式={
    多边形:{
    填充颜色:'#00ff80',
    填充不透明度:0.3,
    strokeColor:“#008840”,
    冲程重量:1,
    可点击:正确,
    是的,
    zIndex:1
    },
    多段线:{
    strokeColor:“#ffff00”,
    冲程重量:3,
    可点击:正确,
    是的,
    zIndex:2
    },
    标记:{
    可点击:正确,
    真的,
    zIndex:3
    }
    }
    var映射;
    函数initMap(){
    map=new google.maps.map(document.getElementById('map'){
    中心:{
    拉脱维亚:40.748429,
    液化天然气:-73.985603
    },
    缩放:18,
    诺克利尔:没错,
    mapTypeId:'卫星',
    导航控制:对,
    mapTypeControl:false,
    街景控制:错误,
    倾斜:0
    });
    //在从GeoJSON加载之前添加此侦听器
    map.data.addListener('addfeature',featureAdded);
    //从geojson加载地图功能
    map.data.addGeoJson(导入);
    //初始化绘图工具
    var drawingManager=new google.maps.drawing.drawingManager({
    //取消行下方的注释以设置默认绘图模式
    //drawingMode:'标记',
    drawingControl:对,
    drawingControlOptions:{
    位置:google.maps.ControlPosition.TOP_CENTER,
    绘图模式:[“多边形”、“多段线”、“标记”]
    },
    多边形选项:styles.polygon,
    多段线选项:样式。多段线,
    标记选项:styles.marker
    });
    drawingManager.setMap(map);
    //对于每个绘图模式,为绘图结束设置侦听器
    drawingManager.addListener('polygoncomplete',函数(多边形){
    //如果没有足够的点,请删除图形
    if(polygon.getPath().getLength()<3){
    警报('多边形必须有3个或更多点');
    polygon.getPath().clear();
    }
    //否则,创建新特征并删除图形
    否则{
    阿德费特
    
    // 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);
      });
    }