openlayes 3 點選,圈選,多邊形選實現
點選、圈選、多邊形選擇也是地圖中比較基礎的功能了,只是一直沒有需求,最近兩天把這個功能從頁面到功能完整的做了一遍。我使用的方法是使用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、最終結果