如何修复可拖拽缩放(DRR)元素的宽高比,实现等比例调整
实现方案
你只需要修改JS部分代码即可实现1:1等比例锁定,同时保留原有拖拽、缩放的定位逻辑无卡顿偏移,CSS和HTML无需改动。
核心修改逻辑
- 新增全局固定宽高比配置,可按需调整比例
- 在缩放的鼠标移动回调中,同步宽高数值的同时,修正对应的偏移参数,保证位置计算准确
完整修改后的JS代码
var box = document.getElementById("box"); var boxWrapper = document.getElementById("box-wrapper"); const minWidth = 40; const minHeight = 40; // 新增:固定宽高比,1表示1:1正方形,可按需修改为其他值 const ASPECT_RATIO = 1; var initX, initY, mousePressX, mousePressY, initW, initH, initRotate; function repositionElement(x, y) { boxWrapper.style.left = x + 'px'; boxWrapper.style.top = y + 'px'; } function resize(w, h) { box.style.width = w + 'px'; box.style.height = h + 'px'; } function getCurrentRotation(el) { var st = window.getComputedStyle(el, null); var tm = st.getPropertyValue("-webkit-transform") || st.getPropertyValue("-moz-transform") || st.getPropertyValue("-ms-transform") || st.getPropertyValue("-o-transform") || st.getPropertyValue("transform") || "none"; if (tm != "none") { var values = tm.split('(')[1].split(')')[0].split(','); var angle = Math.round(Math.atan2(values[1], values[0]) * (180 / Math.PI)); return (angle < 0 ? angle + 360 : angle); } return 0; } function rotateBox(deg) { boxWrapper.style.transform = `rotate(${deg}deg)`; } // drag support boxWrapper.addEventListener('mousedown', function (event) { if (event.target.className.indexOf("dot") > -1) { return; } initX = this.offsetLeft; initY = this.offsetTop; mousePressX = event.clientX; mousePressY = event.clientY; function eventMoveHandler(event) { repositionElement(initX + (event.clientX - mousePressX), initY + (event.clientY - mousePressY)); } boxWrapper.addEventListener('mousemove', eventMoveHandler, false); window.addEventListener('mouseup', function eventEndHandler() { boxWrapper.removeEventListener('mousemove', eventMoveHandler, false); window.removeEventListener('mouseup', eventEndHandler); }, false); }, false); // done drag support // handle resize var rightMid = document.getElementById("right-mid"); var leftMid = document.getElementById("left-mid"); var topMid = document.getElementById("top-mid"); var bottomMid = document.getElementById("bottom-mid"); var leftTop = document.getElementById("left-top"); var rightTop = document.getElementById("right-top"); var rightBottom = document.getElementById("right-bottom"); var leftBottom = document.getElementById("left-bottom"); function resizeHandler(event, left = false, top = false, xResize = false, yResize = false) { initX = boxWrapper.offsetLeft; initY = boxWrapper.offsetTop; mousePressX = event.clientX; mousePressY = event.clientY; initW = box.offsetWidth; initH = box.offsetHeight; initRotate = getCurrentRotation(boxWrapper); var initRadians = initRotate * Math.PI / 180; var cosFraction = Math.cos(initRadians); var sinFraction = Math.sin(initRadians); function eventMoveHandler(event) { var wDiff = (event.clientX - mousePressX); var hDiff = (event.clientY - mousePressY); var rotatedWDiff = cosFraction * wDiff + sinFraction * hDiff; var rotatedHDiff = cosFraction * hDiff - sinFraction * wDiff; var newW = initW, newH = initH, newX = initX, newY = initY; if (xResize) { if (left) { newW = initW - rotatedWDiff; if (newW < minWidth) { newW = minWidth; rotatedWDiff = initW - minWidth; } } else { newW = initW + rotatedWDiff; if (newW < minWidth) { newW = minWidth; rotatedWDiff = minWidth - initW; } } } if (yResize) { if (top) { newH = initH - rotatedHDiff; if (newH < minHeight) { newH = minHeight; rotatedHDiff = initH - minHeight; } } else { newH = initH + rotatedHDiff; if (newH < minHeight) { newH = minHeight; rotatedHDiff = minHeight - initH; } } } // 新增:同步宽高保持固定比例 if (xResize && yResize) { // 拖拽角的情况,取变化幅度更大的维度作为基准 const wChange = Math.abs(newW - initW); const hChange = Math.abs(newH - initH); if (wChange > hChange) { newH = newW * ASPECT_RATIO; } else { newW = newH / ASPECT_RATIO; } } else if (xResize) { // 拖拽左右边的情况,以宽度为基准同步高度 newH = newW * ASPECT_RATIO; } else if (yResize) { // 拖拽上下边的情况,以高度为基准同步宽度 newW = newH / ASPECT_RATIO; } // 修正最小尺寸限制 if (newW < minWidth) { newW = minWidth; newH = newW * ASPECT_RATIO; } if (newH < minHeight) { newH = minHeight; newW = newH / ASPECT_RATIO; } // 同步更新偏移量,保证位置计算准确 rotatedWDiff = left ? initW - newW : newW - initW; rotatedHDiff = top ? initH - newH : newH - initH; // 重新计算位置 newX = initX + 0.5 * rotatedWDiff * cosFraction - 0.5 * rotatedHDiff * sinFraction; newY = initY + 0.5 * rotatedWDiff * sinFraction + 0.5 * rotatedHDiff * cosFraction; resize(newW, newH); repositionElement(newX, newY); } window.addEventListener('mousemove', eventMoveHandler, false); window.addEventListener('mouseup', function eventEndHandler() { window.removeEventListener('mousemove', eventMoveHandler, false); window.removeEventListener('mouseup', eventEndHandler); }, false); } rightMid.addEventListener('mousedown', e => resizeHandler(e, false, false, true, false)); leftMid.addEventListener('mousedown', e => resizeHandler(e, true, false, true, false)); topMid.addEventListener('mousedown', e => resizeHandler(e, false, true, false, true)); bottomMid.addEventListener('mousedown', e => resizeHandler(e, false, false, false, true)); leftTop.addEventListener('mousedown', e => resizeHandler(e, true, true, true, true)); rightTop.addEventListener('mousedown', e => resizeHandler(e, false, true, true, true)); rightBottom.addEventListener('mousedown', e => resizeHandler(e, false, false, true, true)); leftBottom.addEventListener('mousedown', e => resizeHandler(e, true, false, true, true)); // handle rotation var rotate = document.getElementById("rotate"); rotate.addEventListener('mousedown', function (event) { initX = this.offsetLeft; initY = this.offsetTop; mousePressX = event.clientX; mousePressY = event.clientY; var arrow = document.querySelector("#box"); var arrowRects = arrow.getBoundingClientRect(); var arrowX = arrowRects.left + arrowRects.width / 2; var arrowY = arrowRects.top + arrowRects.height / 2; function eventMoveHandler(event) { var angle = Math.atan2(event.clientY - arrowY, event.clientX - arrowX) + Math.PI / 2; rotateBox(angle * 180 / Math.PI); } window.addEventListener('mousemove', eventMoveHandler, false); window.addEventListener('mouseup', function eventEndHandler() { window.removeEventListener('mousemove', eventMoveHandler, false); window.removeEventListener('mouseup', eventEndHandler); }, false); }, false); resize(200, 200); repositionElement(200, 200);
使用说明
如果需要切换其他宽高比,直接修改顶部ASPECT_RATIO的数值即可,比如设置为16/9就会固定为16:9的宽高比。
内容的提问来源于stack exchange,提问作者Ranjeet Eppakayala
相关产品推荐
相关产品推荐

