Как заставить объект вращаться с помощью перетаскивания, как получить точку поворота вокруг начала использовать sin или cos?

Я искал много времени, но не могу найти лучший способ решить мою проблему,
сделать div перетаскиваемым, повернуть и изменить размер каждого дескриптора, как эти 2 пример 1 2, теперь его можно перетаскивать, но вращать..

Относительно 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

<div class="draggable_wp">
    <div class="el"></div>
    <div class="handle"></div>
</div>

Ответ 1

В вашем подходе есть две проблемы:

  • Происхождение не должно быть там, где пользователь нажал (это дескриптор), но фиксированная точка в вашем 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, если оно присутствует - оно должно гарантировать, что мышь ручку как можно ближе. Однако это экспериментальная функция, поэтому фактические результаты могут различаться. Постскриптум Я не уверен, что настройка на 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
    

    После этого вы получите поворот (для одной итерации пользователя как минимум).

Вы заметите, что дескриптор не точно соответствует мышью, и причина в выборе точки начала - по умолчанию для верхнего/левого угла элемента. Отрегулируйте его где-нибудь внутри элемента (возможно, используя атрибут data-), и он должен работать как ожидалось.

Однако, если пользователь взаимодействует с дескриптором несколько раз, этого недостаточно, чтобы просто установить угол поворота, вы должны обновить все, что было на последней итерации. Поэтому я добавляю last_angle var, который будет установлен на первом клике, а затем добавлен к окончательному углу во время перетаскивания:

// 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);

Здесь приведен рабочий пример . (Примечание: я исправил вложенность ваших обработчиков мыши, поэтому они не добавляются снова после каждого нажатия)

$(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>

Ответ 2

Они используют матричную функцию в свойствах преобразования. Вы можете повернуть элемент посредством muliplay вашей матрицы (координаты элемента) с помощью матрицы поворота.

transform:  matrix(a, c, b, d, tx, ty)

Дополнительная информация и примеры здесь: Матрица CSS3() Преобразование для математически оспариваемых