javascript - 使用 DrawingManager 在 Google 地图多边形中绘制孔
问题描述
到目前为止,我将绘制的对象列表保存到一个数组中
var overlayArr = [] //Store all completed objects
var formattedWithHoles = [] //Store converted collisions
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
overlayArr.push(e.overlay);
overlayArr.forEach(isPolygonInsidePolygon) //Doesn't work right
});
包含所有对象,然后我需要生成一个 GeoJSON,但首先如果一个多边形内部有一个多边形 - 那么它必须被绘制为一个洞
//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;
}
}
//formattedWithHoles.push(...); //Use inner and outer polygon data class?
return true;
}
生成每个对象的 GeoJSON 而不检查碰撞:
google.maps.Polygon.prototype.getGeoJSON = function() {
//GeoJSON format
let geoJSON = {
type: 'Feature',
geometry: {
type: 'Polygon', //MultiPolygon for holes?
coordinates: []
},
properties: {}
};
let paths = this.getPaths().getArray();
for (var path of paths) {
let pathArray = [];
let points = path.getArray();
let firstPoint = false;
for (var point of points) {
if (firstPoint === false) {
firstPoint = point;
}
pathArray.push([point.lng(), point.lat()])
}
pathArray.push([firstPoint.lng(), firstPoint.lat()]);
geoJSON.geometry.coordinates.push(pathArray);
}
//console.log(geoJSON);
return geoJSON;
};
如何结合google.maps.event.addListener(drawingManager, 'overlaycomplete',...)
侦听器来检测碰撞并让它们生成带孔的 geoJSON?
我基本上是在地图上绘制农田,并想在无法耕种的障碍物上打洞,因此 1 个农场可能有多个我需要消除的障碍物。
解决方案
要打孔,如果外多边形是逆时针的,内多边形需要顺时针(缠绕方向),反之亦然。根据文档:
要在多边形内创建一个空白区域,您需要创建两条路径,一条在另一条内部。要创建孔,定义内部路径的坐标必须与定义外部路径的坐标顺序相反。例如,如果外部路径的坐标是顺时针方向,那么内部路径必须是逆时针方向。
相关问题:
一种选择:
- 创建一个函数来控制缠绕方向。下面是来自https://github.com/mapbox/geojson-rewind/blob/main/index.js的修改(获取
google.maps.LatLng
对象数组)版本rewindRing
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;
}
- 当你在另一个多边形中找到一个多边形时,反转它的缠绕方向:
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));
e.overlay.setMap(null);
break;
}
}
if (!found) {
console.log("!found");
overlayArr.push(e.overlay);
}
代码片段:
// 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,
],
},
});
drawingManager.setMap(map);
var overlayArr = [] //Store all completed objects
var formattedWithHoles = [] //Store converted collisions
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
var path = e.overlay.getPath().getArray()
path = rewindRing(path, true);
var newPoly = new google.maps.Polygon({
path: path,
})
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));
e.overlay.setMap(null);
break;
}
}
if (!found) {
overlayArr.push(e.overlay);
}
});
//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;
}
google.maps.Polygon.prototype.getGeoJSON = function() {
//GeoJSON format
let geoJSON = {
type: 'Feature',
geometry: {
type: 'Polygon', //MultiPolygon for holes?
coordinates: []
},
properties: {}
};
let paths = this.getPaths().getArray();
for (var path of paths) {
let pathArray = [];
let points = path.getArray();
let firstPoint = false;
for (var point of points) {
if (firstPoint === false) {
firstPoint = point;
}
pathArray.push([point.lng(), point.lat()])
}
pathArray.push([firstPoint.lng(), firstPoint.lat()]);
geoJSON.geometry.coordinates.push(pathArray);
}
//console.log(geoJSON);
return geoJSON;
};
// 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>
<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>
推荐阅读
- c - 为什么当函数值为 void 时,数字仍然会被编译?C
- reporting-services - SSRS - 使用 javascript 打开超链接
- python - Remove dict in list if samle keys/values in Python
- regex - 为什么我的正则表达式模式的位置会影响匹配?
- azure-blob-storage - 从 Azure 存储下载小文件
- django - Django Rest Framework:带有多个 slug 的 url
- javascript - CRUD 功能,使用 React 和 Firebase 查看已删除项目的历史记录
- c# - Visual C# 标签格式未在秒字段中显示前导零
- javascript - 从无状态子组件更改我的父组件的状态
- python - Python Flask Jinja 如何使用 if else 语句创建动态列