如何在Canvas上通过鼠标绘制平行四边形?附矩形实现参考代码
实现Canvas上鼠标绘制平行四边形的方案
当然可以实现啦!你当前的代码是通过创建绝对定位的div来模拟矩形绘制,要改成平行四边形有两种可行思路:一种是基于你现有代码用CSS变形改造,另一种是真正利用Canvas的原生绘图API来实现——后者更贴合Canvas的使用场景,我会分别详细说明。
方案一:基于现有div结构+CSS变形改造
你的现有代码是靠div模拟矩形,我们可以通过CSS的transform: skew()属性把矩形扭成平行四边形。这里我调整了交互逻辑,让拖动时同时控制平行四边形的宽高和倾斜角度,尽可能贴合你原来的点击-拖动-完成的操作习惯:
<div id="canvas"></div> <style> #canvas { width: 2000px; height: 2000px; border: 10px solid transparent; position: relative; /* 确保子元素绝对定位以它为基准 */ } .parallelogram { border: 1px solid #FF0000; position: absolute; background-color: rgba(255,0,0,0.1); /* 加个半透背景方便看清形状 */ } </style> <script> initDraw(document.getElementById('canvas')); function initDraw(canvas) { function setMousePosition(e) { var ev = e || window.event; if (ev.pageX) { mouse.x = ev.pageX + window.pageXOffset; mouse.y = ev.pageY + window.pageYOffset; } else if (ev.clientX) { mouse.x = ev.clientX + document.body.scrollLeft; mouse.y = ev.clientY + document.body.scrollTop; } // 转换为相对于canvas内部的坐标 const rect = canvas.getBoundingClientRect(); mouse.relativeX = mouse.x - rect.left; mouse.relativeY = mouse.y - rect.top; }; var mouse = { x: 0, y: 0, startX: 0, startY: 0, relativeX:0, relativeY:0 }; var element = null; canvas.onmousemove = function(e) { setMousePosition(e); if (element !== null) { const width = Math.abs(mouse.relativeX - mouse.startX); const height = Math.abs(mouse.relativeY - mouse.startY); // 计算水平倾斜角度,根据鼠标拖动的方向动态调整 const skewAngle = Math.atan2(mouse.relativeY - mouse.startY, mouse.relativeX - mouse.startX) * (180/Math.PI) - 90; // 把元素定位在拖动区域的左上角 element.style.left = Math.min(mouse.startX, mouse.relativeX) + 'px'; element.style.top = Math.min(mouse.startY, mouse.relativeY) + 'px'; element.style.width = width + 'px'; element.style.height = height + 'px'; // 应用倾斜变换 element.style.transform = `skewX(${skewAngle}deg)`; } } canvas.onclick = function(e) { if (element !== null) { element = null; canvas.style.cursor = "default"; console.log("绘制完成!"); } else { console.log("开始绘制!"); setMousePosition(e); mouse.startX = mouse.relativeX; mouse.startY = mouse.relativeY; element = document.createElement('div'); element.className = 'parallelogram'; element.style.left = mouse.startX + 'px'; element.style.top = mouse.startY + 'px'; canvas.appendChild(element); canvas.style.cursor = "crosshair"; } } } </script>
这个方案的核心是用transform: skewX()将矩形扭曲成平行四边形,通过鼠标拖动的方向计算倾斜角度,完美适配你原来的交互逻辑。
方案二:原生Canvas绘图API实现(更推荐)
其实你现在的代码并没有真正用到Canvas的绘图能力,只是把它当作了一个容器。原生Canvas的beginPath()、lineTo()等API可以直接绘制任意多边形,包括平行四边形——这种方案更高效,也更符合Canvas的设计初衷,扩展性也更强。
下面是具体实现代码:
<canvas id="canvas" width="2000" height="2000"></canvas> <style> #canvas { border: 10px solid transparent; cursor: default; } </style> <script> initDraw(document.getElementById('canvas')); function initDraw(canvas) { const ctx = canvas.getContext('2d'); let isDrawing = false; let startPoint = { x: 0, y: 0 }; let currentPoint = { x: 0, y: 0 }; // 获取鼠标相对于Canvas内部的坐标 function getMousePos(e) { const rect = canvas.getBoundingClientRect(); return { x: e.clientX - rect.left, y: e.clientY - rect.top }; } // 绘制平行四边形的核心函数 function drawParallelogram() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布上的临时图形 ctx.beginPath(); // 定义平行四边形的四个顶点:起点 → 右侧顶点 → 右下角顶点 → 左下角顶点 → 闭合 const width = currentPoint.x - startPoint.x; const height = currentPoint.y - startPoint.y; // 这里的0.5是倾斜系数,你可以调整这个值来改变平行四边形的倾斜程度 const skewOffset = height * 0.5; ctx.moveTo(startPoint.x, startPoint.y); ctx.lineTo(startPoint.x + width, startPoint.y); ctx.lineTo(startPoint.x + width + skewOffset, startPoint.y + height); ctx.lineTo(startPoint.x + skewOffset, startPoint.y + height); ctx.closePath(); ctx.strokeStyle = '#FF0000'; ctx.lineWidth = 1; ctx.stroke(); ctx.fillStyle = 'rgba(255,0,0,0.1)'; ctx.fill(); } canvas.onmousedown = function(e) { isDrawing = true; startPoint = getMousePos(e); currentPoint = startPoint; canvas.style.cursor = "crosshair"; } canvas.onmousemove = function(e) { if (!isDrawing) return; currentPoint = getMousePos(e); drawParallelogram(); } canvas.onmouseup = function(e) { isDrawing = false; canvas.style.cursor = "default"; console.log("绘制完成!"); // 如果需要保留所有绘制的平行四边形,可以在这里把当前图形的顶点数据存入数组,每次重绘遍历数组绘制 } // 处理鼠标意外移出Canvas的情况 canvas.onmouseleave = function() { if (isDrawing) { isDrawing = false; canvas.style.cursor = "default"; } } } </script>
这个方案直接用Canvas原生API绘图,你可以灵活调整倾斜系数来改变平行四边形的形状,还能轻松实现“保留所有绘制图形”的功能——只需要把每个完成的平行四边形的顶点数据保存到数组里,每次重绘时遍历数组绘制即可。
两种方案各有优劣:方案一可以复用你现有的div结构,改动较小;方案二更贴近Canvas的原生用法,功能扩展性更强,我个人更推荐第二种。
内容的提问来源于stack exchange,提问作者popeye
相关产品推荐
相关产品推荐

