JQuery.position() странность при использовании атрибута поворота CSS3

Я получаю абсолютно позиционированное положение позиций с помощью метода jQuery .position(), а затем устанавливаю атрибуты, связанные с позицией (сверху, слева) с помощью jQuery .css(pos), где pos - это данные, возвращаемые .position(). Я думаю, что он оставит элемент в нем, но положение элементов меняется.

Как я могу использовать позицию с установленными вращающимися элементами, чтобы она была размещена так, как ожидалось? Может быть, существует коэффициент, зависящий от угла, который меняет положение?

Я тестирую Google Chrome v.9, Windows XP.

HTML

<div id="container">
  <div id="element"> 
    <img src="http://t0.gstatic.com/images?q=tbn:ANd9GcS0Fawya9MVMez80ZusMVtk_4-ScKCIy6J_fg84oZ37GzKaJXU74Ma0vENc"/>
  </div>
</div> 

CSS

#container {
    position: relative;   
    border: 1px solid #999;
    padding: 5px;
    height: 300px;
    width:300px;
}    
#element {
    position: absolute;
    top:50px;
    left: 60px;
    width: auto;
    border: 1px solid #999;
    padding: 5px;
    -webkit-transform: rotate(45deg);
    -moz-transform: rotate(45deg);
}

JS

$(document).ready(function(){
    var $el = $('#element'),
    // getting position    
        pos = $el.position();
    alert(pos.left + '/' + pos.top);
    // alerts 37/11

    // setting css position attributes equal to pos
    $el.css(pos);
    // re-getting position
    pos = $el.position();
    alert(pos.left + '/' + pos.top);
    // alerts 14/-28
});    

Просмотреть http://jsfiddle.net/Antaranian/2gVL4/

Ответы

Ответ 1

// Needed to read the "real" position
$.fn.adjustedPosition = function() {
    var p = $(this).position();
    return {
        left: p.left - this.data('dx'),
        top: p.top - this.data('dy')
    }
};

$(function() { 

    var img = $('img'),
        pos;

    // Calculate the delta
    img.each(function() {
        var po = $(this).position(), // original position
            pr = $(this).addClass('rot').position(); // rotated position

        $(this).data({
            dx: pr.left - po.left, // delta X
            dy: pr.top - po.top // delta Y
        });
    });

    // Read the position
    pos = img.adjustedPosition();    
    alert(pos.left + '/' + pos.top);     

    // Write the position
    img.css(pos);

    // Read the position again
    pos = img.adjustedPosition();    
    alert(pos.left + '/' + pos.top);

});

Live demo: http://jsfiddle.net/2gVL4/4/

Итак, что здесь происходит:

  • Код CSS, который вращает изображение, хранится внутри специального класса CSS. Я делаю это, потому что хочу прочитать исходное положение изображения (перед вращением). Когда я прочитаю эту исходную позицию, я применяю класс .rot, а затем снова прочитаю позицию для вычисления разности (дельта), которая хранится внутри данных элемента().

  • Теперь я могу прочитать позицию с помощью настраиваемого метода adjustedPosition (который определен выше). Этот метод будет читать позицию элемента, а затем вычесть значения дельта, хранящиеся внутри данных() элемента.

  • Чтобы записать позицию, просто используйте метод css(pos), как обычно.

Ответ 2

Была аналогичная проблема. Существует простое решение (не элегантное, но работающее):

  • установить текущий угол в 0
  • читать позицию X/Y
  • вернуть угол назад к его значению

    var temp = $(this).position();
    temp.angle = getRotationDegrees( $(this) );            // remember current angle
    rotateObject($(this), 0);                              // set angle to 0
    temp.left = Math.round($(this).position().left);       // proper value
    temp.top = Math.round($(this).position().top);         // proper value
    
    // revert back the angle
    rotateObject($(this), temp.angle); 
    

Используемые функции:

    function rotateObject(obj, angle) {
        obj.css({ '-webkit-transform': 'rotate(' + angle + 'deg)'});
        obj.css({ '-moz-transform': 'rotate(' + angle + 'deg)'});
        obj.css({ '-ms-transform': 'rotate(' + angle + 'deg)'});
        obj.css({ 'msTransform': 'rotate(' + angle + 'deg)'});
        obj.css({ '-o-transform': 'rotate(' + angle + 'deg)'});
        obj.css({ '-sand-transform': 'rotate(' + angle + 'deg)'});
        obj.css({ 'transform': 'rotate(' + angle + 'deg)'});
    }

    function getRotationDegrees(obj) {
        var matrix = obj.css("-webkit-transform") ||
        obj.css("-moz-transform")    ||
        obj.css("-ms-transform")     ||
        obj.css("-o-transform")      ||
        obj.css("transform");
        if(matrix !== 'none') {
            var tr;
            if (tr = matrix.match('matrix\\((.*)\\)')) {
                tr = tr[1].split(',');
                if(typeof tr[0] != 'undefined' && typeof tr[1] != 'undefined') {
                    var angle = Math.round(Math.atan2(tr[1], tr[0]) * (180/Math.PI));
                }else{
                    var angle = 0; 
                }
            }else if(tr = matrix.match('rotate\\((.*)deg\\)')){
                var angle = parseInt(tr[1]); 
            }
        } else { var angle = 0; }
        return (angle < 0) ? angle + 360 : angle;
    }