过滤覆盖层的漏洞,然后将其无重复地推送到数据层

Filtering overlay for holes and then pushing it to the Data Layer without duplicates

我在 DrawManager 绘图和将叠加层导出到 GeoJSON 对象时遇到问题。

我可以在 DrawManager 中绘制带孔的多边形,叠加层将显示对象中的孔。问题是将其导出到 DataLayer 时。

数据层使导出 GeoJSON 变得容易。关于漏洞:polygon data layer

map.data.add({
    geometry: new google.maps.Data.Polygon([
    outerCoords,
    innerCoords1,//hole
    innerCoords2, //hole
    ]),
});

如何导出 DrawManager 绘图以适合此模式?

我已经尝试使用数据层上倒带路径的解决方案。但是,我无法将孔 link 到带孔的多边形。它会创建重复项。 DrawingManager 显示数据,但我很难将此数据导出为看起来像绘制的图像。

绘制图像:

输出 GeoJSON 数据:

{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[150.3308896484375,-34.242748228904865],[150.0232724609375,-34.555492148137766],[150.764849609375,-34.70465158215243],[151.0779599609375,-34.27452911659509],[150.3308896484375,-34.242748228904865]]]},"properties":{}},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[150.3308896484375,-34.242748228904865],[150.0232724609375,-34.555492148137766],[150.764849609375,-34.70465158215243],[151.0779599609375,-34.27452911659509],[150.3308896484375,-34.242748228904865]],[[150.8362607421875,-34.41512862111033],[150.35835546875,-34.51476578284105],[150.53413671875,-34.392467230948675],[150.8362607421875,-34.41512862111033]]]},"properties":{}},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[150.3308896484375,-34.242748228904865],[150.0232724609375,-34.555492148137766],[150.764849609375,-34.70465158215243],[151.0779599609375,-34.27452911659509],[150.3308896484375,-34.242748228904865]],[[150.44624609375,-34.35619624254908],[150.237505859375,-34.49213141771243],[150.1606015625,-34.47854784880349],[150.369341796875,-34.29722239841581],[150.44624609375,-34.35619624254908]]]},"properties":{}}]}

绘制输出: 数据没有附加孔,它正在重新创建 [outer,inner] 数据层。

代码片段:

    // This example requires the Drawing library. Include the libraries=drawing
    // parameter when you first load the API. For example:
    // <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBIwzALxUPNbatRBj3Xi1Uhp0fFzwWNBkE&libraries=drawing">
    function initMap() {
        const map = new google.maps.Map(document.getElementById("map"), {
            center: {
                lat: -34.397,
                lng: 150.644
            },
            zoom: 8,
        });
        const drawingManager = new google.maps.drawing.DrawingManager({
            drawingMode: google.maps.drawing.OverlayType.POLYGON,
            drawingControl: true,
            drawingControlOptions: {
                position: google.maps.ControlPosition.TOP_CENTER,
                drawingModes: [
                    google.maps.drawing.OverlayType.POLYGON,
                    google.maps.drawing.OverlayType.CIRCLE
                ],
            },
        });
        var dataLayer = new google.maps.Data();
        drawingManager.setMap(map);
        var overlayArr = [] //Store all completed objects
        var holeArr = [] //Keep track of holes to build polygon with data layer
        google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
            if (e.type === 'polygon') {
                console.log("overlaycomplete start overlayArr.length=" + overlayArr.length);
                var path = e.overlay.getPath().getArray()
                path = rewindRing(path, true);
                var found = false;
                for (var i = 0; i < overlayArr.length; i++) {
                    if (isPolygonInsidePolygon(e.overlay, overlayArr[i])) {
                        found = true;
                        var path = e.overlay.getPath().getArray();
                        path = rewindRing(path, false);
                        overlayArr[i].getPaths().push(new google.maps.MVCArray(path))
                        dataLayer.add(new google.maps.Data.Feature({
                            geometry: new google.maps.Data.Polygon([overlayArr[i].getPath().getArray(), path]) //Store holes as the secondary "outer" to save to GeoJSON
                        }));
                        holeArr.push(overlayArr[i]);
                        e.overlay.setMap(null); //make hole
                        break;
                    }
                }
                if (!found) {
                    overlayArr.push(e.overlay);
                    //This is a duplicate object in the datalayer after a hole is drawn -- how to remove if hole is drawn?
                    dataLayer.add(new google.maps.Data.Feature({
                        geometry: new google.maps.Data.Polygon([e.overlay.getPath().getArray()]) //No holes add normal
                    }));
                    found = false;
                }
            }
            if (e.type === 'circle') {
                dataLayer.add(new google.maps.Data.Feature({
                    properties: {
                        radius: e.overlay.getRadius()
                    },
                    geometry: new google.maps.Data.Point(e.overlay.getCenter())
                }));
            }
        });
    
        google.maps.event.addDomListener(document.getElementById('save'), 'click', function() {
            dataLayer.toGeoJson(function(obj) {
                document.getElementById('geojson').innerHTML = JSON.stringify(obj);
            });
        })
    
        //Helper function
        function isPolygonInsidePolygon(innerPolygon, outerPolygon) {
            var points = innerPolygon.getPath().getArray();
    
            for (var i = 0; i < points.length; i++) {
                if (!google.maps.geometry.poly.containsLocation(points[i], outerPolygon)) {
                    return false;
                }
            }
            return true;
        }
    
        // from https://github.com/mapbox/geojson-rewind/blob/main/index.js
        function rewindRing(ring, dir) {
            var area = 0;
            for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
                area += ((ring[i].lng() - ring[j].lng()) * (ring[j].lat() + ring[i].lat()));
            }
            console.log("area=" + area + " dir=" + dir);
            if (area >= 0 !== !dir)
                ring.reverse();
            return ring;
        }
    }
    /* Always set the map height explicitly to define the size of the div
           * element that contains the map. */

#map {
  height: 100%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Drawing Tools</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <!-- jsFiddle will insert css and js -->
  </head>
  <body>
  <input id="save" value="save" type="button" />
  <div id="geojson"></div>
    <div id="map"></div>

    <!-- Async script executes immediately and must be after any DOM elements used in callback. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=drawing&v=weekly" async></script>
  </body>
</html>

我的建议是在需要导出多边形之前不要将它们添加到 DataLayer。删除在绘制时将多边形添加到 DataLayer 的代码,然后像这样创建导出函数:

  google.maps.event.addDomListener(document.getElementById('export'), 'click', function() {
    for (var i=0; i<overlayArr.length;i++) {
      // for each polygon drawn, get its paths
      var paths = [];
      for (var j=0; j<overlayArr[i].getPaths().getLength();j++) {
        var path = [];
        for (k=0; k<overlayArr[i].getPaths().getAt(j).getLength(); k++) {
          path.push(overlayArr[i].getPaths().getAt(j).getAt(k));
        }
        paths.push(path);
      }
      // create a Data.Polygon
      map.data.add({
        geometry: new google.maps.Data.Polygon(paths)
      });    
    }
    // export the GeoJson from the Data Layer
    map.data.toGeoJson(function(geoJson){
      console.log(geoJson);
      document.getElementById('geoJson').innerHTML = JSON.stringify(geoJson);
    });
  });

proof of concept fiddle

// This example requires the Drawing library. Include the libraries=drawing
    // parameter when you first load the API. For example:
    // <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBIwzALxUPNbatRBj3Xi1Uhp0fFzwWNBkE&libraries=drawing">
    function initMap() {
        const map = new google.maps.Map(document.getElementById("map"), {
            center: {
                lat: -34.397,
                lng: 150.644
            },
            zoom: 8,
        });
        const drawingManager = new google.maps.drawing.DrawingManager({
            drawingMode: google.maps.drawing.OverlayType.POLYGON,
            drawingControl: true,
            drawingControlOptions: {
                position: google.maps.ControlPosition.TOP_CENTER,
                drawingModes: [
                    google.maps.drawing.OverlayType.POLYGON,
                    google.maps.drawing.OverlayType.CIRCLE
                ],
            },
        });
        var dataLayer = new google.maps.Data();
        drawingManager.setMap(map);
        var overlayArr = [] //Store all completed objects
        var holeArr = [] //Keep track of holes to build polygon with data layer
        google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
            if (e.type === 'polygon') {
                console.log("overlaycomplete start overlayArr.length=" + overlayArr.length);
                var path = e.overlay.getPath().getArray()
                path = rewindRing(path, true);
                var found = false;
                for (var i = 0; i < overlayArr.length; i++) {
                    if (isPolygonInsidePolygon(e.overlay, overlayArr[i])) {
                        found = true;
                        var path = e.overlay.getPath().getArray();
                        path = rewindRing(path, false);
                        overlayArr[i].getPaths().push(new google.maps.MVCArray(path))
                        dataLayer.add(new google.maps.Data.Feature({
                            geometry: new google.maps.Data.Polygon([overlayArr[i].getPath().getArray(), path]) //Store holes as the secondary "outer" to save to GeoJSON
                        }));
                        holeArr.push(overlayArr[i]);
                        e.overlay.setMap(null); //make hole
                        break;
                    }
                }
                if (!found) {
                    overlayArr.push(e.overlay);
                    //This is a duplicate object in the datalayer after a hole is drawn -- how to remove if hole is drawn?
                    dataLayer.add(new google.maps.Data.Feature({
                        geometry: new google.maps.Data.Polygon([e.overlay.getPath().getArray()]) //No holes add normal
                    }));
                    found = false;
                }
            }
            if (e.type === 'circle') {
                dataLayer.add(new google.maps.Data.Feature({
                    properties: {
                        radius: e.overlay.getRadius()
                    },
                    geometry: new google.maps.Data.Point(e.overlay.getCenter())
                }));
            }
        });
    
        google.maps.event.addDomListener(document.getElementById('export'), 'click', function() {
            dataLayer.toGeoJson(function(obj) {
                document.getElementById('geoJson').innerHTML = JSON.stringify(obj);
            });
        })
    
        //Helper function
        function isPolygonInsidePolygon(innerPolygon, outerPolygon) {
            var points = innerPolygon.getPath().getArray();
    
            for (var i = 0; i < points.length; i++) {
                if (!google.maps.geometry.poly.containsLocation(points[i], outerPolygon)) {
                    return false;
                }
            }
            return true;
        }
    
        // from https://github.com/mapbox/geojson-rewind/blob/main/index.js
        function rewindRing(ring, dir) {
            var area = 0;
            for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
                area += ((ring[i].lng() - ring[j].lng()) * (ring[j].lat() + ring[i].lat()));
            }
            console.log("area=" + area + " dir=" + dir);
            if (area >= 0 !== !dir)
                ring.reverse();
            return ring;
        }
    }
/* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
#map {
  height: 90%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Drawing Tools</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <!-- jsFiddle will insert css and js -->
  </head>
  <body>
    <input id="export" value="export" type="button" />
    <div id="map"></div>
    <div id="geoJson"></div>

    <!-- Async script executes immediately and must be after any DOM elements used in callback. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=drawing&v=weekly" async></script>
  </body>
</html>