如何围绕Canvas任意原点实现图像的平移、缩放与旋转?
问题:Canvas图像围绕任意原点旋转的实现方案
我正在开发一款图像编辑工具,目前已实现Canvas上图像的拖拽、平移、缩放和旋转功能,基于DOMMatrix API实现变换。当前功能可用,但仅支持围绕图像中心点进行变换。
如何实现围绕Canvas任意原点(例如以Canvas中心(0.5, 0.5)、左下角(0.0, 0.1)等位置)进行旋转操作?
我尝试过为图像添加平移效果来围绕指定原点旋转,但当图像较大且部分超出Canvas时,需要让图像围绕Canvas中心点旋转,同时当前围绕Canvas中心点旋转的Demo存在指针拖拽对齐偏差的问题。
Demo说明
快捷键
- 按下"r"键:图像旋转5°
- 按下"-"键:图像缩小0.1倍
- 按下"="键:图像放大0.1倍
示例代码
JavaScript
let rotation = 0; let scale = 1; let x = 0; let y = 0; let startX = 0; let startY = 0; let lastX = 0; let lastY = 0; let pointerDown = false; const canvas = document.querySelector("#canvas"); const ctx = canvas.getContext("2d"); const imgWidth = 480; const imgHeight = 300; function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } resizeCanvas(); window.addEventListener("resize", resizeCanvas); const img = new Image(); img.crossOrigin = "anonymous"; img.src = "https://i.imgur.com/3q3kNGh.png"; function onPointerDown(event) { pointerDown = true; startX = (event.clientX - canvas.offsetLeft) / imgWidth; startY = (event.clientY - canvas.offsetTop) / imgHeight; } function onPointerMove(event) { if (!pointerDown) return; x = lastX + ((event.clientX - canvas.offsetLeft) / imgWidth - startX); y = lastY + ((event.clientY - canvas.offsetTop) / imgHeight - startY); } function onPointerUp() { pointerDown = false; lastX = x; lastY = y; } window.addEventListener("pointerdown", onPointerDown); window.addEventListener("pointermove", onPointerMove); window.addEventListener("pointerup", onPointerUp); window.addEventListener("keydown", (event) => { const key = event.key.toLowerCase(); switch (key) { case "r": rotation = (rotation + 5) % 360; break; case "-": scale = Math.max(0, scale - 0.1); break; case "=": scale = Math.min(2, scale + 0.1); break; default: break; } }); function rotate(x, y, rotation) { const panXX = x * Math.cos((rotation * Math.PI) / 180); const panXY = y * Math.sin((rotation * Math.PI) / 180); const panYY = y * Math.cos((rotation * Math.PI) / 180); const panYX = x * Math.sin((rotation * Math.PI) / 180); const panX = panXX + panXY; const panY = panYY - panYX; return { x: panX, y: panY }; } (function draw() { requestAnimationFrame(draw); const imgX = imgWidth * x; const imgY = imgHeight * y; const { x: tX, y: tY } = rotate(imgX, imgY, rotation); const matrix = new DOMMatrix() .translate(imgWidth / 2, imgHeight / 2) .rotate(rotation) .translate(imgWidth / -2, imgHeight / -2) .translate(tX, tY) .scale(scale); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.setTransform(matrix); ctx.drawImage(img, 0, 0, imgWidth, imgHeight); ctx.resetTransform(); })();
CSS
html, body { margin: 0; padding: 0; } canvas { display: block; }
HTML
<canvas id="canvas"></canvas>
内容的提问来源于stack exchange,提问作者James Craig
相关产品推荐
相关产品推荐

