作为一名前端开发者,在工作中经常会用到地图相关的API,比如百度、高德、腾讯等,但是不同地图平台使用的坐标系可能不一样,这就导致定位时会出现几百米到1000左右的误差,比如在小程序平台获取位置的时候我们可以选择wgs84或者国标gcj02标准,但是如果把这些数据拿到后台用百度地图来显示的话,就会出现几百米的误差,所以就需要对经纬度做一下转换,来抹平各个坐标系之间的差异。
本篇文章不仅会介绍不同坐标系的转换,还会介绍电子围栏的绘制与校验。希望能够帮到有需要的人!
1、电子围栏的绘制
我这里使用的是百度地图,其他地图请参考相关开发者文档
1、地图绘制
地图绘制之前需要先注册一个百度开发者账号,获取一个密钥,然后引入百度地图相关js文件,即可使用百度地图。
var map = new BMap.Map('map'); //创建map实例
var poi = new BMap.Point(116.307852, 40.057031); //地图中心点
map.centerAndZoom(poi, 16);
map.enableScrollWheelZoom(); //是否开启滚轮缩放
2、电子围栏的绘制
//定义一个空数组、用于保存绘制成功后,每个围栏的坐标集合、有一点需要注意的是这里的圆形是由42个坐标点绘制而成,
如果围栏的范围过大,可能精细度不够。
var overlays = [];
var overlaycomplete = function (e) {
overlays.push(e.overlay);
};
var styleOptions = {
strokeColor: "red", //边线颜色。
fillColor: "red", //填充颜色。当参数为空时,圆形将没有填充效果。
strokeWeight: 3, //边线的宽度,以像素为单位。
strokeOpacity: 0.8, //边线透明度,取值范围0 - 1。
fillOpacity: 0.6, //填充的透明度,取值范围0 - 1。
strokeStyle: 'solid' //边线的样式,solid或dashed。
}
//实例化鼠标绘制工具
var drawingManager = new BMapLib.DrawingManager(map, {
isOpen: false, //是否开启绘制模式
enableDrawingTool: true, //是否显示工具栏
drawingToolOptions: {
anchor: BMAP_ANCHOR_TOP_RIGHT, //位置
offset: new BMap.Size(5, 5), //偏离值
},
circleOptions: styleOptions, //圆的样式
polylineOptions: styleOptions, //线的样式
polygonOptions: styleOptions, //多边形的样式
rectangleOptions: styleOptions //矩形的样式
});
//添加鼠标绘制工具监听事件,用于获取绘制结果
drawingManager.addEventListener('overlaycomplete', overlaycomplete);
function clearAll() {
for (var i = 0; i < overlays.length; i++) {
map.removeOverlay(overlays[i]);
}
overlays.length = 0
}
2、电子围栏的校验
这块主要是判断某个坐标是否在已经划定好的电子围栏内,可用于考勤定位打卡等场景!
话不多说,直接放代码!
function isPointInPolygon(point, polygon) {
var pts = polygon;
var N = pts.length;
var boundOrVertex = true;
var intersectCount = 0;
var precision = 2e-10;
var p1, p2;
var p = point;
p1 = pts[0];
for (var i = 1; i <= N; ++i) {
if (p.lat == p1.lat || p.lng == p1.lng) {
return boundOrVertex
}
p2 = pts[i % N];
if (p.lat < Math.min(p1.lat, p2.lat) || p.lat > Math.max(p1.lat, p2.lat)) {
p1 = p2;
continue
}
if (p.lat > Math.min(p1.lat, p2.lat) && p.lat < Math.max(p1.lat, p2.lat)) {
if (p.lng <= Math.max(p1.lng, p2.lng)) {
if (p1.lat == p2.lat && p.lng >= Math.min(p1.lng, p2.lng)) {
return boundOrVertex
}
if (p1.lng == p2.lng) {
if (p1.lng == p.lng) {
return boundOrVertex
} else {
++intersectCount
}
} else {
var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng;
if (Math.abs(p.lng - xinters) < precision) {
return boundOrVertex
}
if (p.lng < xinters) {
++intersectCount
}
}
}
} else {
if (p.lat == p2.lat && p.lng <= p2.lng) {
var p3 = pts[(i + 1) % N];
if (p.lat >= Math.min(p1.lat, p3.lat) && p.lat <= Math.max(p1.lat, p3.lat)) {
++intersectCount
} else {
intersectCount += 2
}
}
}
p1 = p2
}
if (intersectCount % 2 == 0) {
return false
} else {
return true
}
}
这个方法接收两个参数,第一参数是当前坐标,第二个参数绘制电子围栏时拿到数据,直接调用即可。
3、不同坐标系的相互转换
上文中我们绘制电子围栏使用的是百度的API,所有拿到的所有坐标都是BD09标准的,如果我们需要把这个数据拿到其他平台来用的话,必须对其进行转行,比如微信小程序只支持wgs84和gcj02标准。
这里我们可以使用Gcoord这个库,使用方式也非常简单。
1、安装引入
npm install gcoord --save
或者直接在页面中引入:
<script src="https://unpkg.com/gcoord/dist/gcoord.js"></script>
import gcoord from 'gcoord'
或者
const gcoord = require('gcoord')
2、使用Gcoord
var result = gcoord.transform(
[116.403988, 39.914266], // 经纬度坐标
gcoord.WGS84, // 当前坐标系
gcoord.BD09 // 目标坐标系
);
console.log(result);
此方法接收三个参数,如上图所示。
gcoord支持的坐标系也非常广泛、目前支持以下这个,可以满足我们的开发需求!
如果此文对你有帮助,请留下一个免费的关注与点赞,谢谢!