打卡是很多人每天都要做两次的事情,钉钉很多人都用过,但是应该怎么判断你的位置可不可以打卡呢


我最近在做一个打卡的工具,简略它就是设置一个打卡的地点,允许打卡的范围等,然后提醒某个团体进行打卡,但是只能在设定的范围内打卡,不在范围或者不在打卡时间则打卡失败,因为源代码和软件是公司的东西,这里就写一个大家都玩的小例子来计算一下经纬度间的距离。

计算距离主要需要的数据就是

1、设置的活动地点的经纬度
2、打卡者当前位置的经纬度(这个经纬度有可能会改变,因为打卡者有可能在移动,或者是在没进入范围的时候发起的打卡,避免进入范围之后打卡失败)
得到上面1、2的数据之后,就可以根据计算出的距离≤设置的打卡范围(100米,200米,500米等),则打卡成功
3、地球半径

计算公式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
let PI = Math.PI;
function getDistance(lat1,lng1,lat2,lng2){
var f = getRad((lat1 + lat2)/2);
var g = getRad((lat1 - lat2)/2);
var l = getRad((lng1 - lng2)/2);

var sg = Math.sin(g);
var sl = Math.sin(l);
var sf = Math.sin(f);

var s,c,w,r,d,h1,h2;
var a = EARTH_RADIUS;
var fl = 1/298.257;

sg = sg*sg;
sl = sl*sl;
sf = sf*sf;

s = sg*(1-sl) + (1-sf)*sl;
c = (1-sg)*(1-sl) + sf*sl;

w = Math.atan(Math.sqrt(s/c));
r = Math.sqrt(s*c)/w;
d = 2*w*a;
h1 = (3*r -1)/2/c;
h2 = (3*r +1)/2/s;

return d*(1 + fl*(h1*sf*(1-sg) - h2*(1-sf)*sg));
}
function getRad(d){
return d*PI/180.0;
}

也可以是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
getDistance:function(lat1,lng1,lat2,lng2){
lat1 = lat1 || 0;
lng1 = lng1 || 0;
lat2 = lat2 || 0;
lng2 = lng2 || 0;
var rad1 = lat1 * Math.PI / 180.0;
var rad2 = lat2 * Math.PI / 180.0;
var a = rad1 - rad2;
var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
var r = 637139.3; //地球半径
var distance = r * 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rad1) * Math.cos(rad2) * Math.pow(Math.sin(b / 2), 2)));
return distance;
}

cosbeta通过搜索找到了一个js的计算脚本(其实是google map的计算脚本,应该算是比较准确了),做成了一个根据经纬度计算两点距离的工具,前辈利用google map的经纬度到距离计算的js脚本还原出来的公式是这个样子的


公式中经纬度均用弧度表示,可以参考这里

lat1 lng1 表示A点纬度和经度
lat2 lng2 表示B点纬度和经度

两点纬度之差: a=lat1 – lat2
两点经度之差: b=lng1 - lng2

637139.3为地球半径,单位为米
计算过程为

1
2
3
4
5
6
7
8
9
10
11
12
13
//计算距离,参数分别为第一点的纬度,经度;第二点的纬度,经度
function getDistance(lat1,lng1,lat2,lng2){
var radLat1 = Rad(lat1);
var radLat2 = Rad(lat2);
var a = radLat1 - radLat2;
var b = Rad(lng1) - Rad(lng2);
var 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)))*637139.3;
s = Math.round(s * 10000) / 10000;
return s;
}
function Rad(d){
return d * Math.PI / 180.0;//经纬度转换成三角函数中度分表形式。
}

总之,计算的的精度取决于传入的经纬度的精度,同样的经纬度在百度、腾讯、高德等得到的位置有可能都不一样,不过偏差可以尽量缩小