微信小程序-如何只显示固定地理范围km公里内的marker-只显示屏幕范围内的marker


前言

之前做了个课设,内容是在地图上显示停车位。但是课设有个要求是只显示2km范围的停车位,这一块网上资料较少,但其实思路很简单,我就简略写一写,当作帮助后来者。

在这里插入图片描述
如上图所示,一个个的锁代表着停车位,现在我们要显示离屏幕中心2km范围内的所有锁。(如果你是要只显示屏幕范围内的锁也可以做到,原理一样的)

大家可以在共享单车的平台(如下图所示的“青桔”小程序)上找到类似实现效果:当用户移动地图后(中心大头针随之移动),即用户手指刚离开屏幕时,屏幕中心周围的共享单车就会刷新一次(即向后台重新请求一次大头针半径范围内的共享单车)。
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、思路

  1. 用户每次划动地图,都会获取一次屏幕中心经纬度坐标,并将坐标发送给后台。
  2. 后台根据坐标筛选出范围内的车位,返回给小程序。坐标可由腾讯地图工具获取。
  3. 小程序接收到新的车位信息后,进行车位刷新并重新展示即可。

:后端存储的marker的地理坐标可以由腾讯地图工具获得,并不难

二、实现步骤与源代码

2.1.如何获取屏幕中心坐标

2.1.1 地图中心大头针

首先,为了方便起见,我们可以屏幕中心加个大头针.png图片。(png图片背景是透明的,适合这种上层图标)
在这里插入图片描述
链接: 大头针.png 百度网盘下载链接
提取码:4DEF

下载完大头针图片后,将图片插入到map组件里,修改wxml和wxss文件即可。

//.wxml文件

<map id="map" style="width:100vw; height:100vh"  markers="{{markers}}" 
  <image class="mapCenter" src="../../images/map-center.png" ></image>
</map>
//.wxss文件

.mapCenter {
  width: 48rpx;
  height: 77rpx;
  position: absolute;  //固定大头针在屏幕中心
  left: calc(50% - 24rpx);
  top: calc(50% - 77rpx);
}

在这里插入图片描述

2.1.2 调用API,获取屏幕中心坐标

获取屏幕中心点的经纬度坐标,可以用微信官方提供的API getCenterLocation() ,success后会返回给我们中心点经纬度。

我们在.js文件中添加以下代码即可。

//.js文件
  getCenterLocation: function () {
    this.mpCtx.getCenterLocation({
      success: function(res){
        console.log(res.longitude+" "+res.latitude)
      }
    })
  }, 

2.1.3 用户拖动屏幕时,小程序能自动获取屏幕中心坐标

这里需要将上述两步进行结合,即大头针移动时,小程序能自动获取中心大头针坐标。这里要用到官方提供的API叫regionchange(),作用是每当用户进行缩放或移动屏幕时,小程序都会自动调用一次该函数。

在这里插入图片描述

所以,只要我们在这个函数里写上获取中心坐标的代码后,每当用户移动屏幕,小程序就会自动调用该函数,从而实现自动获取屏幕中心经纬度坐标的效果。

具体代码如下所示:

在wxml中的map组件加入bindregionchange属性,并让该属性绑定.js文件中的 regionDidChange() 函数

//.wxml文件

<map id="map" style="width:100vw; height:100vh"  markers="{{markers}}" bindregionchange="regionDidChange" >
  <image class="mapCenter" src="../../images/map-center.png" ></image>
</map>

在js文件里写下 regionDidChange() 函数,每当用户移动屏幕时,前端会自动触发该函数,并将用户移动屏幕的具体信息传入参数e,你们可以自己console出来看看,我就不过多赘述了,注释写得很清楚。

//.js文件

  regionDidChange(e) {
  	console.log(e)
    if (e.type == 'end')		//begin 代表屏幕移动操作开始,end 代表屏幕移动操作结束,我们只要移动结束的时候即可
        if(e.causedBy == "drag")	//scale 代表屏幕缩放操作,drag代表屏幕移动操作,我们只要屏幕移动的时候即可
        {
          this.getCenterLocation()	//当屏幕移动结束时,我们立刻获取屏幕中心坐标
        }
    }
  },

至此,我们就实现了用户移动屏幕,小程序自动获取中心坐标的效果。

2.2 后台筛选范围内的markers信息

获取到中心经纬度坐标后,我们就要将坐标发送给后台(服务器),让后台帮我们筛选范围内的markers。

当然,你也可以在自己的小程序写个js函数,让小程序直接执行筛选范围内车位的工作,代码思路也一样。但是这只适合markers数量很少的时候。当markers数量过多时,计算量过大会使得小程序运行速度大大降低,所以可以的话还是尽量让后台来帮我们进行计算过程。

2.2.1 如何显示后台筛选范围后的markers

我们先对上述的.js函数 getCenterLocation() 进行些微更改,添加了一个函数putArrayIntoMarkers() 用来向后台发送我们的屏幕中心经纬度坐标。

//.js文件
  getCenterLocation: function () {
    var that = this	//success里的this并不是页面的this,故要先把页面的this保存为that
    this.mpCtx.getCenterLocation({
      success: function(res){
        that.putArrayIntoMarkers(res.longitude,res.latitude) //向后台发送屏幕中心经纬度坐标
      }
    })
  }, 

putArrayIntoMarkers() 函数实现了刷新车位信息,并装载新的车位信息效果。

//.js文件

  //获取大头针2km范围内的地锁信息,并存入markers
  putArrayIntoMarkers(longitude,latitude){
    var that = this
    var temp_array = [] //用于接收后台传来的新的车位组信息
    this.setData({
      markers:[]		//清空当前的车位组信息
    })
    wx.request({
      url: 'http://127.0.0.1:8888/find2kmLock',	
      data:{	//向后台发送屏幕中心经纬度坐标
        "longitude":longitude,
        "latitude":latitude
      },
      method:'POST',
      success:(res)=>{	//后台筛选完毕后,以data数组的形式将范围内所有车位信息发给我
	     res.data.data.forEach(function(item, index) {//循环所有的车位信息
	     
            var temp = {id:item.id, latitude:item.latitude, longitude:item.longitude,
                        iconPath:temp_icon, width:that.data.width, height: that.data.height}
                        
            temp_array.push(temp)	//一个temp代表一个车位,把所有车位都push到temp_array集合里
            
          })
      },
      complete:()=>{	//success函数全部执行完后
			that.setData({
	            markers:temp_array	//全部完成后再将所有的车位信息装载到markers里
	        })
	  }
    })
  },

注: that.setData({}) 不能放在请求外面,因为请求是异步的,当小程序运行速度很快的时候,后台还没来得及给小程序返回值,temp_array就还是空的,所以得到的markers也是空的。故要等请求完全complete后再进行赋值操作。

至此,我们实现了如何让小程序给后台发送请求,并让小程序渲染后台返回的新车位的效果了。

2.2.2 后台筛选车位的思路

这里才是整个算法的关键之处。

假设我们服务器的数据库里存储了每个车位的经纬度坐标,然后现在我们要获取距离屏幕中心2km范围的车位,那我们最容易想到的思路应该是:

  1. 建立经纬度和km单位之间的转换方法。
  2. 用for循环将每个车位经纬度坐标和屏幕中心坐标进行欧氏距离计算(两点之间距离)。
  3. 将范围小于2km的车位记录下来,后续一同发送给小程序。

显然,这样的做法计算量过于庞大,于是在参考了网上资料后,我们有了更简便的方法:

我们本来是求半径2km范围圆内的车位,但现在我们将问题转换成求半径2km圆的外接矩形范围内的车位,下图是找到的网图,O点代表屏幕中心。
在这里插入图片描述
假设我们知道经纬度和km距离换算方法(假设经纬度与km之比为1:2),那我们显然可以根据O点的经纬度坐标来求得A点和B点的经纬度坐标。
如果O点经纬度坐标为(1,2),那么2km外接矩形上的B点经纬度坐标为(0,1),A点经纬度坐标为(2,3)。显然,我们现在就将问题转换成了求得落在矩形区域内的车位。

很简单,一条sql语句即可:

SELECT * FROM 车位信息表 WHERE (纬度 between 0 and 2) and (经度 between 1 and 3)

了解过数据库的应该都不难理解这句SQL的含义,这样我们就大大减少了计算量(计算欧氏距离等),加快了后台筛选速度。

2.2.3 经纬度与km之间的转换

经纬度与km之间的转换有两种方法。

第一种:较为准确的,即直接进行数学计算,网上有很多教程,很简单的高中运算知识,就不赘述了,文章后面我会贴上代码,。
在这里插入图片描述

第二种:较为简便也带点误差的方法。

先进入 腾讯地图位置服务官网—开发文档— 坐标拾取器网站
我们可以在这个网站上很方便的得到每一点的经纬度。
在这里插入图片描述
然后我们再打开腾讯地图页面,右上角有一个“尺子”的标志,即测距功能,我们测量横向2km的距离。
在这里插入图片描述

然后在坐标拾取器上找到对应的经纬度距离即可,这里为了方便我直接列出数据:
横向2km,方向从左到右,经度增加0.019014
纵向2km,方向从下到上,纬度增加0.017380

至此,我们就能够转换km和经纬度的关系,从而得到A和B点的坐标。

2.2.4 后台代码

后台服务器用的是第一种方法实现的经纬度转换。(这里的代码是由同组人员完成的,非本人实现,经过测试,效果还是挺准确的)

public Result findNearLock(@RequestBody RoadLock roadLock){
    double longitude = roadLock.getLongitude();
    double latitude = roadLock.getLatitude();
    int distance = 2;
    double R = 6371.393;//地球半径:千米
    double r = R*Math.cos(latitude*Math.PI/180);//latitude是角度
    double dlng = distance/r;//弧度
    //double dlng = 2*Math.asin(Math.sin(distance/(2*R))/Math.cos(latitude*Math.PI/180));
    dlng = dlng*180/Math.PI;//弧度转为角度
    double dlat = distance/R;//弧长/半径=弧度
    dlat = dlat*180/Math.PI;//角度
    double minlatitude = latitude - dlat;//get
    double maxlatitude = latitude + dlat;//get
    double minlongitude = longitude - dlng;
    double maxlongitude = longitude + dlng;
    List<RoadLock> list = roadLockService.findByLongitudeAndLatitudeDistance(minlatitude,maxlatitude,
            minlongitude,maxlongitude);
    return Result.suc((Object) list, (long) list.size());
}

2.2.5 小程序源代码

wxml部分:

<map id="map" style="width:100vw; height:100vh"  markers="{{markers}}" 
latitude="{{latitude}}" longitude="{{longitude}}" scale="{{scale}}" 
show-location="true"  controls="{{controls}}" bindcontroltap="controltap" 
bindmarkertap="handleMarkerTap" bindregionchange="regionDidChange" >

  <image class="mapCenter" src="../../images/map-center.png" ></image>
  
</map>

wxss部分:

.mapCenter {
  width: 48rpx;
  height: 77rpx;
  position: absolute;	//固定大头针在屏幕中心
  left: calc(50% - 24rpx);
  top: calc(50% - 77rpx);
}

js部分:

//.js文件
  regionDidChange(e) {	//用户进行了屏幕移动操作则触发该函数
  	console.log(e)
    if (e.type == 'end')		//begin 代表屏幕移动操作开始,end 代表屏幕移动操作结束,我们只要移动结束的时候即可
        if(e.causedBy == "drag")	//scale 代表屏幕缩放操作,drag代表屏幕移动操作,我们只要屏幕移动的时候即可
        {
          this.getCenterLocation()	//当屏幕移动结束时,我们立刻获取屏幕中心坐标
        }
    }
  },
  
  getCenterLocation: function () {
    var that = this	//success里的this并不是页面的this,故要先把页面的this保存为that
    this.mpCtx.getCenterLocation({
      success: function(res){
        that.putArrayIntoMarkers(res.longitude,res.latitude) //向后台发送屏幕中心经纬度坐标
      }
    })
  }, 


  //获取大头针2km范围内的地锁信息,并存入markers
  putArrayIntoMarkers(longitude,latitude){
    var that = this
    var temp_array = [] //用于接收后台传来的新的车位组信息
    this.setData({
      markers:[]		//清空当前的车位组信息
    })
    wx.request({
      url: 'http://127.0.0.1:8888/find2kmLock',	
      data:{	//向后台发送屏幕中心经纬度坐标
        "longitude":longitude,
        "latitude":latitude
      },
      method:'POST',
      success:(res)=>{	//后台筛选完毕后,以data数组的形式将范围内所有车位信息发给我
	     res.data.data.forEach(function(item, index) {//循环所有的车位信息
	     
            var temp = {id:item.id, latitude:item.latitude, longitude:item.longitude,
                        iconPath:temp_icon, width:that.data.width, height: that.data.height}
                        
            temp_array.push(temp)	//一个temp代表一个车位,把所有车位都push到temp_array集合里
            
          })
      },
      complete:()=>{	//success函数全部执行完后
			that.setData({
	            markers:temp_array	//全部完成后再将所有的车位信息装载到markers里
	        })
	  }
    })
  },

三、可选

如果你是想显示屏幕范围内的markers,你可以试试调用微信官方提供的获取屏幕坐标API,比如说MapContext.fromScreenLocation(Object object),这一块我不太清楚,不过思路应该大体一致。

总结

以上就是获取固定范围内的markers方法,部分内容参考了网上的资料,如有错误,欢迎指正。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bartender_Jill

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值