目录
一、实现逻辑
1、点击定位按钮,调用locatedRender方法
2、app端由于本身自带的定位不太准确,用了原生方法plus.geolocation.watchPosition,并用了高德的key(key需要自己申请),且用了gcoord来转换坐标系
3、由于app端的地图限制,以下涉及地图的方法是写在视图层的,即在里面,而不是在逻辑层里面
二、引用的方法
1、在地图上创建点标记(createMarker)
2、缩放到地图中间(zoomMapToPoint)或者地图上半部分(zoomMapToPointTop)
3、追踪用户位置
在地图基础框架已经搭好的前提下,即window._map已存在
注:app端只测试了安卓系统,不知道ios是否适用
一、实现逻辑
1、点击定位按钮,调用locatedRender方法
2、app端由于本身自带的定位不太准确,用了原生方法plus.geolocation.watchPosition,并用了高德的key(key需要自己申请),且用了gcoord来转换坐标系
连续定位,uniapp官方(https://uniapp.dcloud.net.cn/api/location/location-change.html)也有对应的方法,但是在我本地实测,会出现延迟的情况,就是走了好几米,但是定位还是不动,不实时变化,会在10~30秒后,定位跳一下
3、由于app端的地图限制,以下涉及地图的方法是写在视图层的,即在<script module="maptalksJS" lang="renderjs"></script>里面,而不是在逻辑层<script></script>里面
我这儿主要是为了做app端,只是作了h5的兼容,如果只是h5,正常在<script></script>里面写就行
import gcoord from 'gcoord'; point: [], watchId: null, locationlayer: null, dwOpen:false, this.locationlayer = new maptalks.VectorLayer('locationLayer').addTo(window._map);/** * 定位用户当前位置 */ locatedRender() { if (this.point.length > 0) { // 放大到当前用户位置(地图上半部分) // zoomMapToPointTop(window._map, this.point); // 放大到当前用户位置(居中位置) zoomMapToPoint(window._map, this.point); // 在地图上创建标记 createMarker(window._map, this.locationlayer, this.point[0], this.point[1], false); } else { // 启动位置追踪 this.startTrackingWz(); } }, /** * 启动追踪用户位置 */ startTrackingWz() { // #ifdef APP-PLUS this.watchId = trackUserLocationApp( position => { // 使用 gcoord 转换 → WGS84 const wgs84 = gcoord.transform( [position.coords.longitude, position.coords.latitude], // 必须是 [经度, 纬度] gcoord.GCJ02, // 来源坐标系 gcoord.WGS84 // 目标坐标系 ) this.point = wgs84 if (this.point && this.dwOpen == false) { // 设置只有第一次点击的时候才放大缩放 // zoomMapToPointTop(window._map, this.point); zoomMapToPoint(window._map, this.point); this.dwOpen = true } createMarker(window._map, this.locationlayer, this.point[0], this.point[1], false); // 在地图上添加标记 }, error => { console.error('追踪用户位置出错', error); } ); // #endif // #ifdef H5 this.watchId = trackUserLocation( position => { this.point = [position.coords.longitude, position.coords.latitude]; if (this.point && this.dwOpen == false) { // 设置只有第一次点击的时候才放大缩放 // zoomMapToPointTop(window._map, this.point); zoomMapToPoint(window._map, this.point); this.dwOpen = true } createMarker(window._map, this.locationlayer, this.point[0], this.point[1], false); // 在地图上添加标记 }, error => { console.error('追踪用户位置出错', error); } ); // #endif }, /** * 清除位置追踪 */ watchIdClearRender(){ if(this.watchId){ // #ifdef APP-PLUS plus.geolocation.clearWatch(this.watchId); // #endif // #ifdef H5 navigator.geolocation.clearWatch(this.watchId); // #endif } },二、引用的方法
1、在地图上创建点标记(createMarker)
/** * 在地图上创建标记 * @param {Object} map 地图实例 * @param {Object} locationLayer 标注图层 * @param {number} lng 经度 * @param {number} lat 纬度 * @param {boolean} isZoom 是否缩放到该点 */ export const createMarker = (map, locationLayer, lng, lat, isZoom = false, oldMarker = null) => { const marker = new maptalks.Circle([lng, lat], 0, { symbol: { markerType: 'ellipse', markerWidth: 10, markerHeight: 10, markerFill: 'red', markerLineColor: '#fff', markerLineWidth: 2, opacity: 1 } }); const markerCenter = new maptalks.Marker([lng, lat], { symbol: { markerType: 'ellipse', markerWidth: 10, markerHeight: 10, markerFill: 'red', markerLineColor: '#fff', markerLineWidth: 2 } }); locationLayer.clear(); locationLayer.addGeometry(marker); locationLayer.addGeometry(markerCenter); if (isZoom) { map.setZoom(18); map.setCenter([lng, lat]); } animateRipple(marker); }; /** * 为标记添加波纹动画效果 * @param {Object} marker 标记实例 */ const animateRipple = (marker) => { const maxMarkerSize = 40; const minMarkerSize = 10; const duration = 1500; let startTime = null; function animate(timestamp) { if (!startTime) startTime = timestamp; const progress = timestamp - startTime; const scaleFactor = progress / duration; const currentSize = minMarkerSize + (maxMarkerSize - minMarkerSize) * scaleFactor; const currentOpacity = 1 - scaleFactor; marker.updateSymbol({ markerWidth: currentSize, markerHeight: currentSize, opacity: currentOpacity }); if (progress >= duration) { startTime = timestamp; } requestAnimationFrame(animate); } requestAnimationFrame(animate); };2、缩放到地图中间(zoomMapToPoint)或者地图上半部分(zoomMapToPointTop)
/** * 缩放地图到指定坐标(居中定位) * @param {Object} map 地图实例 * @param {Array} coordinates 坐标数组 */ export const zoomMapToPoint = (map, coordinates) => { map.animateTo({ center: coordinates, zoom: 18, pitch: 0, bearing: 0 }, { duration: 1500, easing: 'out' }); }; /** * 缩放地图到指定坐标(定位到地图的上半部分) * @param {Object} map 地图实例 * @param {Array} coordinates 坐标数组 */ export const zoomMapToPointTop = (map, coordinates) => { map.animateTo({ center: coordinates, zoom: 18, pitch: 0, bearing: 0 }, { duration: 1500, easing: 'out' }); setTimeout(() => { //计算需要向上平移的像素距离( 例如, 向上平移 1/3 地图高度) const mapSize = map.getSize(); const dy = mapSize.height * -0.3; // 向上平移 1/3 高度 // 平移地图 map.panBy([0, dy], { animation: { duration: 1000 } }); }, 1500); // 等待1500ms,若不设置,则向上平移不生效 };3、追踪用户位置
/** * 追踪用户位置:h5 * @param {function} successCallback 成功获取位置的回调 * @param {function} errorCallback 失败回调 */ export const trackUserLocation = (successCallback, errorCallback) => { if (navigator.geolocation) { return navigator.geolocation.watchPosition(successCallback, errorCallback, { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }); } else { console.log('浏览器不支持地理位置。'); } }; /** * 追踪用户位置:app * @param {function} successCallback 成功获取位置的回调 * @param {function} errorCallback 失败回调 */ export const trackUserLocationApp = (successCallback, errorCallback) => { if (plus.geolocation) { return plus.geolocation.watchPosition(successCallback, errorCallback, { provider: 'amap', // 强制高德(关键!) type: 'gcj02', // 高德坐标系 enableHighAccuracy: true, // 高精度 maximumAge: 1000, // 1秒缓存 timeout: 5000 }); } else { console.log('浏览器不支持地理位置。'); } };