Mushegh A.
Mushegh A.

Reputation: 1431

jQuery Element Free Rotation. Correcting Transform Origin and Translate in IE

I'm developing a jQuery plugin to make a block-level element rotatable with mouse. Now it works as expected in non-IE browsers, but have a strange behavior while rotating in Internet Explorer.

Demo is hosted at testerski.antaranian.me here, rotation plugin script is

    $.fn.roll = function(angle){
    var $this = this,
        ie = !jQuery.support.leadingWhitespace;
    if (ie) {
        var cosAngle = parseFloat(parseFloat(Math.cos(angle.rad())).toFixed(8)),
            sinAngle = parseFloat(parseFloat(Math.sin(angle.rad())).toFixed(8)),
            tx = 0, ty = 0,
            matrixFilter = '(M11=' + cosAngle + ', ' 
                    + 'M12=' + -sinAngle + ', '
                    + 'M21=' + sinAngle + ', '
                    + 'M22=' + cosAngle + ','
                    + 'sizingMethod=\'auto expand\')',
            filter = 'progid:DXImageTransform.Microsoft.Matrix' + matrixFilter,
            css = {
                '-ms-filter': filter,
                'filter': filter                        
              };
            debug.log(filter);  
        var matrix = $M([
                  [cosAngle, -sinAngle, tx],
                  [sinAngle, cosAngle, ty],
                  [0, 0, 1]
                ]);  
        debug.log(matrix);
        $this.transformOrigin(matrix);
        $this.fixIeBoundaryBug(matrix);

    } else {
        var css = {
                '-webkit-transform': 'rotate(' + angle + 'deg)',
                '-moz-transform': 'rotate(' + angle + 'deg)',
                '-o-transform': 'rotate(' + angle + 'deg)'
              };
    }   
    $this.css(css);
    return this;            
  };

I googled and found these two pages related to this subject

Grady's guide and Zoltan's guide

As I get there are some accounting needed related to Linear Algebra, but it's hard for me so if anyone have more simple tutorial, or knows the direct solution, please let me know.

Any help would be appreciated, Antaranian.

Upvotes: 4

Views: 2499

Answers (3)

idanzalz
idanzalz

Reputation: 1760

The position fix for IE can also be calculated analytically - see here

Upvotes: 0

Mushegh A.
Mushegh A.

Reputation: 1431

Actually I've coded it according to my needs, here is the code, if anyone else is interested.

$.fn.ieRotate = function(alfa){
    var self = this,
        cosAlfa = Math.cos(alfa),
        sinAlfa = Math.sin(alfa),
        matrix = '(M11=' + cosAlfa + ', ' 
                + 'M12=' + -sinAlfa + ', '
                + 'M21=' + sinAlfa + ', '
                + 'M22=' + cosAlfa + ','
                + 'sizingMethod=\'auto expand\')',
        // constructing the final filter string
        filter = 'progid:DXImageTransform.Microsoft.Matrix' + matrix;    
    self.each(function(el){
        var $this = $(el),
            size = $this.data('size'),
            pos = $this.data('pos');
        $this.css({
            '-ms-filter': filter,
            'filter': filter,
            // for IE9
            'transform': 'rotate(' + angle + 'deg)'
          });
        // calculate the difference between element's expeced and the actual centers
        var dLeft = ($this.width() - size.width) / 2,
            dTop = ($this.height() - size.height) / 2;
        $this.css({
            top: pos.top -dTop,
            left: pos.left - dLeft 
          });   
    });
    return self;    
};

Usage:

// caching the image object to a variable
$image = $('img#my-image');
// saving images non-rotated position and size data
$image.data('pos', {
        top:    $image.position().top,
        left:   $image.position().left
    }).data('size', {
        height: $image.height(),
        width:  $image.width()
    });
// rotate image 1.2 radians
$image.ieRotate(1.2);

Thanks to @Zoltan Hawryluk, his code helped me during the development.

Upvotes: 0

Zoltan Hawryluk
Zoltan Hawryluk

Reputation: 31

IE's Transform Filter, unfortunately, doesn't have a concept of "transform-origin". the 'auto expand' sizingMethod will make the transformed object take the minimum amount of space possible, and you need to change it's positioning.

In cssSandpaper, I put another <div> tag around the transformed object and adjusted it's margin-left and margin-top. If you go to the cssSandpaper website and look through the code, you will see the exact formula (search for "setMatrixFilter" in cssSandpaper.js). You can hard code it into your library, or you can use cssSandpaper itself to do it (using the cssSandpaper.setTransform() method). Even though it may add a few KB to your code, I suggest this just in case I make improvements to the way I handle transforms in the future.

In any case, good luck!

Z.

Upvotes: 3

Related Questions