Reputation: 1751
I am applying a CSS transform (and the browser specific -webkit, -o etc):
transform: matrix(0.5 , 0 , 0, 0.5, 0 , 0);
to a div then using jQuery's draggable() and resizable() plugins on children of said div.
The problem I had was that when dragging or resizing the child elements, the alteration jQuery made were out of "sync" with the mouse by a factor equal to the scale applied.
I found a solution on stackoverflow (though I stupidly did not bookmark it and now cant find it....) that suggested patching the plugins, and it worked wonderfully. It went along these line:
function monkeyPatch_mouseStart() {
// don't really need this, but in case I did, I could store it and chain
// var oldFn = $.ui.draggable.prototype._mouseStart ;
$.ui.draggable.prototype._mouseStart = function(event) {
var o = this.options;
//Create and append the visible helper
this.helper = this._createHelper(event);
//Cache the helper size
this._cacheHelperProportions();
//If ddmanager is used for droppables, set the global draggable
if($.ui.ddmanager)
$.ui.ddmanager.current = this;
/*
* - Position generation -
* This block generates everything position related - it's the core of draggables.
*/
//Cache the margins of the original element
this._cacheMargins();
//Store the helper's css position
this.cssPosition = this.helper.css("position");
this.scrollParent = this.helper.scrollParent();
//The element's absolute position on the page minus margins
//PATCH CODE
this.offset = this.positionAbs = getViewOffset(this.element[0]);
//END
this.offset = {
top: this.offset.top - this.margins.top,
left: this.offset.left - this.margins.left
};
$.extend(this.offset, {
click: { //Where the click happened, relative to the element
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
},
parent: this._getParentOffset(),
relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
});
//Generate the original position
this.originalPosition = this.position = this._generatePosition(event);
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
if(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)){
}
//Set a containment if given in the options
if(o.containment)
this._setContainment();
//Trigger event + callbacks
if(this._trigger("start", event) === false) {
this._clear();
return false;
}
//Recache the helper size
this._cacheHelperProportions();
//Prepare the droppable offsets
if ($.ui.ddmanager && !o.dropBehaviour)
$.ui.ddmanager.prepareOffsets(this, event);
this.helper.addClass("ui-draggable-dragging");
this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
//If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
if ( $.ui.ddmanager && $.ui.ddmanager.dragStart) $.ui.ddmanager.dragStart(this, event);
return true;
}
}
function getViewOffset(node) {
var x = 0, y = 0, win = node.ownerDocument.defaultView || window;
if (node) addOffset(node);
return { left: x, top: y };
function getStyle(node) {
return node.currentStyle || // IE
win.getComputedStyle(node, '');
}
function addOffset(node) {
var p = node.offsetParent, style, X, Y;
x += parseInt(node.offsetLeft, 10) || 0;
y += parseInt(node.offsetTop, 10) || 0;
if (p) {
x -= parseInt(p.scrollLeft, 10) || 0;
y -= parseInt(p.scrollTop, 10) || 0;
if (p.nodeType == 1) {
var parentStyle = getStyle(p)
, localName = p.localName
, parent = node.parentNode;
if (parentStyle.position != 'static') {
x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
y += parseInt(parentStyle.borderTopWidth, 10) || 0;
if (localName == 'TABLE') {
x += parseInt(parentStyle.paddingLeft, 10) || 0;
y += parseInt(parentStyle.paddingTop, 10) || 0;
}
else if (localName == 'BODY') {
style = getStyle(node);
x += parseInt(style.marginLeft, 10) || 0;
y += parseInt(style.marginTop, 10) || 0;
}
}
else if (localName == 'BODY') {
x += parseInt(parentStyle.borderLeftWidth, 10) || 0;
y += parseInt(parentStyle.borderTopWidth, 10) || 0;
}
while (p != parent) {
x -= parseInt(parent.scrollLeft, 10) || 0;
y -= parseInt(parent.scrollTop, 10) || 0;
parent = parent.parentNode;
}
addOffset(p);
}
}
else {
if (node.localName == 'BODY') {
style = getStyle(node);
x += parseInt(style.borderLeftWidth, 10) || 0;
y += parseInt(style.borderTopWidth, 10) || 0;
var htmlStyle = getStyle(node.parentNode);
x -= parseInt(htmlStyle.paddingLeft, 10) || 0;
y -= parseInt(htmlStyle.paddingTop, 10) || 0;
}
if ((X = node.scrollLeft)) x += parseInt(X, 10) || 0;
if ((Y = node.scrollTop)) y += parseInt(Y, 10) || 0;
}
}
}
var isNumber = function(value) {
return !isNaN(parseInt(value, 10));
};
I have made my own changes such as (you can see on the 6-7 lines the multiplication of the movement by a "scale factor"):
$.ui.draggable.prototype._generatePosition = function(event) {
var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
var pageX = event.pageX;
var pageY = event.pageY;
//PATCH CODE
if($(this.element[0]).hasClass('item')){
pageY = this.originalPageY + ((pageY - this.originalPageY)*(1/$.viewbox.foreground.scale));
pageX = this.originalPageX + ((pageX - this.originalPageX)*(1/$.viewbox.foreground.scale));
}
//END
/*
* - Position constraining -
* Constrain the position to a mix of grid, containment.
*/
if(this.originalPosition) { //If we are not dragging yet, we won't check for options
if(this.containment) {
if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
}
if(o.grid) {
var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
}
}
return {
top: (
pageY // The absolute mouse position
- this.offset.click.top // Click offset (relative to the element)
- this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.parent.top // The offsetParent's offset without borders (offset + border)
+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
),
left: (
pageX // The absolute mouse position
- this.offset.click.left // Click offset (relative to the element)
- this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
- this.offset.parent.left // The offsetParent's offset without borders (offset + border)
+ ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
)
};
}
So big thank you to whoever suggested that.
So, my question! Has anyone come across a nice way to have draggable/resizable events inside a scaled element that doesn't require patching jQuery? I have googled, and this was the best solution I could find. Does anyone know of alternative to jquery that perhaps works under these conditions, with CSS transforms?
Many thanks for any responses.
Upvotes: 50
Views: 33309
Reputation: 99
For different resize corner
$('.rect-item').resizable({
handles: 'n,e,s,w,ne,se,sw,nw',
resize: (e, ui) => {
const zoomScale = Your scale;
const changeWidth = ui.size.width - ui.originalSize.width; // find change in width
const newWidth = ui.originalSize.width + changeWidth / zoomScale; // adjust new width by our zoomScale
const changeHeight = ui.size.height - ui.originalSize.height; // find change in height
const newHeight = ui.originalSize.height + changeHeight / zoomScale; // adjust new height by our zoomScale
ui.size.width = newWidth;
ui.size.height = newHeight;
// here
const posOrigin = ui.originalPosition;
if (posOrigin.left !== ui.position.left) {
ui.position.left = posOrigin.left - changeWidth / zoomScale;
}
if (posOrigin.top !== ui.position.top) {
ui.position.top = posOrigin.top - changeHeight / zoomScale;
}
}
});
Upvotes: 0
Reputation: 4693
None of these solutions worked for me, as for one, I could not transform the parent of the draggables - only the draggables themselves were transformed.
This is how I fixed this issue:
$('.draggable').draggable(
{
cancel: '.restrict-drag',
scroll: false,
containment: '#contain',
start: function(event, ui)
{
ui.position.left = 0;
ui.position.top = 0;
},
drag: function(event, ui)
{
ui.position.left = ui.position.left - ($(event.target).width() * Zoom);
ui.position.top = ui.position.top - ($(event.target).height() * Zoom);
}
});
Zoom is by default 0.
To scale the draggables I did the following:
function changeZoom(zoom)
{
$('.draggable').each(function() { $(this).css('transform-origin', '50% 50%'); $(this).css('transform', 'scale(' + zoom + ')'); });
Zoom = zoom; // Global Zoom-variable
}
And everything seems to work allright.
Upvotes: 0
Reputation: 3490
For a long time I wonder why @GungFoo
solution not working for me for Jquery Resizable but some people told it was worked. Finally I found out there are 4 points for using jQuery Draggable and Resizable with CSS Transform Scale:
Check some of this problems:
function resizeDiv(event, ui) {
debugger;
var changeWidth = ui.size.width - ui.originalSize.width;
var newWidth = ui.originalSize.width + changeWidth / 4;
var changeHeight = ui.size.height - ui.originalSize.height;
var newHeight = ui.originalSize.height + changeHeight / 4;
ui.size.width = newWidth;
ui.size.height = newHeight;
};
$('#box').resizable({
minWidth: -($(this).width()) * 10,
minHeight: -($(this).height()) * 10,
resize: resizeDiv
});
$('#box2').resizable({
minWidth: -($(this).width()) * 10,
minHeight: -($(this).height()) * 10,
resize: resizeDiv
});
$('#box3').resizable({
minWidth: -($(this).width()) * 10,
minHeight: -($(this).height()) * 10,
resize: resizeDiv
});
$('#box4').resizable({
minWidth: -($(this).width()) * 10,
minHeight: -($(this).height()) * 10,
resize: resizeDiv
});
.box{
position:absolute;
width:30px;
height:30px;
border:1px solid black;
font-size:3pt;
overflow:hidden;
-webkit-transform:scale(4);
direction:ltr;
}
#box{
transform-origin: top left;
top: 0;
left:0;
}
#box2{
transform-origin: bottom left;
top: 250px;
left:0;
}
#box3{
direction:rtl;
left: 250px;
top: -10px;
}
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js"></script>
<div id= 'box' class="box">
True styles
</div>
<div id= 'box2' class="box">
Bad transform-orgin
</div>
<div id= 'box3' class="box">
Bad direction
</div>
Thanks to @Guy ;)
Upvotes: 1
Reputation: 474
The top answer was working for me till i've found a glitch on draggable :(
When the containment itself is also scaled:
Luckily, i've found a solution here
Upvotes: 2
Reputation: 928
I found I could just wrap the scaled element with another div and set draggable on it instead.
Upvotes: 1
Reputation: 2171
I had the same problem, and the easiest way for me was NOT to use the jquery-ui's draggable functionality since it does not support CSS3 transform properties.
What worked for me really good was to implement an own draggable functionality: http://css-tricks.com/snippets/jquery/draggable-without-jquery-ui/
I know it does not solve your problem 100%, since you still want to use the jquery-ui draggable functionality, but it could help others.
Upvotes: 0
Reputation: 181
Another approach would be to add a plugin that compensate for the transformation ( remember to add "transform : true" to the plugin initialization.
The ui.draggable need to be passed via a inverse matrix of the transformation in order to position the element in the un-transformed space which the browser later transform on display.
For "draggable" the following worked for me ( jqueryui 1.10 ) ( the matrix calculation I have taken from jquery.panzoom):
var Matrix = function(a, b, c, d, e, f, g, h, i) {
if ($.type(a) === 'array') {
this.elements = [
+a[0], +a[2], +a[4],
+a[1], +a[3], +a[5],
0, 0, 1
];
} else {
this.elements = [
a, b, c,
d, e, f,
g || 0, h || 0, i || 1
];
}
};
Matrix.prototype = {
/**
* Multiply a 3x3 matrix by a similar matrix or a vector
* @param {Matrix|Vector} matrix
* @return {Matrix|Vector} Returns a vector if multiplying by a vector
*/
x: function(matrix) {
var isVector = matrix instanceof Vector;
var a = this.elements,
b = matrix.elements;
if (isVector && b.length === 3) {
// b is actually a vector
return new Vector(
a[0] * b[0] + a[1] * b[1] + a[2] * b[2],
a[3] * b[0] + a[4] * b[1] + a[5] * b[2],
a[6] * b[0] + a[7] * b[1] + a[8] * b[2]
);
} else if (b.length === a.length) {
// b is a 3x3 matrix
return new Matrix(
a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
);
}
return false; // fail
},
/**
* Generates an inverse of the current matrix
* @returns {Matrix}
*/
inverse: function() {
var d = 1 / this.determinant(),
a = this.elements;
return new Matrix(
d * ( a[8] * a[4] - a[7] * a[5]),
d * (-(a[8] * a[1] - a[7] * a[2])),
d * ( a[5] * a[1] - a[4] * a[2]),
d * (-(a[8] * a[3] - a[6] * a[5])),
d * ( a[8] * a[0] - a[6] * a[2]),
d * (-(a[5] * a[0] - a[3] * a[2])),
d * ( a[7] * a[3] - a[6] * a[4]),
d * (-(a[7] * a[0] - a[6] * a[1])),
d * ( a[4] * a[0] - a[3] * a[1])
);
},
/**
* Calculates the determinant of the current matrix
* @returns {Number}
*/
determinant: function() {
var a = this.elements;
return a[0] * (a[8] * a[4] - a[7] * a[5]) - a[3] * (a[8] * a[1] - a[7] * a[2]) + a[6] * (a[5] * a[1] - a[4] * a[2]);
}
};
var Vector = function (x, y, z) {
this.elements = [ x, y, z ];
};
/**
* Get the element at zero-indexed index i
* @param {Number} i
*/
Vector.prototype.e = Matrix.prototype.e = function(i) {
if( this.elements[ i ] != undefined ){
return this.elements[ i ];
}
return this.elements;
};
$.ui.plugin.add("draggable", "transform", {
start: function( event, ui ) {
if(!$(this).data('ui-draggable')){
return false;
}
var inst = $(this).data("ui-draggable");
inst.matrix = new Matrix(function(matrix){
var rmatrix = new RegExp(
'^matrix\\(' +
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
'(\\-?[\\d\\.e]+)' + '\\,?\\s*' +
'(\\-?[\\d\\.e]+)' + '\\)$'
);
var matrix = rmatrix.exec( matrix );
if (matrix) {
matrix.shift();
}
return matrix || [ 1, 0, 0, 1, 0, 0 ];
}([$(this).parents('[style*="transform"]').css('transform')]));
},
drag: function( event, ui ) {
if(!$(this).data('ui-draggable')){
return false;
}
var inst = $(this).data("ui-draggable");
var t_pos = inst.matrix.inverse().x(new Vector(ui.position.left, ui.position.top, 0));
ui.position.left = t_pos.e(0);
ui.position.top = t_pos.e(1);
if(inst.options.grid) {
ui.position.left = ui.position.left - ui.position.left % inst.options.grid[0];
ui.position.top = ui.position.top - ui.position.top % inst.options.grid[1];
}
if( inst.containment ){
if( ui.position.left < inst.containment[0] ){
ui.position.left = inst.containment[0];
}
if( ui.position.left > inst.containment[2] ){
ui.position.left = inst.containment[2];
}
if( ui.position.top < inst.containment[1] ){
ui.position.top = inst.containment[1];
}
if( ui.position.top > inst.containment[3] ){
ui.position.top = inst.containment[3];
}
}
},
});
Upvotes: 2
Reputation: 334
I would add this as a comment to the accepted answer from Gung Foo but I don't have the rep to comment.
I found Gung's answered worked perfectly for me however the resizable fix only worked when dragging from the bottom-right corner. I also have handles on the other three corners and found the element would shift so I had to add the fix from draggable to the resizable functions.
Maybe there's a better way, or I missed something, but I found the modified resizable below worked for me from all handles:
$(this).resizable({
minWidth: -(contentElem.width()) * 10, // these need to be large and negative
minHeight: -(contentElem.height()) * 10, // so we can shrink our resizable while scaled
// adjust the initial position to accomodate for the scale
start: function(event, ui){
ui.position.left = Math.round(ui.position.left/zoomScale);
ui.position.top = Math.round(ui.position.top/zoomScale);
ui.originalPosition.left = ui.position.left;
ui.originalPosition.top = ui.position.top;
},
resize: function(event, ui) {
var changeWidth = ui.size.width - ui.originalSize.width; // find change in width
var newWidth = ui.originalSize.width + changeWidth / zoomScale; // adjust new width by our zoomScale
var changeHeight = ui.size.height - ui.originalSize.height; // find change in height
var newHeight = ui.originalSize.height + changeHeight / zoomScale; // adjust new height by our zoomScale
ui.size.width = newWidth;
ui.size.height = newHeight;
// if the position is changed by a NW,NE,SW handle resize adjust for the scale
var changeWidth = ui.size.width - ui.originalSize.width; // find change in width
var newWidth = ui.originalSize.width + changeWidth / zoomScale; // adjust new width by our zoomScale
var changeHeight = ui.size.height - ui.originalSize.height; // find change in height
var newHeight = ui.originalSize.height + changeHeight / zoomScale; // adjust new height by our zoomScale
ui.size.width = newWidth;
ui.size.height = newHeight;
}
});
Upvotes: 0
Reputation: 51
I was trying the transform scale() fix for resizable posted by gungfoo on a element displayed at 10% of its actual size and the method didin't work. The cursor still moved away from the element during resizing.
I changed the last two lines of the resizeFix method to directly update the element's width and height and this solved my issue.
function resizeFix(event, ui) {
var changeWidth = ui.size.width - ui.originalSize.width; // find change in width
var newWidth = ui.originalSize.width + changeWidth / zoomScale; // adjust new width by our zoomScale
var changeHeight = ui.size.height - ui.originalSize.height; // find change in height
var newHeight = ui.originalSize.height + changeHeight / zoomScale; // adjust new height by our zoomScale
ui.originalElement.width(newWidth);
ui.originalElement.height(newHeight);
}
Upvotes: 4
Reputation: 1
Here is my solution. Some of the code posted above did not work for me.
I have a dragable image and I apply CSS transform rotate and scale onto that image. Once I scale/rotate it the position is off at drag-start. To fix it I calculate the setpoint difference from stop to start and on-drag apply a new setpoint with the difference factored in.
var $img = $("#my-image-id");
$img.posLeft = 0;
$img.posTop = 0;
$img.diffLeft = 0;
$img.diffTop = 0;
$img.draggable({
start: function( event, ui ) {
//check the difference from start to stop setpoints
$img.diffLeft = $img.posLeft-ui.position.left;
$img.diffTop = $img.posTop-ui.position.top;
//console.log('start x: '+Math.floor(ui.position.left)+' y: '+Math.floor(ui.position.top));
//console.log('diff x: '+Math.floor($img.posLeft-ui.position.left)+' y: '+Math.floor($img.posTop-ui.position.top));
},
drag: function( event, ui ) {
//fix the offset bug that is applied after CSS transform, to do that just add the value difference
ui.position.left = ui.position.left+$img.diffLeft;
ui.position.top = ui.position.top+$img.diffTop;
//console.log('drag x: '+ui.position.left+' y: '+ui.position.top);
},
stop: function( event, ui ) {
//save the last applied setpoints
$img.posLeft = ui.position.left;
$img.posTop = ui.position.top;
//console.log('stop x: '+Math.floor(ui.position.left)+' y: '+Math.floor(ui.position.top));
}
});
The CSS transform-origin trick does fixes the bug for scale only. Rotation should be around center so you want to keep the default 50% 50%.
Upvotes: 0
Reputation: 13568
It's been a while since this question was asked. I have found (actually created) an answer. All it requires is setting callback handlers. No editing jquery-ui needed!
Note: zoomScale in this example is a global variable and the transform is set using animate (aided by jquery.transform.js) like so:
target.animate({
transform: 'scale(' + zoomScale + ')'
});
Take a look at this:
transform scale() fix for resizable:
$(this).resizable({
minWidth: -(contentElem.width()) * 10, // these need to be large and negative
minHeight: -(contentElem.height()) * 10, // so we can shrink our resizable while scaled
resize: function(event, ui) {
var changeWidth = ui.size.width - ui.originalSize.width; // find change in width
var newWidth = ui.originalSize.width + changeWidth / zoomScale; // adjust new width by our zoomScale
var changeHeight = ui.size.height - ui.originalSize.height; // find change in height
var newHeight = ui.originalSize.height + changeHeight / zoomScale; // adjust new height by our zoomScale
ui.size.width = newWidth;
ui.size.height = newHeight;
}
});
transform scale() fix for draggable:
$(this).draggable({
handle: '.drag-handle',
start: function(event, ui) {
ui.position.left = 0;
ui.position.top = 0;
},
drag: function(event, ui) {
var changeLeft = ui.position.left - ui.originalPosition.left; // find change in left
var newLeft = ui.originalPosition.left + changeLeft / (( zoomScale)); // adjust new left by our zoomScale
var changeTop = ui.position.top - ui.originalPosition.top; // find change in top
var newTop = ui.originalPosition.top + changeTop / zoomScale; // adjust new top by our zoomScale
ui.position.left = newLeft;
ui.position.top = newTop;
}
});
Let me know if you find any problems or further improvements on this. :)
Reference: jQuery-UI resizable/draggable with transform: scale() set
Upvotes: 46
Reputation: 1751
My own "answer" was on this occasion was to adapt jQuery UI draggable to make a separate interaction, called "traggable".
https://github.com/paullth/JS-libs
http://jsfiddle.net/paul_herve/ws27C/4/
Would still like to hear about any alternatives...
Upvotes: 3
Reputation: 13336
i had a similar problem with transformation and ended up solving it with css:
transform-origin
http://www.w3schools.com/cssref/css3_pr_transform-origin.asp
have you tried it? maybe it will help.
Upvotes: 3