我怎样才能用 Leaflet.draw 抓取一系列标记?
How can I grab a selection of markers with Leaflet.draw?
上下文:
我制作了一张地图,并在其中填充了大约 300 个随机标记。我可以通过单击弹出窗口中的 link 来 'select' 标记,并激活一个选择以显示来自的数据。我也有 Leaflet.draw 插件来绘制圆形、矩形和自定义形状等形状,我想用它来 'select' 几个标记。
问题
如何抓取落在绘制的 leaflet.draw 形状内的标记的传单标记对象,以便进行编辑?我似乎无法进行选择,它要么选择 none 个标记,要么选择所有标记。
代码片段,从不必要的代码中删除:
const drawControl = new L.Control.Draw({
draw: {
marker : false,
polygon : true,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
});
const map = L.map('map', {
layers: [streets, light]
}).setView([CONFIG.MAP.LATITUDE, CONFIG.MAP.LONGITUDE], CONFIG.MAP.ZOOMLEVEL)
map.addControl(drawControl);
map.on(L.Draw.Event.DRAWSTOP, e => {
const hello = e.target;
console.log(hello);
e.target.eachLayer(layer => {
if (layer.options.icon) {
console.log(layer);
}
});
});
您想要的大部分内容都可以使用 Leaflet 的实用方法轻松完成。如果你想用像 L.Polygon
这样的复杂形状来做到这一点,你将需要像 TurfJS
这样的东西
对于L.Circle
,您需要计算圆心之间的距离并将其与半径进行比较:
var marker = new L.Marker(...),
circle = new L.Circle(...);
var contains = circle.getLatLng().distanceTo(marker.getLatLng()) < circle.getRadius();
对于L.Rectangle
,您需要获取它的边界对象并使用包含方法:
var marker = new L.Marker(...),
rectangle = new L.Rectangle(...);
var contains = rectangle.getBounds().contains(marker.getLatLng());
对于复杂的多边形,我会使用 Turf,但那里有更多的库和插件。下面是一个使用 Turf 的 inside
方法的示例。它以 GeoJSON 点和多边形特征作为参数,因此请注意转换:
var marker = new L.Marker(...),
polygon = new L.Polygon(...);
var contains = turf.inside(marker.toGeoJSON(), polygon.toGeoJSON());
您可以将它们包装到各自的方便方法中 class:
L.Polygon.include({
contains: function (latLng) {
return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
}
});
L.Rectangle.include({
contains: function (latLng) {
return this.getBounds().contains(latLng);
}
});
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
var marker = new L.Marker(...),
polygon = new L.Polygon(...),
rectangle = new L.Rectangle(...),
circle = new L.Circle(...);
polygon.contains(marker.getLatLng());
rectangle.contains(marker.getLatLng());
circle.contains(marker.getLatLng());
请注意,如果您实现了多边形方法,则不需要矩形方法。由于矩形是从多边形扩展而来的,它将继承该方法。我把它留在那儿是为了完整。
现在迭代你的标记并比较它们很容易:
map.on(L.Draw.Event.CREATED, function (e) {
markers.eachLayer(function (marker) {
if (!e.layer.contains(marker.getLatLng())) {
marker.remove();
}
});
});
希望对您有所帮助,这是一个有效的片段:
var map = new L.Map('leaflet', {
'center': [0, 0],
'zoom': 0
});
var markers = new L.LayerGroup().addTo(map);
for (var i = 0; i < 300; i++) {
var marker = new L.Marker([
(Math.random() * (90 - -90) + -90).toFixed(5) * 1,
(Math.random() * (180 - -180) + -180).toFixed(5) * 1
]).addTo(markers);
}
new L.Control.Draw({
draw: {
marker : false,
polygon : true,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
}).addTo(map);
L.Polygon.include({
contains: function (latLng) {
return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
}
});
L.Rectangle.include({
contains: function (latLng) {
return this.getBounds().contains(latLng);
}
});
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
map.on(L.Draw.Event.CREATED, function (e) {
markers.eachLayer(function (marker) {
if (!e.layer.contains(marker.getLatLng())) {
marker.remove();
}
});
});
body {
margin: 0;
}
html, body, #leaflet {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<title>Leaflet 1.0.3</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
</head>
<body>
<div id="leaflet"></div>
<script type="application/javascript" src="//unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
<script type="application/javascript" src="//unpkg.com/@turf/turf@latest/turf.min.js"></script>
</body>
</html>
感谢@iH8 提供的精彩示例。我进一步避免了
的重复
markers.eachLayer(function (marker) {
...
}
并使用标记数组代替其他方法扩展包装器:
首先我注意到 LayerGroup
有一个对象,其键值包含所有标记。我只是使用该对象创建一个标记数组:
// In the on draw event
...
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
...
function jsonToArray(jsonObject) {
var result = [];
var keys = Object.keys(jsonObject);
keys.forEach(function (key) {
result.push(jsonObject[key]);
});
return result;
}
然后我用修改后的 contains()
方法重新使用包装器:
L.Rectangle.include({
// Single marker case
contains: function (marker) {
return this.getBounds().contains(marker.getLatLng());
},
// Array of markers
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getBounds().contains(marker.getLatLng()));
})
return markersContained;
}
});
L.Circle.include({
contains: function (marker) {
return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
})
return markersContained;
}
});
最后在绘制事件中,我检查我的标记是否包含在 :
map.on(L.Draw.Event.CREATED, function (geometry) {
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
var result = geometry.layer.contains(markers);
console.log('result => ', result);
});
function jsonToArray(jsonObject) {
var result = [];
var keys = Object.keys(jsonObject);
keys.forEach(function (key) {
result.push(jsonObject[key]);
});
return result;
}
var map = new L.Map('leaflet', {
'center': [0, 0],
'zoom': 0
});
var layerGroup = new L.LayerGroup().addTo(map);
for (var i = 0; i < 10; i++) {
var marker = new L.Marker([
(Math.random() * (90 - -90) + -90).toFixed(5) * 1,
(Math.random() * (180 - -180) + -180).toFixed(5) * 1
]).addTo(layerGroup);
}
new L.Control.Draw({
draw: {
marker : false,
polygon : false,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
}).addTo(map);
// Define contains() method for each geometry
L.Rectangle.include({
contains: function (marker) {
return this.getBounds().contains(marker.getLatLng());
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getBounds().contains(marker.getLatLng()));
})
return markersContained;
}
});
L.Circle.include({
contains: function (marker) {
return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
})
return markersContained;
}
});
map.on(L.Draw.Event.CREATED, function (geometry) {
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
var result = geometry.layer.contains(markers);
console.log('result => ', result);
});
body {
margin: 0;
}
html, body, #leaflet {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<title>Leaflet 1.0.3</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
</head>
<body>
<div id="leaflet"></div>
<script type="application/javascript" src="//unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
</body>
</html>
我用过:
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
边上不在圆内的点也被判断
上下文:
我制作了一张地图,并在其中填充了大约 300 个随机标记。我可以通过单击弹出窗口中的 link 来 'select' 标记,并激活一个选择以显示来自的数据。我也有 Leaflet.draw 插件来绘制圆形、矩形和自定义形状等形状,我想用它来 'select' 几个标记。
问题
如何抓取落在绘制的 leaflet.draw 形状内的标记的传单标记对象,以便进行编辑?我似乎无法进行选择,它要么选择 none 个标记,要么选择所有标记。
代码片段,从不必要的代码中删除:
const drawControl = new L.Control.Draw({
draw: {
marker : false,
polygon : true,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
});
const map = L.map('map', {
layers: [streets, light]
}).setView([CONFIG.MAP.LATITUDE, CONFIG.MAP.LONGITUDE], CONFIG.MAP.ZOOMLEVEL)
map.addControl(drawControl);
map.on(L.Draw.Event.DRAWSTOP, e => {
const hello = e.target;
console.log(hello);
e.target.eachLayer(layer => {
if (layer.options.icon) {
console.log(layer);
}
});
});
您想要的大部分内容都可以使用 Leaflet 的实用方法轻松完成。如果你想用像 L.Polygon
这样的复杂形状来做到这一点,你将需要像 TurfJS
对于L.Circle
,您需要计算圆心之间的距离并将其与半径进行比较:
var marker = new L.Marker(...),
circle = new L.Circle(...);
var contains = circle.getLatLng().distanceTo(marker.getLatLng()) < circle.getRadius();
对于L.Rectangle
,您需要获取它的边界对象并使用包含方法:
var marker = new L.Marker(...),
rectangle = new L.Rectangle(...);
var contains = rectangle.getBounds().contains(marker.getLatLng());
对于复杂的多边形,我会使用 Turf,但那里有更多的库和插件。下面是一个使用 Turf 的 inside
方法的示例。它以 GeoJSON 点和多边形特征作为参数,因此请注意转换:
var marker = new L.Marker(...),
polygon = new L.Polygon(...);
var contains = turf.inside(marker.toGeoJSON(), polygon.toGeoJSON());
您可以将它们包装到各自的方便方法中 class:
L.Polygon.include({
contains: function (latLng) {
return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
}
});
L.Rectangle.include({
contains: function (latLng) {
return this.getBounds().contains(latLng);
}
});
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
var marker = new L.Marker(...),
polygon = new L.Polygon(...),
rectangle = new L.Rectangle(...),
circle = new L.Circle(...);
polygon.contains(marker.getLatLng());
rectangle.contains(marker.getLatLng());
circle.contains(marker.getLatLng());
请注意,如果您实现了多边形方法,则不需要矩形方法。由于矩形是从多边形扩展而来的,它将继承该方法。我把它留在那儿是为了完整。
现在迭代你的标记并比较它们很容易:
map.on(L.Draw.Event.CREATED, function (e) {
markers.eachLayer(function (marker) {
if (!e.layer.contains(marker.getLatLng())) {
marker.remove();
}
});
});
希望对您有所帮助,这是一个有效的片段:
var map = new L.Map('leaflet', {
'center': [0, 0],
'zoom': 0
});
var markers = new L.LayerGroup().addTo(map);
for (var i = 0; i < 300; i++) {
var marker = new L.Marker([
(Math.random() * (90 - -90) + -90).toFixed(5) * 1,
(Math.random() * (180 - -180) + -180).toFixed(5) * 1
]).addTo(markers);
}
new L.Control.Draw({
draw: {
marker : false,
polygon : true,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
}).addTo(map);
L.Polygon.include({
contains: function (latLng) {
return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
}
});
L.Rectangle.include({
contains: function (latLng) {
return this.getBounds().contains(latLng);
}
});
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
map.on(L.Draw.Event.CREATED, function (e) {
markers.eachLayer(function (marker) {
if (!e.layer.contains(marker.getLatLng())) {
marker.remove();
}
});
});
body {
margin: 0;
}
html, body, #leaflet {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<title>Leaflet 1.0.3</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
</head>
<body>
<div id="leaflet"></div>
<script type="application/javascript" src="//unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
<script type="application/javascript" src="//unpkg.com/@turf/turf@latest/turf.min.js"></script>
</body>
</html>
感谢@iH8 提供的精彩示例。我进一步避免了
的重复markers.eachLayer(function (marker) {
...
}
并使用标记数组代替其他方法扩展包装器:
首先我注意到 LayerGroup
有一个对象,其键值包含所有标记。我只是使用该对象创建一个标记数组:
// In the on draw event
...
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
...
function jsonToArray(jsonObject) {
var result = [];
var keys = Object.keys(jsonObject);
keys.forEach(function (key) {
result.push(jsonObject[key]);
});
return result;
}
然后我用修改后的 contains()
方法重新使用包装器:
L.Rectangle.include({
// Single marker case
contains: function (marker) {
return this.getBounds().contains(marker.getLatLng());
},
// Array of markers
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getBounds().contains(marker.getLatLng()));
})
return markersContained;
}
});
L.Circle.include({
contains: function (marker) {
return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
})
return markersContained;
}
});
最后在绘制事件中,我检查我的标记是否包含在 :
map.on(L.Draw.Event.CREATED, function (geometry) {
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
var result = geometry.layer.contains(markers);
console.log('result => ', result);
});
function jsonToArray(jsonObject) {
var result = [];
var keys = Object.keys(jsonObject);
keys.forEach(function (key) {
result.push(jsonObject[key]);
});
return result;
}
var map = new L.Map('leaflet', {
'center': [0, 0],
'zoom': 0
});
var layerGroup = new L.LayerGroup().addTo(map);
for (var i = 0; i < 10; i++) {
var marker = new L.Marker([
(Math.random() * (90 - -90) + -90).toFixed(5) * 1,
(Math.random() * (180 - -180) + -180).toFixed(5) * 1
]).addTo(layerGroup);
}
new L.Control.Draw({
draw: {
marker : false,
polygon : false,
polyline : false,
rectangle: true,
circle : {
metric: 'metric'
}
},
edit: false
}).addTo(map);
// Define contains() method for each geometry
L.Rectangle.include({
contains: function (marker) {
return this.getBounds().contains(marker.getLatLng());
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getBounds().contains(marker.getLatLng()));
})
return markersContained;
}
});
L.Circle.include({
contains: function (marker) {
return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
},
contains: function (markers) {
var markersContained = [];
markers.forEach(marker => {
markersContained.push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
})
return markersContained;
}
});
map.on(L.Draw.Event.CREATED, function (geometry) {
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers);
var result = geometry.layer.contains(markers);
console.log('result => ', result);
});
body {
margin: 0;
}
html, body, #leaflet {
height: 100%;
}
<!DOCTYPE html>
<html>
<head>
<title>Leaflet 1.0.3</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
<link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
</head>
<body>
<div id="leaflet"></div>
<script type="application/javascript" src="//unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
<script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
</body>
</html>
我用过:
L.Circle.include({
contains: function (latLng) {
return this.getLatLng().distanceTo(latLng) < this.getRadius();
}
});
边上不在圆内的点也被判断