我可以找到涉及jQuery UI lib的类似问题,或者只有没有拖动句柄的css,但纯数学没有。
我尝试执行的是拥有可调整大小且可旋转的div。到目前为止这么容易,我可以做到。
但旋转时会变得更复杂,调整大小手柄会以相反的方式进行计算:当拖离形状时,它会减小尺寸而不是增加。
除了计算之外,我希望能够根据旋转更改调整大小手柄的光标以使其始终有意义。 为此我想要检测哪个象限是调整大小句柄并应用一个类来通过css更改光标。
最后,如果有人有想法或更好的例子向我展示,我正在寻找用户体验改进!
以下是我的代码和Codepen:http://codepen.io/anon/pen/rrAWJA
<html>
<head>
<style>
html, body {height: 100%;}
#square {
width: 100px;
height: 100px;
margin: 20% auto;
background: orange;
position: relative;
}
.handle * {
position: absolute;
width: 20px;
height: 20px;
background: turquoise;
border-radius: 20px;
}
.resize {
bottom: -10px;
right: -10px;
cursor: nwse-resize;
}
.rotate {
top: -10px;
right: -10px;
cursor: alias;
}
</style>
<script type="text/javascript" src="js/jquery.js"></script>
<script>
$(document).ready(function()
{
new resizeRotate('#square');
});
var resizeRotate = function(targetElement)
{
var self = this;
self.target = $(targetElement);
self.handles = $('<div class="handle"><div class="resize" data-position="bottom-right"></div><div class="rotate"></div></div>');
self.currentRotation = 0;
self.positions = ['bottom-right', 'bottom-left', 'top-left', 'top-right'];
self.bindEvents = function()
{
self.handles
//=============================== Resize ==============================//
.on('mousedown', '.resize', function(e)
{
// Attach mouse move event only when first clicked.
$(document).on('mousemove', function(e)
{
var topLeft = self.target.offset(),
bottomRight = {x: topLeft.left + self.target.width(), y: topLeft.top + self.target.height()},
delta = {x: e.pageX - bottomRight.x, y: e.pageY - bottomRight.y};
self.target.css({width: '+=' + delta.x, height: '+=' + delta.y});
})
.one('mouseup', function(e)
{
// When releasing handle, round up width and height values :)
self.target.css({width: parseInt(self.target.width()), height: parseInt(self.target.height())});
$(document).off('mousemove');
});
})
//============================== Rotate ===============================//
.on('mousedown', '.rotate', function(e)
{
// Attach mouse move event only when first clicked.
$(document).on('mousemove', function(e)
{
var topLeft = self.target.offset(),
center = {x: topLeft.left + self.target.width() / 2, y: topLeft.top + self.target.height() / 2},
rad = Math.atan2(e.pageX - center.x, e.pageY - center.y),
deg = (rad * (180 / Math.PI) * -1) + 135;
self.currentRotation = deg;
// console.log(rad, deg);
self.target.css({transform: 'rotate(' + (deg)+ 'deg)'});
})
.one('mouseup', function(e)
{
$(document).off('mousemove');
// console.log(self.positions[parseInt(self.currentRotation/90-45)]);
$('.handle.resize').attr('data-position', self.positions[parseInt(self.currentRotation/90-45)]);
});
});
};
self.init = function()
{
self.bindEvents();
self.target.append(self.handles.clone(true));
}();
}
</script>
</head>
<body>
<div id="all">
<div id="square"></div>
</div>
</body>
</html>
感谢您的帮助!
答案 0 :(得分:2)
以下是对代码的修改,以实现您的目标:
$(document).ready(function() {
new resizeRotate('#square');
});
var resizeRotate = function(targetElement) {
var self = this;
self.target = $(targetElement);
self.handles = $('<div class="handle"><div class="resize" data-position="bottom-right"></div><div class="rotate"></div></div>');
self.currentRotation = 0;
self.w = parseInt(self.target.width());
self.h = parseInt(self.target.height());
self.positions = ['bottom-right', 'bottom-left', 'top-left', 'top-right'];
self.bindEvents = function() {
self.handles
//=============================== Resize ==============================//
.on('mousedown', '.resize', function(e) {
// Attach mouse move event only when first clicked.
$(document).on('mousemove', function(e) {
var topLeft = self.target.offset();
var centerX = topLeft.left + self.target.width() / 2;
var centerY = topLeft.top + self.target.height() / 2;
var mouseRelativeX = e.pageX - centerX;
var mouseRelativeY = e.pageY - centerY;
//reverse rotation
var rad = self.currentRotation * Math.PI / 180;
var s = Math.sin(rad);
var c = Math.cos(rad);
var mouseLocalX = c * mouseRelativeX + s * mouseRelativeY;
var mouseLocalY = -s * mouseRelativeX + c * mouseRelativeY;
self.w = 2 * mouseLocalX;
self.h = 2 * mouseLocalY;
self.target.css({
width: self.w,
height: self.h
});
})
.one('mouseup', function(e) {
$(document).off('mousemove');
});
})
//============================== Rotate ===============================//
.on('mousedown', '.rotate', function(e) {
// Attach mouse move event only when first clicked.
$(document).on('mousemove', function(e) {
var topLeft = self.target.offset(),
center = {
x: topLeft.left + self.target.width() / 2,
y: topLeft.top + self.target.height() / 2
},
rad = Math.atan2(e.pageX - center.x, center.y - e.pageY) - Math.atan(self.w / self.h),
deg = rad * 180 / Math.PI;
self.currentRotation = deg;
self.target.css({
transform: 'rotate(' + (deg) + 'deg)'
});
})
.one('mouseup', function(e) {
$(document).off('mousemove');
$('.handle.resize').attr('data-position', self.positions[parseInt(self.currentRotation / 90 - 45)]);
});
});
};
self.init = function() {
self.bindEvents();
self.target.append(self.handles.clone(true));
}();
}
主要变化如下:
在resize事件中,基于当前旋转将鼠标位置转换为局部坐标系。然后根据鼠标在本地系统中的位置确定大小。
旋转事件考虑了框的宽高比(- Math.atan(self.w / self.h)
部分)。
如果要根据当前旋转更改光标,请检查手柄的角度(即self.currentRotation + Math.atan(self.w / self.h) * 180 / Math.PI
)。例如。如果每个象限有一个光标,只需检查该值是否在0..90,90..180之间,依此类推。如果atan2
返回负数,您可能需要查看文档。
注意:偶尔的闪烁是由于盒子没有垂直居中造成的。
答案 1 :(得分:2)
Nico的答案基本上是正确的,但最终结果计算不正确->这导致闪烁的BTW。发生的事情是大小的增加或减小被2倍乘法加倍。应该将原始的半角宽度添加到新的半角宽度中,以计算出正确的新宽度和高度。
代替此:
self.w = 2 * mouseLocalX;
self.h = 2 * mouseLocalY;
应该是这样:
self.w = (self.target.width() / 2) + mouseLocalX;
self.h = (self.target.height() / 2) + mouseLocalY;