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=\'a开发者_StackOverflowuto 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.
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.
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.
The position fix for IE can also be calculated analytically - see here
精彩评论