开始
项目上需要在用户端展示周围的商家,比如用户周围5km内的商家,思路是先获取用户的经纬度,然后与商家的经纬度计算出距离是否符合。
环境框架
后端使用关系型数据库,前端使用js、jq。
步骤
1. 获取用户经纬度。
因为是手机端网页,且小程序初始代码中就写好了方法,因此这里给出微信公众号网页和支付宝内网页获取用户地理位置的方式:
- 微信公众号获取用户地理位置
// 微信公众号获取用户地理位置
wx.getLocation({type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'success: function (res) {var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。var speed = res.speed; // 速度,以米/每秒计var accuracy = res.accuracy; // 位置精度}
});
- 支付宝内网页获取用户地理位置
//通过支付宝提供的接口获取用户地理位置
alipay.mobile.public.gis.get
2. 换算最大/最小经纬度。
将用户距离范围圈子转化成最大/最小经纬度。如下图。事实上,这里用户的范围其实是正方形,范围要比预想中的大一些。
* 但是这种方式,需要将距离转化成经纬度数,因为地面其实是个弧度,所以这里要通过求反正弦得到距离相应度数。
可以参考以下代码。
//userlat 用户所在纬度
//userlng 用户所在经度
//distince 用户范围半径
function getLatAndLngScope(userlat,userlng,distince){var r = 6371.393; // 地球半径(km)var lng = userlng;var lat = userlat;var dlng = 2 * Math.asin(Math.sin(distince / (2 * r)) / Math.cos(lat * Math.PI / 180));dlng = dlng * 180 / Math.PI;var dlat = distince / r;dlat = dlat * 180 / Math.PI;return {minlat:lat - dlat,maxlat:lat + dlat,minlng:lng - dlng,maxlng:lng + dlng};}
3.检索符合条件商家。
商家注册时会要求填写经纬度并且保存,这时通过条件对比,即可筛选出合适的商家们。
sql语句:
*** where lat >= minlat
and lat <= maxlat
and lng >= minlng
and lng <= maxlng
* 如果想要更好的准确度,在拉取这些商家后,通过循环迭代,使用商家和用户的经纬度,算出他们之间的距离,将距离大于预设的这部分商家剔除。可以参考以下代码。
// 根据经纬度计算距离,参数分别为第一点的纬度,经度;第二点的纬度,经度function getDistanceByLatAndLng(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)));s = s * 6378.137;s = Math.round(s * 10000) / 10000;var distance = s;var distance_str = "";if (parseInt(distance) >= 1) {distance_str = distance.toFixed(1) + "km";} else {distance_str = distance * 1000 + "m";}return s;}//此代码参考于 https://www.cnblogs.com/feiquan/p/11338691.html
示例
以微信公众号页面做个demo
var wantDistance = 5;//用户范围5km内
wx.ready(function(){wx.getLocation({type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'success: function (res) {var userlat= res.latitude; // 纬度,浮点数,范围为90 ~ -90var userlng= res.longitude; // 经度,浮点数,范围为180 ~ -180。var scope = getLatAndLngScope(userlat,userlng,wantDistance);$.ajax({ //以下简写url: '**/getStoresByScope', //访问后台换取方形范围内商家data: scope,success:function(e){var storelist = e.storelist;for(var n in storelist ){//若是精度要求较高(其实没必要),可以进一步筛选出圆形范围内的商家。如下:var store = storelist[n];var realDistance = getDistanceByLatAndLng(store.lat,store.lng,userlat,userlng);if(realDistance>wantDistance ){continue;}showstore(store);//展示商家,此处跳出结束。}} });}});
});