关于mapbox 中拖拽point,line ,polygon实现原理

最近闲来无事开始对-gl-draw.js工具做了一些剖析,在绘制完一个line或者 和point 鼠标按下移动鼠标可以改变图层位置 。当时我就在想,他是怎样实现的 。所以了解源码之后我的小小结论就出来 。
怎样让一个line图层或者图层跟着你的鼠标移动呢?这里point就不作探讨了,官网有相关案例 。一看就明白那种,所以我们就重点讨论怎样实现line或者的拖动 。
首先要理解line 和的拖动,最基本要理解数学二维直角坐标系和三角形相关的知识和概念 。在直角坐标系中,知道一点(x,y)和夹角 和一条边的长度就可以计算出未知的目标点,如图所示

关于mapbox 中拖拽point,line ,polygon实现原理

文章插图
所以在中移动图层就是运用这样的数学逻辑,那怎样去拖拽line或改变其位置呢 。所以你就要理解line或者在概念和数据组织上是一个个point组成的 ,所以通过已知图层数据到鼠标点击或者鼠标按下的坐标点,就可以计算出该鼠标点到各个点间的距离和夹角 。那么是不是再进行鼠标移动过程中,就可以通过原始各个点的距离和夹角来计算出移动后的各个点的坐标呢 。所以梳理原理之后,那么就开始实现,以下是在vue2中对线的实现代码
关于mapbox 中拖拽point,line ,polygon实现原理

文章插图
/*** * 拖动原理的实现* ① 首先实现需要三个个鼠标事件mousedown, mousemove ,mouseup,还有turf.js(that.$turf)工具(辅助计算长度和距离),其实这里我有一个大胆想法不用turf直接把放在二维直角坐标系中使用三角公式一样可以做*1:mousedown 用来计算初始layer 各个点到鼠标点的距离和夹角,这是在后续拖动图层可以计算新的各个点的坐标*2:mousemove 使用拖动的坐标点来计算各个点的坐标*3: mouseup结束拖动, 关闭鼠标事件* */drewDrag(key){let that = this;that.index = key;let layerId = 'drew_line'//添加鼠标按下事件that.map.on('mousedown',layerId, mousedownEvent);//添加触控启动事件that.map.on('touchstart', layerId,touchstartEvent)function mousemoveEvent(e) {let coords =[e.lngLat.lng,e.lngLat.lat] //当前坐标 //根据点,距离和角度计算目标点that.json_line.features.forEach((_e)=>{var s_destination = that.$turf.destination(that.$turf.point([e.lngLat.lng,e.lngLat.lat]), _e.properties.distance[0], _e.properties.angle[0], {units: 'degrees'});console.log(s_destination)var e_destination = that.$turf.destination(that.$turf.point([e.lngLat.lng,e.lngLat.lat]), _e.properties.distance[1], _e.properties.angle[1], {units: 'degrees'});console.log(e_destination)_e.geometry.coordinates=[s_destination.geometry.coordinates,e_destination.geometry.coordinates]})that.map.getSource('drew_line').setData(that.json_line)console.log(e+coords);}function onUp(e) {that.map.off('mousemove', mousemoveEvent);that.map.off('touchmove', mousemoveEvent);that.map.off('mousedown', mousedownEvent);that.map.off('touchstart', touchstartEvent);that.map.off('touchend', onUp);console.log(e)}function mousedownEvent(e) {e.preventDefault();//防止默认地图拖动行为 。//使用turf 计算各个坐标点的长度 和角度let data = http://www.kingceram.com/post/that.map.getSource('drew_line')._data.featuresconsole.log(data)that.json_line_point.features = []that.json_line.features = []data.forEach((_e,index,row)=>{console.log(index+row)//计算距离var start_distance = that.$turf.rhumbDistance(that.$turf.point([e.lngLat.lng,e.lngLat.lat]), that.$turf.point(_e.properties.start), {units: 'degrees'}); var end_distance = that.$turf.rhumbDistance(that.$turf.point([e.lngLat.lng,e.lngLat.lat]), that.$turf.point(_e.properties.end), {units: 'degrees'}); console.log(start_distance+"--"+end_distance)_e.properties.distance[0] = start_distance_e.properties.distance[1] = end_distance// 计算两点间的夹角var s_bearing = that.$turf.bearing(that.$turf.point([e.lngLat.lng,e.lngLat.lat]), that.$turf.point(_e.properties.start));var e_bearing = that.$turf.bearing(that.$turf.point([e.lngLat.lng,e.lngLat.lat]), _e.properties.end);_e.properties.angle[0]=s_bearing_e.properties.angle[1]=e_bearingthat.json_line.features.push({type: _e.type,geometry:_e.geometry,properties:_e.properties});})var feature = e.features[0];that.map.setFilter('pointlayerhighlight', ['in', 'id', feature.properties.id]);//鼠标移动that.map.on('mousemove',mousemoveEvent);//鼠标抬起that.map.once('mouseup', onUp);console.log(e);}function touchstartEvent(e){//防止默认地图拖动行为e.preventDefault();//触控移动that.map.on('touchmove', mousemoveEvent);//触控端起that.map.once('touchend', onUp);console.log(e)}}