之前一个项目涉及到GIS方面,使用的是leaflet;要求功能:是在地图上可以动态绘制图形,并筛选展示该图形区域内的标记点;
首先,绘制图形的功能使用了leaflet.draw http://leaflet.github.io/Leaflet.draw/docs/leaflet-draw-latest.html
调用地图监听事件
// 监听绘制完成
map.on(L.Draw.Event.CREATED, function (e) {
var type = e.layerType,
layer = e.layer;
console.log(layer)
drawnItems.addLayer(layer); // 添加图层
for (var i in markers) {
var marker = markers[i];
// console.log(marker)
if(layer._mRadius){ // 判断绘制图形是否为圆形
// 调用函数 得出点到圆心的距离
var distance = geoDistance(marker.position.lat,marker.position.lng, layer._latlng.lat,layer._latlng.lng)
// 判断距离是否小于半径
if (distance*1000 <= layer._mRadius){
console.log(i)
}
}else{
if (polygonFilter(marker.position, layer._latlngs[0])){ // 判断是否在区域内
console.log(i)
}
}
}
});
看了上面的代码就知道,我对绘制图形做了下判断;
因为当时有多边形、矩形、圆形选择绘制,矩形属于特殊多边形,可以共用下面的多边形的判断方式;但圆形判断不适用
/**
* 区域筛选 => 多边形
* @param checkPoint 点坐标(经纬度)
* @param polygonPoints 区域组成坐标(经纬度)
*
*/
function polygonFilter(checkPoint, polygonPoints) {
var counter = 0;
var i;
var xinters;
var p1, p2;
var pointCount = polygonPoints.length;
p1 = polygonPoints[0];
for (i = 1; i <= pointCount; i++) {
p2 = polygonPoints[i % pointCount];
if (
checkPoint.lat > Math.min(p1.lat, p2.lat) &&
checkPoint.lat <= Math.max(p1.lat, p2.lat)
) {
if (checkPoint.lng <= Math.max(p1.lng, p2.lng)) {
if (p1.lat != p2.lat) {
xinters =
(checkPoint.lat - p1.lat) *
(p2.lng - p1.lng) /
(p2.lat - p1.lat) + p1.lng;
if (p1.lng == p2.lng || checkPoint.lng <= xinters) {
counter++;
}
}
}
}
p1 = p2;
}
if (counter % 2 == 0) {
return false;
} else {
return true;
}
}
有了上面的方法,多边形的筛选已经可以了;但该方法不适用于圆形区域的筛选,那圆形区域该怎么筛选呢?
。
。
。
。
。
。
灵光一闪,可以判断点到圆心的距离,然后再跟半径比较大小,不就可以判断点是否在圆内吗
//经纬度转换成三角函数中度分表形式。
function rad(d) {
return d * Math.PI / 180.0;
}
/**
* 计算两个经纬度间的距离
* @param lat1 纬度
* @param lng1 经度
* @param lat2 纬度
* @param lng2 经度
*/
function geoDistance(lat1, lng1, lat2, lng2) {
let radLat1 = rad(lat1);
let radLat2 = rad(lat2);
let a = radLat1 - radLat2;
let b = rad(lng1) - rad(lng2);
let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * 6378.137;// EARTH_RADIUS;
s = Math.round(s * 10000) / 10000; //输出为公里
return s;
}
上面的方法可以得出两个经纬度之间的距离
得出距离了现在可以跟半径比较了,圆半径可以在上面的监听回调得到数据,但这里要注意的是我们需要的是距离半径,不是绘制图形的半径
还有一个注意点:距离单位的换算,上面算经纬度间距离的返回单位是km