旋转后图片拖拽异常问题求助(附JavaScript代码)
图片拖拽+旋转功能异常排查与修复
问题现象
原本正常的图片拖拽功能,添加旋转按钮后出现以下异常:
- 旋转图片后拖拽,坐标会严重偏移
- 点击旋转按钮,图片会回到初始拖拽位置
- 再次拖拽时,图片直接跳回最开始的初始位置
问题根源
- 旋转操作覆盖拖拽位置:
rot_plus和rot_minus函数直接用rotate覆盖整个transform属性,冲掉了之前拖拽产生的translate3d,导致位置重置。 - 拖拽计算未适配旋转坐标系:元素旋转后,页面坐标系和元素自身坐标系产生夹角,原拖拽偏移计算方式不再适用,导致坐标偏移。
- 初始位置存储逻辑错误:
dragEnd中直接把currentX/Y赋值给initialX/Y,未考虑旋转对元素实际位置的影响,再次拖拽时计算基准错误。
修复后的完整代码
HTML部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> </head> <body> <div id="boite"> <img src="https://static.vecteezy.com/system/resources/previews/009/342/282/original/cartoon-eyes-clipart-design-illustration-free-png.png" id="test" class="remove" style="position: absolute; width:150px; height:auto; transform-origin: center center;"> <svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" fill="currentColor" class="bi bi-plus-circle" id="rotplus" style="margin-top:120px" onclick="rot_plus()" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/> <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/> </svg> <svg xmlns="http://www.w3.org/2000/svg"width="46" height="46" fill="currentColor" class="bi bi-dash-circle" id="rotminus" style="margin-top:120px" onclick="rot_minus()" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/> <path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/> </svg> </div> </body> </html>
JavaScript部分
let rotate = 0; // 存储当前的偏移量,避免旋转时丢失 let xOffset = 0; let yOffset = 0; let active = false; let dragItem = null; let container = document.querySelector("#boite"); container.addEventListener("mousedown", dragStart, false); container.addEventListener("mouseup", dragEnd, false); container.addEventListener("mousemove", drag, false); function rot_plus() { rotate += 10; // 调用统一的setTranslate,保留当前偏移 setTranslate(xOffset, yOffset, document.querySelector("#test")); } function rot_minus() { rotate -= 10; setTranslate(xOffset, yOffset, document.querySelector("#test")); } function dragStart(e) { if (e.target.id === "test") { dragItem = e.target; // 获取元素当前的实际位置,计算初始偏移基准 const rect = dragItem.getBoundingClientRect(); // 计算鼠标相对于元素中心点的偏移(适配旋转) const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; const mouseX = e.clientX - centerX; const mouseY = e.clientY - centerY; // 旋转鼠标偏移量,转换为元素坐标系下的偏移 const rad = (rotate * Math.PI) / 180; const rotatedMouseX = mouseX * Math.cos(rad) + mouseY * Math.sin(rad); const rotatedMouseY = -mouseX * Math.sin(rad) + mouseY * Math.cos(rad); // 设置初始位置基准 initialX = e.clientX - rotatedMouseX - xOffset; initialY = e.clientY - rotatedMouseY - yOffset; active = true; } } function drag(e) { if (active && dragItem) { e.preventDefault(); const rad = (rotate * Math.PI) / 180; // 计算当前鼠标相对于初始基准的偏移 const currentMouseX = e.clientX - initialX; const currentMouseY = e.clientY - initialY; // 转换为元素坐标系下的偏移(反向旋转) xOffset = currentMouseX * Math.cos(rad) + currentMouseY * Math.sin(rad); yOffset = -currentMouseX * Math.sin(rad) + currentMouseY * Math.cos(rad); setTranslate(xOffset, yOffset, dragItem); } } function dragEnd(e) { active = false; dragItem = null; } function setTranslate(xPos, yPos, el) { // 同时设置translate和rotate,确保两者都保留 el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0) rotate(${rotate}deg)`; }
关键修复点
- 统一更新transform:旋转时不再单独设置rotate,而是调用
setTranslate函数,同时保留translate和rotate属性,避免位置丢失。 - 适配旋转坐标系:拖拽开始和过程中,将鼠标坐标转换为元素旋转后的自身坐标系,确保拖拽偏移计算准确,解决坐标偏移问题。
- 修正初始位置基准:基于元素实际位置和旋转角度计算初始拖拽基准,避免再次拖拽时跳回初始位置。
效果截图
- 旋转前:

- 旋转后:

- 旋转后拖拽:

内容的提问来源于stack exchange,提问作者Nour Hariz
相关产品推荐
相关产品推荐

