uniapp的app/h5实现地图连续定位

一、实现逻辑

1、点击定位按钮,调用locatedRender方法

2、app端由于本身自带的定位不太准确,使用了高德的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>里面写就行

html 复制代码
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)

html 复制代码
/**
 * 在地图上创建标记
 * @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)

html 复制代码
/**
 * 缩放地图到指定坐标(居中定位)
 * @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、追踪用户位置

html 复制代码
/**
 * 追踪用户位置: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('浏览器不支持地理位置。');
	}
};
相关推荐
编程猪猪侠3 小时前
uni-app微信小程序车牌号输入组件实现
微信小程序·uni-app
真的不想写实验3 小时前
uniapp上传文件的载荷是个空对象
前端·uni-app
乌托邦16 小时前
uni-mini-ci:让 uniapp 小程序构建后自动预览和上传
前端·vue.js·uni-app
敲代码的鱼17 小时前
NFC读卡能力 支持安卓/iOS/鸿蒙 UTS插件
android·ios·uni-app
西洼工作室21 小时前
UniApp云开发笔记
前端·笔记·uni-app
Martin -Tang1 天前
uniapp 实现录音操作,长按录音,放开取消
前端·javascript·vue.js·uni-app·css3·录音
西洼工作室1 天前
UniApp开发全攻略:从生命周期到路由传值
前端·javascript·uni-app
Martin -Tang2 天前
uniapp+vue3+ts自定义表格
javascript·vue.js·uni-app
LinMin_Rik3 天前
解决win11专业版HbuilderX编译vue3的uniappX失败问题
uni-app