Mapbox GL矩形多边形图层侧边缩放保持直角的实现方案
解决Mapbox矩形编辑时侧边移动导致的变形问题
你的问题出在当前代码直接将鼠标的全部偏移量应用到侧边的两个顶点上,没有限制移动方向——矩形的侧边必须保持与对边平行,且相邻边垂直,所以拖动侧边时只能沿垂直于该侧边的方向移动。
核心思路
- 确定当前拖动的侧边,计算该侧边的方向向量
- 计算该方向的垂直向量(这是唯一允许的移动方向)
- 将鼠标的实际偏移投影到垂直向量上,得到符合矩形规则的增量
- 用这个增量更新侧边的两个顶点,确保边的方向不变
修改后的代码
onPointerMove = (event: MapMouseEvent) => { if (!isNumber(this.knobIndex)) return; if (!this.raster.coordinates?.length) return; const mouseLngLat = [event.lngLat.lng, event.lngLat.lat]; const indexA = this.knobIndex; const indexB = (this.knobIndex + 1) % 4; const pointA = this.raster.coordinates[indexA]; const pointC = this.raster.coordinates[indexB]; // 1. 计算当前侧边的方向向量 (从A到C) const edgeDirX = pointC[0] - pointA[0]; const edgeDirY = pointC[1] - pointA[1]; // 2. 计算垂直于侧边的方向向量(顺时针旋转90度) // 这是侧边允许移动的唯一方向,保证边平行、矩形不变形 const perpDirX = -edgeDirY; const perpDirY = edgeDirX; // 3. 计算侧边中点的当前位置和鼠标位置的向量 const midPoint = [(pointA[0] + pointC[0]) / 2, (pointA[1] + pointC[1]) / 2]; const mouseDeltaX = mouseLngLat[0] - midPoint[0]; const mouseDeltaY = mouseLngLat[1] - midPoint[1]; // 4. 将鼠标偏移投影到垂直方向上,得到有效移动增量 // 计算投影长度:(鼠标向量 · 垂直方向向量) / (垂直方向向量的模长平方) const dotProduct = mouseDeltaX * perpDirX + mouseDeltaY * perpDirY; const perpLengthSq = perpDirX * perpDirX + perpDirY * perpDirY; const scale = dotProduct / perpLengthSq; // 最终的移动增量 const deltaX = perpDirX * scale; const deltaY = perpDirY * scale; // 5. 更新两个顶点的位置 const newCoordinates = [...this.raster.coordinates]; newCoordinates[indexA] = [pointA[0] + deltaX, pointA[1] + deltaY]; newCoordinates[indexB] = [pointC[0] + deltaX, pointC[1] + deltaY]; this.onUpdate(newCoordinates); };
关键部分解释
- 垂直方向向量计算:通过将侧边方向向量顺时针旋转90度(
(-y, x)),得到唯一允许的移动方向,确保拖动时侧边始终与原方向平行。 - 投影计算:把鼠标的任意偏移限制到垂直方向上,避免侧边出现倾斜,彻底解决矩形变形问题。
- 通用适配:不管矩形初始是轴对齐还是旋转过的,这套逻辑都能维持矩形的直角和平行边特性。
内容的提问来源于stack exchange,提问作者user30132940
相关产品推荐
相关产品推荐

