基于微信地理位置的附近商家距离坐标数据查询方法

以前写过一篇微信公众平台里基于地理位置显示商户的文章,不少朋友加了个人QQ,探讨具体的功能细节。mysql

这阵子我恰好有一点时间,特地写了一篇文档分享这方面的东西。git

要解决的问题:sql

1.经过微信公众平台获取用户地理位置(也就是坐标啦,精度和纬度)编程

2.获取到地理位置后,记录用户的坐标缓存

3.计算出当前的用户坐标和数据表里商户的坐标的距离微信

4.距离排序与距离的用户体验显示cookie

好吧,如今咱们开始具体的细节问题解决session

 

1.经过微信公众平台获取用户地理位置微信开发

经过微信获取用户地理位置有两种方式微信公众平台

方式a:此方式必须是服务号,用户进入微信公众号的时候,会向微信服务端推送关于用户的相关信息,若是你设置了微信开发者模式,那么这些信息能接收到用户的相关信息

用户赞成上报地理位置后,每次进入公众号会话时,都会在进入时上报地理位置,上报地理位置以推送XML数据包到开发者填写的URL来实现。

经过这种方式,咱们的服务端接收到的信息格式是这样的

提示:只有服务号才能获取用户地理位置,而且服务号通过认证,而且须要在开发者的接口权限中去【开启】

<xml><ToUserName><![CDATA[gh_f6bce85ce621]]></ToUserName>
<FromUserName><![CDATA[obxLljpChQwixH0mAZYR1ESeWv3Y]]></FromUserName>
<CreateTime>1460636400</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[LOCATION]]></Event>
<Latitude>30.660822</Latitude>
<Longitude>104.066566</Longitude>
<Precision>65.000000</Precision>
</xml>

能够看到其中有元素LatitudeLongitude,获取到了坐标就好说啦

 

方式b:用户访问咱们的微网站的时候,经过微信的JS-SDK模式获取用户的地理位置(服务号订阅号均可以)

什么是JS-SDK呢?

微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。
微信官方描述:经过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时能够直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验

这种方式获取到用户坐标是基于网页的形式得到的,因此用户的地理位置坐标须要经过异步的模式存储到你本身的系统中

这个是经过JS-SDK的部分代码

wx.getLocation({
    type: 'wgs84', // 默认为wgs84的gps坐标,若是要返回直接给openLocation用的火星坐标,可传入'gcj02'
    success: function (res) {
        var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
        var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
        var speed = res.speed; // 速度,以米/每秒计
        var accuracy = res.accuracy; // 位置精度
    }
})

2.获取到地理位置后,记录用户的坐标

用户的坐标获取到后,自行记录到你的系统里,经过缓存也好,session也好,cookie也好,仍是数据表也好随便你

 

3.计算出当前的用户坐标和数据表里商户的坐标的距离

咱们目前来个假设一个获取到坐标

例如个人坐标是:30.664385188806,104.07559730274

表名:merchants

表字段:itemid,title,hits,lat,lng lat是经度 lat是纬度

 

当前要作的工做就是,经过一个稍微复杂的sql语句作一个排序

其中这个sql语句当中有个两个坐标之间的计算公式

公式以下

function rad($d)  
{  
       return $d * 3.1415926535898 / 180.0;  
}  
function GetDistance($lat1, $lng1, $lat2, $lng2)  
{  
   $EARTH_RADIUS = 6378.137;  
   $radLat1 = rad($lat1);   
   $radLat2 = rad($lat2);  
   $a = $radLat1 - $radLat2;  
   $b = rad($lng1) - rad($lng2);  
   $s = 2 * asin(sqrt(pow(sin($a/2),2) +  
    cos($radLat1)*cos($radLat2)*pow(sin($b/2),2)));  
   $s = $s *$EARTH_RADIUS;  
   $s = round($s * 10000) / 10000;
   $s=$s*1000;
   return ceil($s);  
}  

当前使用GetDistance方法只要你带入两个坐标点就能够计算出这两个坐标的的距离,距离精度是以米为单位的

使用这种方法若是用编程语言编写的话,数据计算很是耗时

咱们须要把数据记录所有查询出,而后在内存中经过本身的方法逐条对所有查询出数据集作过滤,而且计算出一个距离字段,而后再作一次排序才会获得想要的结果

虽然这种方法思考逻辑上简单容易实现,可是耗时多了。

我跟倾向于用下面的方法来实现,那就是借助于SQL语句,经过SQL语句的运算把距离和排序一次性解决。

mysql函数计算坐标距离

 

 

其中30.664385188806是你的经度,104.07559730274是你的纬度

如下SQL语句是所有查询并运算出坐标的的语句

select itemid,title,hits,telephone,ROUND(6378.138*2*ASIN(SQRT(POW(SIN((30.664385188806*PI()/180-lat*PI()/180)/2),2)+COS(30.664385188806*PI()/180)*COS(lat*PI()/180)*POW(SIN((104.07559730274*PI()/180-lng*PI()/180)/2),2)))*1000) AS distance
from merchants order by distance

经过以下方式的SQL运行就可查询出相应的距离+排序+多少千米范围的条件检索

下面的检索出5千米范围的语句

select * from (select itemid,title,hits,telephone,
ROUND(6378.138*2*ASIN(SQRT(POW(SIN((30.664385188806*PI()/180-lat*PI()/180)/2),2)+COS(30.664385188806*PI()/180)*COS(lat*PI()/180)*POW(SIN((104.07559730274*PI()/180-lng*PI()/180)/2),2)))*1000) AS distance
from merchants order by distance ) as a where a.distance<=5000

查询结果见下图

 

4.距离排序与距离的用户体验显示

 查询计算出的distance是数字,须要显示的用户体验更好一点

例如:我和这个商家的精确距离是1290米,由于精度的缘由,其实精确距离其实误差很是大,不能显示一个具体的数字 ,因此要优化显示为1.3千米或者1.5千米内的模式更好

我自用的方法是这样的

A方式

//输入distance,而后对数字作优化显示
function mToKm($number){
    if(!is_numeric($number)) return ' ';
    switch ($number){
            case $number>1800&&$number<=2000:
                 $v='2';
            break;
            case $number>1500&&$number<=1800:
                 $v='1.8';
            break;
            case $number>1200&&$number<=1500:
                 $v='1.5';
            break;
            case $number>1000&&$number<=1200:
                 $v='1.2';
            break;
            case $number>900&&$number<=1000:
                 $v='1';
            break;
            default:
                $v=ceil($number/100)*100;
            break; 
    }
    
    
    if($v<100){
            $v= '距离我【<font color="#FF4C06"><b>'.$v.'</b></font>】公里内。';}
        else{
        $v= '距离我【<font color="#FF4C06"><b>'.$v.'</b></font>】米内。';
    }
    return $v;
    
}

 

B方式

function distanceDesc($number){
    if(!is_numeric($number)) return ' ';
    switch ($number){
        case $number>3000&&$number<=5000:
            $v='5';
            break;
        case $number>2000&&$number<=3000:
            $v='3';
            break;
        case $number>1000&&$number<=2000:
            $v='2';
            break;
        case $number>500&&$number<=1000:
            $v='1';
            break;
        case $number<=500:
            $v='0.5';
            break;
        default:
            $v=ceil($number/1000);
            break;
    }
    if($number<=300) {
        $distance = '【500米内】';
    }else{
        $distance = '【'.$v.'公里内】';
    }
    return $distance;

}

 

 

用户地理位置模式的显示就到此结束了

若是有不明白的,麻烦加QQ:187395037 

相关文章
相关标签/搜索