点选、圈选、多边形选择也是地图中比较基础的功能了,只是一直没有需求,最近两天把这个功能从页面到功能完整的做了一遍。我使用的方法是使用ol4的API加一些js算法,这里记录一下。
1、需求
点选:点击一个点,弹出模态框设置半径,设置完成后,在地图上绘制点和半径画的圆,选中圆内的设备,并在搜索结果框中展示这些设备。
圈选:直接绘制一个圈选,选中圆圈内的设备,并在搜索结果框中展示这些设备。
多边形选择:绘制一个多边形,选中多边形内的设备,并在搜索结果框中展示这些设备。
2、步骤(大致):
这里都通过绘制draw完成
点选:设置draw的type为Point,绘制结束后,获取绘制的点坐标,并结合模态框中输入的半径绘制圆,遍历要素图层,并根据算法pointInsideCircle(point, circle, r)判断要素是否在圆圈范围内,筛选出圈内的要素。
圈选:设置type为Circle,绘制结束后,获取绘制的圆,遍历要素图层,再根据算法pointInsideCircle(point, circle, r),筛选出圆内的要素。
多边形选择:设置type为Polygon,绘制结束后,获取绘制的多边形,遍历要素图层,再根据算法insidePolygon(points, testPoint),筛选出多边形范围内的要素。
框选:设置draw的type为Circle,并设置geometryFunction为ol.interaction.Draw.createBox(),绘制结束后,获取绘制要素的feature.getExtent(),在根据API中的source.getFeaturesInExtent(extent),获取要素图层中在框内的要素。
注:如果图层内要素过多,可以先获取绘制要素的extent,再根据source.getFeaturesInExtent(extent),获取绘制要素的extent框内的要素,再根据自己的算法筛选出图形范围内的要素。
以圈选为例:
-
var draw =
new ol.interaction.Draw({
-
source: drawSource,
-
type:
"Circle",
-
style:drawStyle
-
});
-
map.addInteraction(draw);
-
-
draw.on(
'drawend',
function(evt){
-
var polygon = evt.feature.getGeometry();
-
setTimeout(
function(){
//如果不设置延迟,范围内要素选中后自动取消选中,具体原因不知道
-
var center = polygon.getCenter(),radius = polygon.getRadius(),extent = polygon.getExtent();
-
var features = vectorLayer.getSource().getFeaturesInExtent(extent);
//先缩小feature的范围
-
var str =
"";
-
for(
var i=
0;i<features.length;i++){
-
var newCoords = features[i].getGeometry().getCoordinates();
-
if(pointInsideCircle(newCoords,center,radius)){
-
selectedFeatures.push(features[i]);
-
str +=
"<div class=\"selectedItem\" onclick='showDeviceOnMap(\""+features[i].getId()+
"\");'>"+features[i].get(
"name")+
"</div>";
-
}
-
}
-
$(
"#selectedInfoContent").html(str);
-
},
300)
-
})
3、算法:判断点是否在多边形范围内、点是否在圆范围内
-
/**
-
* 判断一个点是否在多边形内部
-
* @param points 多边形坐标集合
-
* @param testPoint 测试点坐标
-
* 返回true为真,false为假
-
* */
-
function insidePolygon(points, testPoint){
-
var x = testPoint[
0], y = testPoint[
1];
-
var inside =
false;
-
for (
var i =
0, j = points.length -
1; i < points.length; j = i++) {
-
var xi = points[i][
0], yi = points[i][
1];
-
var xj = points[j][
0], yj = points[j][
1];
-
-
var intersect = ((yi > y) != (yj > y))
-
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
-
if (intersect) inside = !inside;
-
}
-
return inside;
-
}
-
-
/**
-
* 判断一个点是否在圆的内部
-
* @param point 测试点坐标
-
* @param circle 圆心坐标
-
* @param r 圆半径
-
* 返回true为真,false为假
-
* */
-
function pointInsideCircle(point, circle, r) {
-
if (r===
0)
return
false
-
var dx = circle[
0] - point[
0]
-
var dy = circle[
1] - point[
1]
-
return dx * dx + dy * dy <= r * r
-
}
4、最终结果