javascript 如何通过拖动使对象旋转,如何使用 sin 或 cos 获得围绕原点的旋转点?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14599738/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make object rotate with drag, how to get a rotate point around the origin use sin or cos?
提问by user1775888
I've been searching long time, but can't find a better way solve my problem,
make div draggable, rotate and resize by each handle like these 2 example 12,, now it can be draggable, but rotate..
我已经搜索了很长时间,但找不到更好的方法来解决我的问题,
使 div 可拖动,通过每个手柄旋转和调整大小,就像这两个示例1 2,现在它可以拖动,但旋转..
Regarding Prasanth K C, Chango, Yi Jiang..'s answer, these code maybe not correct,
1. it should have a rotate point around the origin.
2. need to consider radius.
But I don't know how to use sin or cos here to make rotate consider radius?
Any suggestion will be be appreciated.
http://jsfiddle.net/tBgLh/8/
关于Prasanth KC、Chango、Yi Jiang.. 的回答,这些代码可能不正确,
1. 它应该有一个围绕原点的旋转点。
2.需要考虑半径。
但我不知道如何在这里使用 sin 或 cos 来使旋转考虑半径?
任何建议将不胜感激。
http://jsfiddle.net/tBgLh/8/
var dragging = false, target_wp;
$('.handle').mousedown(function(e) {
var o_x = e.pageX, o_y = e.pageY; // origin point
e.preventDefault();
e.stopPropagation();
dragging = true;
target_wp=$(e.target).closest('.draggable_wp');
$(document).mousemove(function(e) {
if (dragging) {
var s_x = e.pageX, s_y = e.pageY; // start rotate point
if(s_x !== o_x && s_y !== o_y){ //start rotate
var s_rad = Math.atan2(s_y, s_x);
var degree = (s_rad * (360 / (2 * Math.PI)));
target_wp.css('-moz-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-moz-transform-origin', '50% 50%');
target_wp.css('-webkit-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-webkit-transform-origin', '50% 50%');
target_wp.css('-o-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-o-transform-origin', '50% 50%');
target_wp.css('-ms-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-ms-transform-origin', '50% 50%');
}
}
})
$(document).mouseup(function() {
dragging = false
})
})// end mousemove
html
html
<div class="draggable_wp">
<div class="el"></div>
<div class="handle"></div>
</div>
回答by mgibsonbr
There are two problems with your approach:
你的方法有两个问题:
The origin shouldn't be where the user clicked (that is the handle), but a fixed point in your div:
target_wp=$(e.target).closest('.draggable_wp'); //var o_x = e.pageX, o_y = e.pageY; // origin point var o_x = target_wp.offset().left, o_y = target_wp.offset().top; // origin point
You willuse the clicked point also, but for something else (more later):
var h_x = e.pageX, h_y = e.pageY; // clicked point
Finally, the origin should be fixed (i.e. should not change between rotations). One way of doing so is preserving it as a
data
attribute (there are other options though):if ( !target_wp.data("origin") ) target_wp.data("origin", { left:target_wp.offset().left, top:target_wp.offset().top }); var o_x = target_wp.data("origin").left, o_y = target_wp.data("origin").top; // origin point
Update:One good candidate for the origin is the CSS property
transform-origin
, if present - it should ensure that the mouse follow the handle as closely as possible. This is an experimental feature, however, so the actual resulsts may vary. P.S. I'm not sure setting it to50% 50%
is a good idea, since the transformation itself may vary the element's width and height, top and left.To find the angle, you should not call
atan2
on the mouse point only, since it will only calculate the angle between that point and the top left corner of the page. You want the angle between that point and the origin:var s_rad = Math.atan2(s_y - o_y, s_x - o_x); // current to origin
That'll lead you halfway, but it will still behave oddly (it will rotate around the element origin, but not following the handle as you expect). To make it follow the handle, you should adjust the angle in relation to the clicked point - which will serve as a base for the amount to rotate:
s_rad -= Math.atan2(h_y - o_y, h_x - o_x); // handle to origin
After that you get the rotation working(for one user iteration at least).
原点不应该是用户单击的位置(即手柄),而是 div 中的一个固定点:
target_wp=$(e.target).closest('.draggable_wp'); //var o_x = e.pageX, o_y = e.pageY; // origin point var o_x = target_wp.offset().left, o_y = target_wp.offset().top; // origin point
您还将使用单击点,但用于其他用途(稍后会详细介绍):
var h_x = e.pageX, h_y = e.pageY; // clicked point
最后,原点应该是固定的(即不应该在旋转之间改变)。这样做的一种方法是将其保留为
data
属性(尽管还有其他选项):if ( !target_wp.data("origin") ) target_wp.data("origin", { left:target_wp.offset().left, top:target_wp.offset().top }); var o_x = target_wp.data("origin").left, o_y = target_wp.data("origin").top; // origin point
更新:原点的一个很好的候选者是 CSS 属性
transform-origin
(如果存在) - 它应确保鼠标尽可能靠近句柄。然而,这是一项实验性功能,因此实际结果可能会有所不同。PS 我不确定将它设置50% 50%
为一个好主意,因为转换本身可能会改变元素的宽度和高度、顶部和左侧。要找到角度,您不应
atan2
只调用鼠标点,因为它只会计算该点与页面左上角之间的角度。您想要该点与原点之间的角度:var s_rad = Math.atan2(s_y - o_y, s_x - o_x); // current to origin
这会导致你半途而废,但它的行为仍然很奇怪(它会围绕元素原点旋转,但不会像你期望的那样跟随手柄)。要使其跟随手柄,您应该调整与单击点相关的角度 - 这将作为旋转量的基础:
s_rad -= Math.atan2(h_y - o_y, h_x - o_x); // handle to origin
之后,你得到的旋转工作(对于一个用户迭代至少)。
You'll notice the handle does not follow the mouse precisely, and the reason is the choice of the origin point - defaulting to the element's top/left corner. Adjust it to somewhere inside the element (maybe using a data-
attribute) and it should work as expected.
您会注意到手柄没有精确跟随鼠标,原因是原点的选择 - 默认为元素的上/左角。将其调整到元素内部的某个位置(可能使用data-
属性),它应该会按预期工作。
However, if the user interacts with the handle multiple times, it's not enough to just setthe rotation angle, you must updatewhatever it was during the last iteration. So I'm adding a last_angle
var that will be set on the first click and then added to the final angle during drag:
但是,如果用户多次与手柄交互,仅设置旋转角度是不够的,您必须更新上次迭代期间的任何内容。所以我添加了一个last_angle
变量,它将在第一次点击时设置,然后在拖动过程中添加到最终角度:
// on mousedown
last_angle = target_wp.data("last_angle") || 0;
// on mousemove
s_rad += last_angle; // relative to the last one
// on mouseup
target_wp.data("last_angle", s_rad);
Here's the final working example. (Note: I fixed the nesting of your mouse handlers, so they don't get added again after each click)
这是最终的工作示例。(注意:我修复了鼠标处理程序的嵌套问题,因此每次单击后它们都不会再次添加)
$(function () {
var dragging = false,
target_wp,
o_x, o_y, h_x, h_y, last_angle;
$('.handle').mousedown(function (e) {
h_x = e.pageX;
h_y = e.pageY; // clicked point
e.preventDefault();
e.stopPropagation();
dragging = true;
target_wp = $(e.target).closest('.draggable_wp');
if (!target_wp.data("origin")) target_wp.data("origin", {
left: target_wp.offset().left,
top: target_wp.offset().top
});
o_x = target_wp.data("origin").left;
o_y = target_wp.data("origin").top; // origin point
last_angle = target_wp.data("last_angle") || 0;
})
$(document).mousemove(function (e) {
if (dragging) {
var s_x = e.pageX,
s_y = e.pageY; // start rotate point
if (s_x !== o_x && s_y !== o_y) { //start rotate
var s_rad = Math.atan2(s_y - o_y, s_x - o_x); // current to origin
s_rad -= Math.atan2(h_y - o_y, h_x - o_x); // handle to origin
s_rad += last_angle; // relative to the last one
var degree = (s_rad * (360 / (2 * Math.PI)));
target_wp.css('-moz-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-moz-transform-origin', '50% 50%');
target_wp.css('-webkit-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-webkit-transform-origin', '50% 50%');
target_wp.css('-o-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-o-transform-origin', '50% 50%');
target_wp.css('-ms-transform', 'rotate(' + degree + 'deg)');
target_wp.css('-ms-transform-origin', '50% 50%');
}
}
}) // end mousemove
$(document).mouseup(function (e) {
dragging = false
var s_x = e.pageX,
s_y = e.pageY;
// Saves the last angle for future iterations
var s_rad = Math.atan2(s_y - o_y, s_x - o_x); // current to origin
s_rad -= Math.atan2(h_y - o_y, h_x - o_x); // handle to origin
s_rad += last_angle;
target_wp.data("last_angle", s_rad);
})
})
.draggable_wp {
position: absolute;
left: 150px;
top: 150px;
}
.el {
width: 25px;
height: 50px;
background-color: yellow;
}
.handle {
position: absolute;
left:0;
top:-75;
width: 25px;
height: 25px;
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="draggable_wp">
<div class="el"></div>
<div class="handle"></div>
</div>
回答by jarekpelczynski
They use a matrix function in a transform properties. You can rotate element by muliplay your matrix (element coordinates) by rotation matrix.
他们在变换属性中使用矩阵函数。您可以通过旋转矩阵通过多重播放您的矩阵(元素坐标)来旋转元素。
transform: matrix(a, c, b, d, tx, ty)
More info and examples here: The CSS3 matrix() Transform for the Mathematically Challenged
更多信息和示例在这里:CSS3 matrix() Transform for the Mathematically Challenged