我找到了在javascript中创建DRR元素的一个很好的解决方案
目前,我希望有这个功能支持维持长宽比。
下面是代码片段:
var box = document.getElementById("box");
var boxWrapper = document.getElementById("box-wrapper");
const minWidth = 40;
const minHeight = 40;
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;
}
}
newX += 0.5 * rotatedWDiff * cosFraction;
newY += 0.5 * rotatedWDiff * sinFraction;
}
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;
}
}
newX -= 0.5 * rotatedHDiff * sinFraction;
newY += 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) {
// if (event.target.className.indexOf("dot") > -1) {
// return;
// }
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);
.box {
background-color: #00BCD4;
position: relative;
user-select: none;
transform: translate(-50%, -50%);
}
.box-wrapper {
position: absolute;
transform-origin: top left;
user-select: none;
}
.dot {
height: 10px;
width: 10px;
background-color: #1E88E5;
position: absolute;
border-radius: 100px;
border: 1px solid white;
user-select: none;
}
.dot:hover {
background-color: #0D47A1;
}
.dot.left-top {
top: -5px;
left: -5px;
/* cursor: nw-resize; */
}
.dot.left-bottom {
bottom: -5px;
left: -5px;
/* cursor: sw-resize; */
}
.dot.right-top {
top: -5px;
right: -5px;
/* cursor: ne-resize; */
}
.dot.right-bottom {
bottom: -5px;
right: -5px;
/* cursor: se-resize; */
}
.dot.top-mid {
top: -5px;
left: calc(50% - 5px);
/* cursor: n-resize; */
}
.dot.left-mid {
left: -5px;
top: calc(50% - 5px);
/* cursor: w-resize; */
}
.dot.right-mid {
right: -5px;
top: calc(50% - 5px);
/* cursor: e-resize; */
}
.dot.bottom-mid {
bottom: -5px;
left: calc(50% - 5px);
/* cursor: s-resize; */
}
.dot.rotate {
top: -30px;
left: calc(50% - 5px);
cursor: url('https://findicons.com/files/icons/1620/crystal_project/16/rotate_ccw.png'), auto;
}
.rotate-link {
position: absolute;
width: 1px;
height: 15px;
background-color: #1E88E5;
top: -20px;
left: calc(50% + 0.5px);
z-index: -1;
}
<div class="box-wrapper" id="box-wrapper">
<div class="box" id="box">
<div class="dot rotate" id="rotate"></div>
<div class="dot left-top" id="left-top"></div>
<div class="dot left-bottom" id="left-bottom"></div>
<div class="dot top-mid" id="top-mid"></div>
<div class="dot bottom-mid" id="bottom-mid"></div>
<div class="dot left-mid" id="left-mid"></div>
<div class="dot right-mid" id="right-mid"></div>
<div class="dot right-bottom" id="right-bottom"></div>
<div class="dot right-top" id="right-top"></div>
<div class="rotate-link"></div>
</div>
</div>
如果答案只与保持方形长宽比有关,我很好。
尝试解决方案:
- 在
resize
函数中,设置高度和宽度相等。 - 重新定位元素一旦调整大小,根据调整大小的元素的位置。但是,重新定位行为似乎与上述解决方案有故障(缺少某些东西/没有做对)。
目标:
- 修复纵横比
- 保持重新定位行为。
注意:
<旋转特性/strong>可以忽略,我正在寻找一个精确的重新定位元素。
谢谢!感谢您的宝贵回答。
这个问题有两个挑战:维持一个宽高比(这很简单)和基于锚点计算位置(从这个例子中可以看出这是棘手的)。
在原始示例中,分别计算每个维度的位置和大小(在同一代码块中计算宽度和x位置,然后计算高度和y位置):
if (xResize) {
// recalculate width
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;
}
}
// recalculate position
newX += 0.5 * rotatedWDiff * cosFraction;
newY += 0.5 * rotatedWDiff * sinFraction;
}
if (yResize) {
// recalculate height
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;
}
}
// recalculate position
newX -= 0.5 * rotatedHDiff * sinFraction;
newY += 0.5 * rotatedHDiff * cosFraction;
}
为了保持宽高比,你需要约束宽度和高度的相互关系,然后根据这些值重新定位。由于基于高度和宽度的重新定位现在是相互依赖的,这使得代码有点笨拙:
// calculate new width and height
if (xResize) {
if (left) {
newW = initW - rotatedWDiff;
} else {
newW = initW + rotatedWDiff;
}
if (newW < minWidth) {
newW = minWidth;
}
}
if (yResize) {
if (top) {
newH = initH - rotatedHDiff;
} else {
newH = initH + rotatedHDiff;
}
if (newH < minHeight) {
newH = minHeight;
}
}
// constrain aspect ratio, if a corner is being dragged
var scale;
if (xResize && yResize) {
scale = Math.max(newW / initW, newH / initH);
newW = scale * initW;
newH = scale * initH;
}
// recalculate position
if (xResize) {
if (left) {
rotatedWDiff = initW - newW;
} else {
rotatedWDiff = newW - initW;
}
newX += 0.5 * rotatedWDiff * cosFraction;
newY += 0.5 * rotatedWDiff * sinFraction;
}
if (yResize) {
if (top) {
rotatedHDiff = initH - newH;
} else {
rotatedHDiff = newH - initH;
}
newX -= 0.5 * rotatedHDiff * sinFraction;
newY += 0.5 * rotatedHDiff * cosFraction;
}
总的来说是这样的:
var box = document.getElementById("box");
var boxWrapper = document.getElementById("box-wrapper");
const minWidth = 40;
const minHeight = 40;
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;
// calculate new width and height
if (xResize) {
if (left) {
newW = initW - rotatedWDiff;
} else {
newW = initW + rotatedWDiff;
}
if (newW < minWidth) {
newW = minWidth;
}
}
if (yResize) {
if (top) {
newH = initH - rotatedHDiff;
} else {
newH = initH + rotatedHDiff;
}
if (newH < minHeight) {
newH = minHeight;
}
}
var scale;
// constrain aspect ratio, if a corner is being dragged
// can remove the conditional if aspect ratio should always be preserved
if (xResize && yResize) {
scale = Math.max(newW / initW, newH / initH);
newW = scale * initW;
newH = scale * initH;
}
// recalculate position
if (xResize) {
if (left) {
rotatedWDiff = initW - newW;
} else {
rotatedWDiff = newW - initW;
}
newX += 0.5 * rotatedWDiff * cosFraction;
newY += 0.5 * rotatedWDiff * sinFraction;
}
if (yResize) {
if (top) {
rotatedHDiff = initH - newH;
} else {
rotatedHDiff = newH - initH;
}
newX -= 0.5 * rotatedHDiff * sinFraction;
newY += 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) {
// if (event.target.className.indexOf("dot") > -1) {
// return;
// }
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(300, 200);
repositionElement(200, 200);
.box {
background-color: #00BCD4;
position: relative;
user-select: none;
transform: translate(-50%, -50%);
}
.box-wrapper {
position: absolute;
transform-origin: top left;
user-select: none;
}
.dot {
height: 10px;
width: 10px;
background-color: #1E88E5;
position: absolute;
border-radius: 100px;
border: 1px solid white;
user-select: none;
}
.dot:hover {
background-color: #0D47A1;
}
.dot.left-top {
top: -5px;
left: -5px;
/* cursor: nw-resize; */
}
.dot.left-bottom {
bottom: -5px;
left: -5px;
/* cursor: sw-resize; */
}
.dot.right-top {
top: -5px;
right: -5px;
/* cursor: ne-resize; */
}
.dot.right-bottom {
bottom: -5px;
right: -5px;
/* cursor: se-resize; */
}
.dot.top-mid {
top: -5px;
left: calc(50% - 5px);
/* cursor: n-resize; */
}
.dot.left-mid {
left: -5px;
top: calc(50% - 5px);
/* cursor: w-resize; */
}
.dot.right-mid {
right: -5px;
top: calc(50% - 5px);
/* cursor: e-resize; */
}
.dot.bottom-mid {
bottom: -5px;
left: calc(50% - 5px);
/* cursor: s-resize; */
}
.dot.rotate {
top: -30px;
left: calc(50% - 5px);
cursor: url('https://findicons.com/files/icons/1620/crystal_project/16/rotate_ccw.png'), auto;
}
.rotate-link {
position: absolute;
width: 1px;
height: 15px;
background-color: #1E88E5;
top: -20px;
left: calc(50% + 0.5px);
z-index: -1;
}
<div class="box-wrapper" id="box-wrapper">
<div class="box" id="box">
<div class="dot rotate" id="rotate"></div>
<div class="dot left-top" id="left-top"></div>
<div class="dot left-bottom" id="left-bottom"></div>
<div class="dot top-mid" id="top-mid"></div>
<div class="dot bottom-mid" id="bottom-mid"></div>
<div class="dot left-mid" id="left-mid"></div>
<div class="dot right-mid" id="right-mid"></div>
<div class="dot right-bottom" id="right-bottom"></div>
<div class="dot right-top" id="right-top"></div>
<div class="rotate-link"></div>
</div>
</div>
你也可以依靠CSS规则aspect-ratio:
如果你使用minWidth
和minHeight
来调整元素的大小,它可能有助于重置和保持比率。
下面的示例,使用一些reset on resize(X,X)函数来测试行为:)
const box = document.getElementById("box");
var boxWrapper = document.getElementById("box-wrapper");
const minWidth = 40;
const minHeight = 40;
function resetSize() {// shrinks it to the min size set (unless content inside takes bigger room
box.style.width = '0';
box.style.height = '0';
}
function setCssRatio() {// get ratio from its size
let bH = box.offsetHeight;
let bW = box.offsetWidth;
let dif = bH / bW;
document.documentElement.style.setProperty("--ratio", "1/" + dif);
document.querySelector('#box p').innerHTML = "calculated ratio: <br> 1 / " + dif.toFixed(1);
box.style.width = 'auto';
box.style.height = 'auto';
}
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.minWidth = w + 'px';
box.style.minHeight = h + 'px';
setCssRatio();
}
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;
}
}
newX += 0.5 * rotatedWDiff * cosFraction;
newY += 0.5 * rotatedWDiff * sinFraction;
}
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;
}
}
newX -= 0.5 * rotatedHDiff * sinFraction;
newY += 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) {
// if (event.target.className.indexOf("dot") > -1) {
// return;
// }
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(220, 300);
repositionElement(200, 200);
.box {
background-color: #00BCD4;
position: relative;
user-select: none;
transform: translate(-50%, -50%);
}
.box-wrapper {
position: absolute;
transform-origin: top left;
user-select: none;
}
.dot {
height: 10px;
width: 10px;
background-color: #1E88E5;
position: absolute;
border-radius: 100px;
border: 1px solid white;
user-select: none;
}
.dot:hover {
background-color: #0D47A1;
}
.dot.left-top {
top: -5px;
left: -5px;
/* cursor: nw-resize; */
}
.dot.left-bottom {
bottom: -5px;
left: -5px;
/* cursor: sw-resize; */
}
.dot.right-top {
top: -5px;
right: -5px;
/* cursor: ne-resize; */
}
.dot.right-bottom {
bottom: -5px;
right: -5px;
/* cursor: se-resize; */
}
.dot.top-mid {
top: -5px;
left: calc(50% - 5px);
/* cursor: n-resize; */
}
.dot.left-mid {
left: -5px;
top: calc(50% - 5px);
/* cursor: w-resize; */
}
.dot.right-mid {
right: -5px;
top: calc(50% - 5px);
/* cursor: e-resize; */
}
.dot.bottom-mid {
bottom: -5px;
left: calc(50% - 5px);
/* cursor: s-resize; */
}
.dot.rotate {
top: -30px;
left: calc(50% - 5px);
cursor: url('https://findicons.com/files/icons/1620/crystal_project/16/rotate_ccw.png'), auto;
}
.rotate-link {
position: absolute;
width: 1px;
height: 15px;
background-color: #1E88E5;
top: -20px;
left: calc(50% + 0.5px);
z-index: -1;
}
#box {
aspect-ratio: var(--ratio);
display: flex;
}
#box p {
margin: auto;
text-align: center;
}
<div class="box-wrapper" id="box-wrapper">
<div class="box" id="box">
<p></p>
<div class="dot rotate" id="rotate"></div>
<div class="dot left-top" id="left-top"></div>
<div class="dot left-bottom" id="left-bottom"></div>
<div class="dot top-mid" id="top-mid"></div>
<div class="dot bottom-mid" id="bottom-mid"></div>
<div class="dot left-mid" id="left-mid"></div>
<div class="dot right-mid" id="right-mid"></div>
<div class="dot right-bottom" id="right-bottom"></div>
<div class="dot right-top" id="right-top"></div>
<div class="rotate-link"></div>
</div>
</div>
<button onclick="resize(150,150);resetSize();setCssRatio();return false;">set a square</button>
<button onclick="resize(200,100);;resetSize();setCssRatio();return false;">set a 200x100</button>
<button onclick="resize(100,200);;resetSize();setCssRatio();return false;">set a 100x200</button>
在eventMoveHandler
设置宽高比,并删除xResize和yResize检查它将工作。
var box = document.getElementById("box");
var boxWrapper = document.getElementById("box-wrapper");
const minWidth = 40;
const minHeight = 40;
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;
acptRatio = initW/initH;
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);
if(wDiff > hDiff) hDiff = wDiff/acptRatio;
else wDiff = hDiff*acptRatio;
var rotatedWDiff = cosFraction * wDiff + sinFraction * hDiff;
var rotatedHDiff = cosFraction * hDiff - sinFraction * wDiff;
var newW = initW, newH = initH, newX = initX, newY = initY;
//if (xResize || true) {
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;
}
}
newX += 0.5 * rotatedWDiff * cosFraction;
newY += 0.5 * rotatedWDiff * sinFraction;
// }
//if (yResize || true) {
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;
}
}
newX -= 0.5 * rotatedHDiff * sinFraction;
newY += 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) {
// if (event.target.className.indexOf("dot") > -1) {
// return;
// }
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);
.box {
background-color: #00BCD4;
position: relative;
user-select: none;
transform: translate(-50%, -50%);
}
.box-wrapper {
position: absolute;
transform-origin: top left;
user-select: none;
}
.dot {
height: 10px;
width: 10px;
background-color: #1E88E5;
position: absolute;
border-radius: 100px;
border: 1px solid white;
user-select: none;
}
.dot:hover {
background-color: #0D47A1;
}
.dot.left-top {
top: -5px;
left: -5px;
/* cursor: nw-resize; */
}
.dot.left-bottom {
bottom: -5px;
left: -5px;
/* cursor: sw-resize; */
}
.dot.right-top {
top: -5px;
right: -5px;
/* cursor: ne-resize; */
}
.dot.right-bottom {
bottom: -5px;
right: -5px;
/* cursor: se-resize; */
}
.dot.top-mid {
top: -5px;
left: calc(50% - 5px);
/* cursor: n-resize; */
}
.dot.left-mid {
left: -5px;
top: calc(50% - 5px);
/* cursor: w-resize; */
}
.dot.right-mid {
right: -5px;
top: calc(50% - 5px);
/* cursor: e-resize; */
}
.dot.bottom-mid {
bottom: -5px;
left: calc(50% - 5px);
/* cursor: s-resize; */
}
.dot.rotate {
top: -30px;
left: calc(50% - 5px);
cursor: url('https://findicons.com/files/icons/1620/crystal_project/16/rotate_ccw.png'), auto;
}
.rotate-link {
position: absolute;
width: 1px;
height: 15px;
background-color: #1E88E5;
top: -20px;
left: calc(50% + 0.5px);
z-index: -1;
}
<div class="box-wrapper" id="box-wrapper">
<div class="box" id="box">
<div class="dot rotate" id="rotate"></div>
<div class="dot left-top" id="left-top"></div>
<div class="dot left-bottom" id="left-bottom"></div>
<div class="dot top-mid" id="top-mid"></div>
<div class="dot bottom-mid" id="bottom-mid"></div>
<div class="dot left-mid" id="left-mid"></div>
<div class="dot right-mid" id="right-mid"></div>
<div class="dot right-bottom" id="right-bottom"></div>
<div class="dot right-top" id="right-top"></div>
<div class="rotate-link"></div>
</div>
</div>