Is there js plugin convert the matrix parameter to css3 transform property?
Numbers you're getting are the result of multiplying Rotation and Translation matrices.
Although for your case you could get by easily by doing the math on paper and getting the formulas you need by hand, for increasing number of terms it would be a teadious task (you need to know the structure of original trasforms in order to reverse them as well).
Here's a link that will help you:
http://www.useragentman.com/blog/2011/01/07/css3-matrix-transform-for-the-mathematically-challenged/
Why not just set those value you need from Javascript code and therefore eliminate need for geting them from matrix at all?
Get the applied css property-identifiers
Got it...
Quite simple:
var getIdentifier = function(str) {
return str.split('(')[0];
};
getIdentifier( 'rect(300px 0px 0px 300px)' ) // => 'rect'
Matrix : get positive value
You can use Math.abs:
var x = Math.abs(values[5]);
jQuery Drag/Resize with CSS Transform Scale
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
Get element -moz-transform:rotate value in jQuery
Here's my solution using jQuery.
This returns a numerical value corresponding to the rotation applied to any HTML element.
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 values = matrix.split('(')[1].split(')')[0].split(',');
var a = values[0];
var b = values[1];
var angle = Math.round(Math.atan2(b, a) * (180/Math.PI));
} else { var angle = 0; }
return (angle < 0) ? angle + 360 : angle;
}
angle1 = getRotationDegrees($('#myDiv'));
angle2 = getRotationDegrees($('.mySpan a:last-child'));
etc...
Fetch the css value of transform directly using jquery
I've got good news and bad news.
I'll start with the bad news: After examining the object that jQuery returns, the matrix
object is nothing but a string and there's absolutely no way you can get another object but a string. As much we would like to disagree that it shouldn't be a string: CSS values are strings, hence jQuery returns strings.
So, whether you like it or not, you really have to parse the string in order to get the value. The good news is: I've got two solutions.
Now, if you're VERY sure that the first couple of values are ALWAYS the same you could simply use substring. But, next problem: in Google Chrome, the value -283.589px
is being changed to -283.5889892578125
.
Honestly, you need a more advanced string parser to get the correct value. I welcome regular expression:
var matrix = $('.selector').css('-moz-transform');
var values = matrix.match(/-?[\d\.]+/g);
This gets all the values of your string.
By selecting the right index, you can get your value:
var x = values[5];
That's the best solution I can provide and I'm positive it's the only possible solution.
How to set a single value of transform while leaving the other values?
There is no way to directly modify a single component of the transform. Sadly, the various possible transforms were implemented as values on the transform
attribute, rather than attributes themselves. There is no object model for CSS attribute values - attribute values are always just a string, as far as JavaScript is concerned. It would've been nice if transform
was treated as a shorthand attribute for, eg, transform-rotate-y
, transform-*
, etc, the same way that background
is a shorthand attribute for all the background-*
attributes. This would've allowed us direct access to the values via JavaScript, but it was not implemented that way, so we are out of luck.
Edit: The simplest way to accomplish this (without studying the spec and doing a bunch of math) would be to nest your elements, applying different transformations to each. If you apply several transformations that won't change, go ahead and combine those on to one element. Any transformation that you do want to change, use a separate element:
Works here: jsfiddle.net/mkTKH/15
Edit: My original solution below won't work. In testing it out I discovered that getComputedStyle()
converts the transform into a matrix()
. An early draft of the spec says:
The
transform
property of the style object returned bygetComputedStyle
contains a single CSSTransformValue with a type of CSS_MATRIX. The 6 parameters represent the 3x2 matrix that is the result of applying the individual functions listed in thetransform
property.
So, you have to parse it. If you want to change just one portion of an attribute value, you can use a regular expression to parse the value:
var rotateY = "rotateY(" + deg + "deg)";
var transform = el.style.webkitTransform.replace(/\brotateY([^)]+)\b/, rotateY);
el.style.webkitTransform = transform;
I'd create a reusable function:
function setTransformValue(el, name, value) {
var currentValue = new RegExp(name + "([^)]+)");
var style = window.getComputedStyle ? getComputedStyle(el) : el.currentStyle;
var currentTransform = style.transform ||
style.webkitTransform ||
style.MozTransform ||
style.msTransform ||
style.OTransform;
var transform;
if (currentValue.test(currentTransform )) {
transform = currentTransform.replace(currentValue, name + "(" + value + ")");
}
else {
transform = currentTransform + " " + name + "(" + value + ")";
}
el.style.transform = transform;
}
Untested.
jQuery positioning with CSS3 transform: scale
I put my content into iframe, and I applied transformation on iframe - it works properly :)
EDIT: Previous version of my solution turn out to be buggy. But if someone would like to check it I save the snippet
/* * jQuery UI FIX * Take focus on window.transformScale */
/* * Offset fix */(function() {
function getWindow(elem) { return jQuery.isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView; }
jQuery.fn.offset = function( options ) {
// Preserve chaining for setter if ( arguments.length ) { return options === undefined ? this : this.each( function( i ) { jQuery.offset.setOffset( this, options, i ); } ); }
var docElem, win, rect, doc, elem = this[ 0 ];
if ( !elem ) { return; }
// Support: IE <=11 only // Running getBoundingClientRect on a // disconnected node in IE throws an error if ( !elem.getClientRects().length ) { return { top: 0, left: 0 }; }
var transform = $(document.body).css('transform'); $(document.body).css('transform', 'none');
rect = elem.getBoundingClientRect();
$(document.body).css('transform', transform);
// Make sure element is not hidden (display: none) if ( rect.width || rect.height ) { doc = elem.ownerDocument; win = getWindow( doc ); docElem = doc.documentElement;
return { top: rect.top + (win.pageYOffset - docElem.clientTop) / window.transformScale, left: rect.left + (win.pageXOffset - docElem.clientLeft) / window.transformScale, }; }
// Return zeros for disconnected and hidden elements (gh-2310) return rect;};
})();
/* * Position fix */(function() {
var cachedScrollbarWidth, max = Math.max, abs = Math.abs, rhorizontal = /left|center|right/, rvertical = /top|center|bottom/, roffset = /[\+\-]\d+(\.[\d]+)?%?/, rposition = /^\w+/, rpercent = /%$/, _position = $.fn.position;
function getOffsets( offsets, width, height ) { return [ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) ];}
function parseCss( element, property ) { return parseInt( $.css( element, property ), 10 ) || 0;}
function getDimensions( elem ) { var raw = elem[ 0 ]; if ( raw.nodeType === 9 ) { return { width: elem.width() / window.transformScale, height: elem.height() / window.transformScale, offset: { top: 0, left: 0 } }; } if ( $.isWindow( raw ) ) { return { width: elem.width() / window.transformScale, height: elem.height() / window.transformScale, offset: { top: elem.scrollTop(), left: elem.scrollLeft() } }; } if ( raw.preventDefault ) { return { width: 0, height: 0, offset: { top: raw.pageY, left: raw.pageX } }; } return { width: elem.outerWidth() / window.transformScale, height: elem.outerHeight() / window.transformScale, offset: elem.offset() };}
jQuery.fn.position = function( options ) { if ( !options || !options.of ) { return _position.apply( this, arguments ); }
// Make a copy, we don't want to modify arguments options = $.extend( {}, options );
var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, target = $( options.of ), within = $.position.getWithinInfo( options.within ), scrollInfo = $.position.getScrollInfo( within ), collision = ( options.collision || "flip" ).split( " " ), offsets = {};
dimensions = getDimensions( target ); if ( target[ 0 ].preventDefault ) {
// Force left top to allow flipping options.at = "left top"; } targetWidth = dimensions.width; targetHeight = dimensions.height; targetOffset = dimensions.offset;
// Clone to reuse original targetOffset later basePosition = $.extend( {}, targetOffset );
// Force my and at to have valid horizontal and vertical positions // if a value is missing or invalid, it will be converted to center $.each( [ "my", "at" ], function() { var pos = ( options[ this ] || "" ).split( " " ), horizontalOffset, verticalOffset;
if ( pos.length === 1 ) { pos = rhorizontal.test( pos[ 0 ] ) ? pos.concat( [ "center" ] ) : rvertical.test( pos[ 0 ] ) ? [ "center" ].concat( pos ) : [ "center", "center" ]; } pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
// Calculate offsets horizontalOffset = roffset.exec( pos[ 0 ] ); verticalOffset = roffset.exec( pos[ 1 ] ); offsets[ this ] = [ horizontalOffset ? horizontalOffset[ 0 ] : 0, verticalOffset ? verticalOffset[ 0 ] : 0 ];
// Reduce to just the positions without the offsets options[ this ] = [ rposition.exec( pos[ 0 ] )[ 0 ], rposition.exec( pos[ 1 ] )[ 0 ] ]; } );
// Normalize collision option if ( collision.length === 1 ) { collision[ 1 ] = collision[ 0 ]; }
if ( options.at[ 0 ] === "right" ) { basePosition.left += targetWidth; } else if ( options.at[ 0 ] === "center" ) { basePosition.left += targetWidth / 2; }
if ( options.at[ 1 ] === "bottom" ) { basePosition.top += targetHeight; } else if ( options.at[ 1 ] === "center" ) { basePosition.top += targetHeight / 2; }
atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); basePosition.left += atOffset[ 0 ]; basePosition.top += atOffset[ 1 ];
return this.each( function() { var collisionPosition, using, elem = $( this ), elemWidth = elem.outerWidth() / window.transformScale, elemHeight = elem.outerHeight() / window.transformScale, marginLeft = parseCss( this, "marginLeft" ), marginTop = parseCss( this, "marginTop" ), collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, position = $.extend( {}, basePosition ), myOffset = getOffsets( offsets.my, elem.outerWidth() / window.transformScale, elem.outerHeight() / window.transformScale );
if ( options.my[ 0 ] === "right" ) { position.left -= elemWidth; } else if ( options.my[ 0 ] === "center" ) { position.left -= elemWidth / 2; }
if ( options.my[ 1 ] === "bottom" ) { position.top -= elemHeight; } else if ( options.my[ 1 ] === "center" ) { position.top -= elemHeight / 2; }
position.left += myOffset[ 0 ]; position.top += myOffset[ 1 ];
collisionPosition = { marginLeft: marginLeft, marginTop: marginTop };
$.each( [ "left", "top" ], function( i, dir ) { if ( jQuery.ui.position[ collision[ i ] ] ) { jQuery.ui.position[ collision[ i ] ][ dir ]( position, { targetWidth: targetWidth, targetHeight: targetHeight, elemWidth: elemWidth, elemHeight: elemHeight, collisionPosition: collisionPosition, collisionWidth: collisionWidth, collisionHeight: collisionHeight, offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], my: options.my, at: options.at, within: within, elem: elem } ); } } );
if ( options.using ) {
// Adds feedback as second argument to using callback, if present using = function( props ) { var left = targetOffset.left - position.left, right = left + targetWidth - elemWidth, top = targetOffset.top - position.top, bottom = top + targetHeight - elemHeight, feedback = { target: { element: target, left: targetOffset.left, top: targetOffset.top, width: targetWidth, height: targetHeight }, element: { element: elem, left: position.left, top: position.top, width: elemWidth, height: elemHeight }, horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" }; if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { feedback.horizontal = "center"; } if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { feedback.vertical = "middle"; } if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { feedback.important = "horizontal"; } else { feedback.important = "vertical"; } options.using.call( this, props, feedback ); }; }
elem.offset( $.extend( position, { using: using } ) ); } );};
})();
/* * Draggable fix */(function() {
jQuery.ui.draggable.prototype._refreshOffsets = function( event ) { this.offset = { top: this.positionAbs.top - this.margins.top, left: this.positionAbs.left - this.margins.left, scroll: false, parent: this._getParentOffset(), relative: this._getRelativeOffset() };
this.offset.click = { left: event.pageX / window.transformScale - this.offset.left, top: event.pageY / window.transformScale - this.offset.top };};
jQuery.ui.draggable.prototype._generatePosition = function( event, constrainPosition ) {
var containment, co, top, left, o = this.options, scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), pageX = event.pageX / window.transformScale, pageY = event.pageY / window.transformScale;
// Cache the scroll if ( !scrollIsRootNode || !this.offset.scroll ) { this.offset.scroll = { top: this.scrollParent.scrollTop(), left: this.scrollParent.scrollLeft() }; }
/* * - Position constraining - * Constrain the position to a mix of grid, containment. */
// If we are not dragging yet, we won't check for options if ( constrainPosition ) { if ( this.containment ) { if ( this.relativeContainer ) { co = this.relativeContainer.offset(); containment = [ this.containment[ 0 ] + co.left, this.containment[ 1 ] + co.top, this.containment[ 2 ] + co.left, this.containment[ 3 ] + co.top ]; } else { containment = this.containment; }
var width = 0; var height = 0; if(window.transformScale != 1) { var width = this.helper.outerWidth(); var height = this.helper.outerHeight(); }
if ( pageX - this.offset.click.left < containment[ 0 ] ) { pageX = containment[ 0 ] + this.offset.click.left; } if ( pageY - this.offset.click.top < containment[ 1 ] ) { pageY = containment[ 1 ] + this.offset.click.top; } if ( pageX - this.offset.click.left + width > containment[ 2 ] ) { pageX = containment[ 2 ] + this.offset.click.left - width; } if ( pageY - this.offset.click.top + height > containment[ 3 ] ) { pageY = containment[ 3 ] + this.offset.click.top - height; } }
if ( o.grid ) {
//Check for grid elements set to 0 to prevent divide by 0 error causing invalid // argument errors in IE (see ticket #6950) top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY - this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY; pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] || top - this.offset.click.top > containment[ 3 ] ) ? top : ( ( top - this.offset.click.top >= containment[ 1 ] ) ? top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
left = o.grid[ 0 ] ? this.originalPageX + Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] : this.originalPageX; pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] || left - this.offset.click.left > containment[ 2 ] ) ? left : ( ( left - this.offset.click.left >= containment[ 0 ] ) ? left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left; }
if ( o.axis === "y" ) { pageX = this.originalPageX; }
if ( o.axis === "x" ) { pageY = this.originalPageY; } }
return { top: (
// The absolute mouse position pageY -
// Click offset (relative to the element) this.offset.click.top -
// Only for relative positioned nodes: Relative offset from element to offset parent this.offset.relative.top -
// The offsetParent's offset without borders (offset + border) this.offset.parent.top + ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) ), left: (
// The absolute mouse position pageX -
// Click offset (relative to the element) this.offset.click.left -
// Only for relative positioned nodes: Relative offset from element to offset parent this.offset.relative.left -
// The offsetParent's offset without borders (offset + border) this.offset.parent.left + ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) ) };
};
jQuery.ui.draggable.prototype._mouseStart = function( event ) {
var o = this.options;
//Create and append the visible helper this.helper = this._createHelper( event );
this._addClass( this.helper, "ui-draggable-dragging" );
//Cache the helper size this._cacheHelperProportions();
//If ddmanager is used for droppables, set the global draggable if ( jQuery.ui.ddmanager ) { jQuery.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( true ); this.offsetParent = this.helper.offsetParent(); this.hasFixedAncestor = this.helper.parents().filter( function() { return $( this ).css( "position" ) === "fixed"; } ).length > 0;
//The element's absolute position on the page minus margins this.positionAbs = this.element.offset(); this._refreshOffsets( event );
//Generate the original position this.originalPosition = this.position = this._generatePosition( event, false ); this.originalPageX = event.pageX / window.transformScale; this.originalPageY = event.pageY / window.transformScale;
//Adjust the mouse offset relative to the helper if "cursorAt" is supplied ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
//Set a containment if given in the options 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 ( jQuery.ui.ddmanager && !o.dropBehaviour ) { jQuery.ui.ddmanager.prepareOffsets( this, event ); }
// Execute the drag once - this causes the helper not to be visible before getting its // correct position this._mouseDrag( event, true );
// If the ddmanager is used for droppables, inform the manager that dragging has started // (see #5003) if ( jQuery.ui.ddmanager ) { jQuery.ui.ddmanager.dragStart( this, event ); }
return true;
};
jQuery.ui.draggable.prototype._mouseDrag = function( event, noPropagation ) {
// reset any necessary cached properties (see #5009) if ( this.hasFixedAncestor ) { this.offset.parent = this._getParentOffset(); }
//Compute the helpers position this.position = this._generatePosition( event, true ); this.positionAbs = this._convertPositionTo( "absolute" );
//Call plugins and callbacks and use the resulting position if something is returned if ( !noPropagation ) { var ui = this._uiHash(); if ( this._trigger( "drag", event, ui ) === false ) { this._mouseUp( new $.Event( "mouseup", event ) ); return false; } this.position = ui.position; }
this.helper[ 0 ].style.left = this.position.left + "px"; this.helper[ 0 ].style.top = this.position.top + "px";
if ( jQuery.ui.ddmanager ) { jQuery.ui.ddmanager.drag( this, event ); }
return false;};
})();
body { position: relative; margin: 0; transform-origin: 0 0 0;}
#root { position: fixed; top: 20px; left: 20px;
width: 500px; height: 500px;
border: solid 2px green;
}
#box { position: absolute; top: 100px; left: 50px;
display: inline-block; width: 50px; height: 50px;
background: yellow; border: solid 2px black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script><script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script><script>/* * EXAMPLE CODE */// this variable is required to make extension workwindow.transformScale = 0.5;
$(document).ready(function() { $(document.body).attr('style', 'transform: scale('+ window.transformScale +')');
$('#root').dblclick(function() { $('#box').position({ my: 'right bottom', at: 'right bottom', of: $('#root') }); })
$('#box').draggable({ containment: $('#root'), });
});</script>
<div id="root"> <div id="box"></div></div>
Related Topics
Provide Local Fallback for CSS from Cdn
JavaScript Image Overlay Over a Specified Div
Bootstrap 3.0 Popovers and Tooltips
Horizontal Swipe Slider with Jquery and Touch Devices Support
Check Visibility of an Object with JavaScript
Html5 Video Custom Additional Seek Bar
Single Navigation Bar Across Website
How to Detect Which CSS Grid Column and Row an Element Is in Using JavaScript
How to Open Safari from a Webapp in iOS 7
Adding Style Stored in a Variable Inside React Class
Android Webview, Loading JavaScript File in Assets Folder
How to Detect When a CSS File Has Been Fully Loaded
How to Detect Device Name in Safari on iOS 13 While It Doesn't Show the Correct User Agent
Bootstrap V3 - Opening a Modal Window Forces the Page to Scroll Up to the Top