如何用JS实现Canvas上支持拖拽顶点调整角度的平行四边形绘制
平行四边形拖拽绘制功能异常修复方案
核心问题定位
- 第一版参考修改代码的错误点:
drawPolygon函数每次触发渲染时都会调用GetMassCenterAndFourthPoint往顶点数组新增第四个点,多次调用后数组长度持续增长,导致顶点计算、渲染逻辑完全错乱 - 第二版自研代码的错误点:缺少拖拽所需的鼠标按下、移动、抬起全流程事件处理,也没有实现鼠标位置和顶点的碰撞检测逻辑,无法触发拖拽行为
- 平行四边形第四顶点不需要持久化存储,只要保证前三个顶点是用户可编辑的,每次渲染前基于「对边平行且相等」的规则动态计算即可,你原本的计算逻辑
point4 = p0 + p2 - p1本身是正确的
修复后完整可运行代码
<canvas id="canvas" width="600" height="600"></canvas>
canvas { border: 1px solid black; }
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); const cw = canvas.width; const ch = canvas.height; let mouse = {}; let draggableIndex = -1; context.lineWidth = 2; context.strokeStyle = "blue"; // 只存储用户可编辑的前三个顶点 const coordinates = []; let isDrawFinished = false; canvas.addEventListener("mousedown", handleMouseDown); canvas.addEventListener("mousemove", handleMouseMove); canvas.addEventListener("mouseup", handleMouseUp); // 动态计算第四顶点 function getFourthPoint(points) { return { x: points[2].x - points[1].x + points[0].x, y: points[2].y - points[1].y + points[0].y }; } function handleMouseDown(e) { mouse = getMousePos(canvas, e); if (isDrawFinished) { // 检测鼠标点击在哪个顶点上 for (let i = 0; i < coordinates.length; i++) { context.beginPath(); context.arc(coordinates[i].x, coordinates[i].y, 5, 0, 2 * Math.PI); if (context.isPointInPath(mouse.x, mouse.y)) { draggableIndex = i; break; } } } else { // 绘制阶段收集前三个顶点 coordinates.push({x: mouse.x, y: mouse.y}); render(); if (coordinates.length === 3) { isDrawFinished = true; } } } function handleMouseMove(e) { if (isDrawFinished && draggableIndex !== -1) { mouse = getMousePos(canvas, e); // 更新被拖拽的顶点坐标 coordinates[draggableIndex].x = mouse.x; coordinates[draggableIndex].y = mouse.y; render(); } } function handleMouseUp() { draggableIndex = -1; } function render() { context.clearRect(0, 0, cw, ch); // 绘制平行四边形 context.beginPath(); context.moveTo(coordinates[0].x, coordinates[0].y); context.lineTo(coordinates[1].x, coordinates[1].y); context.lineTo(coordinates[2].x, coordinates[2].y); if (isDrawFinished) { const p4 = getFourthPoint(coordinates); context.lineTo(p4.x, p4.y); } context.closePath(); context.stroke(); // 绘制所有可拖拽顶点的标识圆圈 coordinates.forEach(point => { context.beginPath(); context.arc(point.x, point.y, 5, 0, 2 * Math.PI); context.stroke(); }); // 如果绘制完成,也给第四顶点画标识(不需要可以直接删掉这段) if (isDrawFinished) { const p4 = getFourthPoint(coordinates); context.beginPath(); context.arc(p4.x, p4.y, 5, 0, 2 * Math.PI); context.stroke(); } } // 获取鼠标在canvas内的相对坐标 function getMousePos(canvas, evt) { const clientRect = canvas.getBoundingClientRect(); return { x: Math.round(evt.clientX - clientRect.left), y: Math.round(evt.clientY - clientRect.top) }; }
功能说明
- 点击三次画布确定平行四边形的前三个顶点,自动生成第四个顶点完成绘制
- 可以拖拽前三个顶点任意调整位置,第四个顶点会自动同步更新,始终保持平行四边形结构
- 所有顶点都有可见的圆圈标识,方便点击拖拽
内容的提问来源于stack exchange,提问作者Den251
相关产品推荐
相关产品推荐

