taro小程序vue3使用腾讯地图获取定位,刷新定位、计算两点之间距离、计算合适的缩放比例scale

业务场景

小程序打卡签到功能实现

效果预览


业务实现

前言

1、实现实时动态更新用户定位;

2、计算当前定位是否在多边形打卡区域内,判断是否可以打卡;

3、根据当前定位和目标打卡位置计算中心点位,并调整合适的比例进行缩放,使两个点位在用户首次进入应用时可同时显示,提升交互体验;

4、用户点击更新定位时,视角聚焦于当前用户定位;

业务代码

1、微信公众平台配置隐私协议

地址:微信公众平台

(1)申请接口
在这里插入图片描述

(2)隐私协议配置

需要配置位置隐私信息,需要审核 0.5-2 天左右

(3)小程序代码 config 接口配置

在 src/app.config.ts 页面中配置申请的三个接口

requiredPrivateInfos: [
  "getLocation",
  "onLocationChange",
  "startLocationUpdate",
];

(4)request域名添加

在微信公众平台配置-开发管理-开发设置-服务器域名-request合法域名中添加【https://apis.map.qq.com】

2、业务代码

(1)绘制我的定位

a、获取用户当前的定位:通过getLocation获取用户当前的定位,由于用户可能会拒绝微信授权或者未开启定位功能,可以通过Taro.getSystemInfo和wx.getLocation判断是否拒绝,如果拒绝可以通过wx.getSetting引导开启

b、监听用户位置:通过wx.startLocationUpdate监听当前用户移动位置,并通过wx.onLocationChange事件获取移动位置信息,wx.stopLocationUpdate在页面关闭时停止监控

c、如果你的业务需要将经纬度转成详细位置信息,需要找包萍钢给应用和小程序申请key值,将经纬度值转成详细位置信息,具体方法参考signin函数

// 获取我的当前经纬度
const getLongitude = (type) => {
   
  Taro.getSystemInfo({
   
    success: (res) => {
   
      if (!res.locationEnabled || !res.locationAuthorized) {
   
        clearMarkers();
        positionPermission.value = false;
        Taro.showToast({
   
          title: "请开启手机定位功能",
        });
      } else {
   
        wx.getLocation({
   
          isHighAccuracy: true, // 开启地图精准定位
          // 高德 gcj02, 百度 wgs84
          type: "gcj02", // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
          success: (res) => {
   
            refreshFlag.value = true;
            console.log("我的位置", res);
            positionPermission.value = true;
            setTimeout(() => {
   
              refreshFlag.value = false;
            }, 10000);
            // 添加标记点
            addMarkers(res);
            if (type === "refresh") {
   
              centerLongitude.value = res.longitude;
              centerLatitude.value = res.latitude;
              tMap.moveToLocation({
   
                longitude: centerLongitude.value,
                latitude: centerLatitude.value,
              });
              scale.value = 18;
            }
            if (type === "once") {
   
              getInitCenter();
            }
          },
          fail: (err) => {
   
            positionPermission.value = false;
            wx.getSetting({
   
              success: (res) => {
   
                if (!res.authSetting["scope.userLocation"]) {
   
                  Taro.showModal({
   
                    content:
                      "检测到您未打开地理位置授权,无法使用该功能,是否前往开启",
                    confirmText: "去开启",
                    success: (res) => {
   
                      if (res.confirm) {
   
                        Taro.openSetting();
                      } else {
   
                        wx.showToast({
   
                          title: "您未授权位置信息,暂无法使用打卡功能",
                          icon: "none",
                        });
                      }
                    },
                  });
                }
              },
              fail: (res) => {
   
                console.log("res拒绝", res);
              },
            });
            console.log("拒绝", err);
          },
        });
      }
    },
  });
};
// 监听当前用户位置移动
onLoad: (options) => {
   
  // 先停止监听
  wx.stopLocationUpdate({
   
    success(res) {
   
      console.log("停止定位更新", res);
    },
  });
  // 创建新的监听
  wx.startLocationUpdate({
   
    success() {
   
      // locationChangeFn为绘制marker等业务
      wx.onLocationChange(_this.locationChangeFn);
    },
    fail(err) {
   
      console.error("定位更新失败", err);
    },
  });
},

onUnload() {
   
  // 页面卸载后停止监听
  wx.stopLocationUpdate({
   
    success(res) {
   
      console.log("停止定位更新", res);
    },
  });
},

(2)绘制打卡范围和打卡中心点,并计算用户当前位置是否在当前区域范围内

a、绘制打卡范围和打卡中心点:可参考代码中getAreaLine方法和addMarkers方法

b、计算当前定位是否在打卡区域内算法,通过isPointInPolygon函数返回,如果在范围内,修改我的定位图标,提示已进入范围


// point 经纬度对象,polygon多边形数组
const isPointInPolygon = (point, polygon) => {
   
  let inside = false;
  for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
   
    const xi = polygon[i].longitude,
      yi = polygon[i].latitude;
    const xj = polygon[j].longitude,
      yj = polygon[j].latitude;
    const intersect =
      yi > point.latitude !== yj > point.latitude &&
      point.longitude < ((xj - xi) * (point.latitude - yi)) / (yj - yi) + xi;
    if (intersect) inside = !inside;
  }
  return inside;
};

(3)将视野调整为我的定位与打卡签到位置中间,并视野缩放为合适的比例

a、计算我的定位和打卡定位直线的中心位置,通过tMap.moveToLocation方法,将视角移动到该两点的中间点

b、计算我的定位和打卡定位中心位置的距离distance,通过算法算出合适的缩放比例,调整地图的缩放比例scale,使得我的定位和打卡定位中心位置同时在页面中合适位置

// 计算两个点之间的中心位置
function calculateDistance(lat1, lon1, lat2, lon2) {
   
  const R = 6371000; // 地球半径,单位为米
  const toRadians = (angle) => angle * (Math.PI / 180);
  const dLat = toRadians(lat2 - lat1);
  const dLon = toRadians(lon2 - lon1);
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(toRadians(lat1)) *
      Math.cos(toRadians(lat2)) *
      Math.sin(dLon / 2) *
      Math.sin(dLon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c;
}
// 计算缩放比例,可以自行调整
function estimateZoomLevel(distance) {
   
  let zoomLevel;
  if (distance > 1000000) {
   
    zoomLevel = 5 - ((distance - 1000000) / 3000000) * 10;
  } else if (distance > 100000 && distance <= 1000000) {
   
    zoomLevel = 7 + ((distance - 100000) / 900000) * 6;
  } else if (distance > 50000 && distance <= 100000) {
   
    zoomLevel = 10 + (distance / 1000000) * 9;
  } else if (distance > 10000 && distance <= 50000) {
   
    zoomLevel = 11 + (distance / 1000000) * 6.5;
  } else if (distance > 5000 && distance <= 10000) {
   
    zoomLevel = 13 + (distance / 100000) * 6;
  } else if (distance > 900 && distance <= 5000) {
   
    zoomLevel = 14 + (distance / 100000) * 8;
  } else if (distance > 500 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值