本文主要是介绍H5页面手绘轨迹路径-过程中允许拖动+缩放地图,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本文章可以参考解决的问题:H5端的多指、单指操作混乱的问题; mapbox-gl手绘轨迹线。
希望本文能帮助到其他人!
对于“在H5页面支持在地图上手绘轨迹"这个需求,从需求层面看比较简单。
作为开发,你会怎么做?
第一映像是 锁定地图,绘制过程中地图不跟随移动,否则手指在移动过程中手指的坐标不会变化,这样就完成了这一需求。
可以的!完全没问题。
但优秀吗?
从用户体验上,一旦锁定地图,在绘制过程中用户要操作的区域到可视区之外的话,则不好完了,怎么办?增加锁定、释放,移动等一系列辅助按钮?
功能上可以了,满足。
但完美吗?
从UI层面,增加了按钮,增加用户操作,体验不太好。
怎么让用户操作起来更丝滑?尽量保留地图的原生操作:1. 双指放大缩小地图。 2. 单指移动地图。直接上代码片段:
// 几种特殊情况: 多指开始->中间一个一个单指结束 ,单指开始 -> 中间加入多指。 处理方式:只要存在多指情况则不处理,且注意延迟。
let lnglats = [], moveTempLnglat = [], lastLnglat, locusChanging = false, touchCount = 0,handleTimer, singleTouch = true, handling = false // 1-单指, 2-双指。从开始start 到结束 end 一次操作才算完成
const tolerance = {10: 1000, 11: 1000, 12: 800, 13: 400, 14: 200, 15: 100, 16: 50, 17: 20, 18: 10, 19: 5, 20: 2, 21: 1}
const setLocus = () => {map.getSource("mylocus").setData({type: "FeatureCollection",features: [{type: "Feature",properties: {},geometry: {type: "LineString",coordinates: lnglats}}]})
}const startHandler = e => {const touchLen = e.originalEvent.changedTouches.lengthtouchCount += touchLen// 任一超一个触点,则视为多指,必须在所有触点释放后才能做后续操作if (touchCount > 1) {singleTouch = false}// 检查是否在附近,只有在附近才视为连续绘制if (singleTouch && touchLen === 1 && lnglats.length > 1) {const dis = turf.rhumbDistance(turf.point(lnglats[lnglats.length - 1]), turf.point([e.lngLat.lng, e.lngLat.lat]), {units: "meters"})if (dis > tolerance[Math.round(map.getZoom())]){map.dragPan.enable()return}}clearTimeout(handleTimer)// 清空移动预存moveTempLnglat = []// 避免双指延迟handleTimer = setTimeout(() => {if (singleTouch && touchLen === 1) {handling = truelnglats.push([e.lngLat.lng, e.lngLat.lat], ...moveTempLnglat.splice(0, moveTempLnglat.length))setLocus()}}, 200)
}const moveHandler = e => {const touchLen = e.originalEvent.targetTouches.lengthif (singleTouch && touchLen === 1) {if (handling) {lnglats.push([e.lngLat.lng, e.lngLat.lat])setLocus()} else {moveTempLnglat.push([e.lngLat.lng, e.lngLat.lat])}}
}const endHandler = e => {const touchLen = e.originalEvent.changedTouches.lengthtouchCount -= touchLen// 之前是单指模式,则开始动作if (singleTouch && touchLen === 1 && handling) {lnglats.push([e.lngLat.lng, e.lngLat.lat])setLocus()}if (touchCount === 0) {singleTouch = truehandling = false}if (locusChanging) {map.dragPan.disable()}
}const startChangeLocus = () => {const map = mapObj.valuelnglats = []moveTempLnglat = []handling = falsemap.dragPan.disable()// 测试:锁定地图,不允许拖动if (!map.getLayer("mylocus")) {map.addLayer({id: "mylocus",type: "line",source: {type: "geojson",data: {type: "FeatureCollection", features: []}}})} else {setLocus()}if (!locusChanging) {map.on("touchstart", startHandler)map.on("touchmove", moveHandler)map.on("touchend", endHandler)}locusChanging = true
}
const stopChangeLocus = () => {const map = mapObj.valuemap.dragPan.enable()map.off("touchstart", startHandler)map.off("touchmove", moveHandler)map.off("touchend", endHandler)locusChanging = false
}
主要思路: 只要触发了多触点,则视为当前多指操作,不做绘制;同时,预留了双指两个指头不同步的情况。
总结:
在使用触摸事件时,注意 changeTouches,touches,targetTouches 属性的在touchstart,touchmove,touchend 事件中分别的含义。
TouchEvent.changedTouches - Web API 接口参考 | MDN
TouchEvent.targetTouches - Web API 接口参考 | MDN
TouchEvent.touches - Web API 接口参考 | MDN
这篇关于H5页面手绘轨迹路径-过程中允许拖动+缩放地图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!