Get the scale value of an element? - javascript

I'm wondering how I can get the scale value of an element?
I have tried $(element).css('-webkit-transform'); which returns matrix(scaleX,0,0,scaleY,0,0); Is there a way of getting scaleX and scaleY only?

The simplest solution to find out the scale factor between the document and an element is the following:
var element = document.querySelector('...');
var scaleX = element.getBoundingClientRect().width / element.offsetWidth;
This works because getBoundingClientRect returns the actual dimension while offsetWidth/Height is the unscaled size.

If it was specified by a matrix I guess you can't with a straightforward way, but you can easily parse the value:
var matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/,
matches = $(element).css('-webkit-transform').match(matrixRegex);
matches[1] will contain scaleX and matches[2] will contain scaleY. If it's possible that other transformations have also been applied, you'd need to slightly tweak the regex, because now it assumes that all other parameters are 0.
A way to just get the scale values might be to remove any transforms, measure the computed width/height of the element and then add them back and measure again. Then divide new/old values. Haven't tried it, but it might work. jQuery itself uses a similar approach for many measurements, it even has an undocumented $.swap() function just for this.
PS: You are using -o-transform -moz-transform and -ms-transform too, right?

If you need to target webkit only (because it's for the iPhone, or iPad) the most reliable and fast way is using the native javascript webkit provides:
node = $("#yourid")[0];
var curTransform = new WebKitCSSMatrix(window.getComputedStyle(node).webkitTransform);
alert(curTransform.a); // curTransform is an object,
alert(curTransform.d); // a through f represent all values of the transformation matrix
You can view a demo here:
http://jsfiddle.net/umZHA/

You could use the following:
var element = document.getElementById("elementID");
// returns matrix(1,0,0,1,0,0)
var matrix = window.getComputedStyle(element).transform;
var matrixArray = matrix.replace("matrix(", "").split(",");
var scaleX = parseFloat(matrixArray[0]); // convert from string to number
var scaleY = parseFloat(matrixArray[3]);
// bonus round - gets translate values
var translateX = parseFloat(matrixArray[4]);
var translateY = parseFloat(matrixArray[5]); // parseFloat ignores ")"

Too late for the OP but might be useful in the future. There is a straightforward way to do it using splits:
function getTransformValue(element,property){
var values = element[0].style.webkitTransform.split(")");
for (var key in values){
var val = values[key];
var prop = val.split("(");
if (prop[0].trim() == property)
return prop[1];
}
return false;
}
This is webkit specific, but can easily be extended for more browsers modifying the fist line.

A more robust and generic way to get the scale :
const { width, height } = element.getBoundingClientRect()
const scale = { x : element.offsetWidth / width, y : element.offsetHeight / height }
It compares the visual dimensions with the non-scaled dimensions. So it will work even with nested scaled elements.

Using regex
element.style.transform.match(/scale\(([1-9\.])\)/)[1]

Related

Get offset right in vanilla JavaScript

How do I get the offset of an element from the right side, relative to the window?
I can only find jQuery solutions but I need a solution using vanilla JavaScript.
This is the solution using jQuery
var rt = ($(window).width() - ($whatever.offset().left + $whatever.outerWidth()));
How do I translate this to vanilla JavaScript?
You could try using element.getBoundingClientRect() to achieve that behavior. If you wrote your code to use this instead of jQuery, it would look something like:
var rt = window.innerWidth - element.getBoundingClientRect().right;
You can get the width of an element using .innerWidth
You can get the offset values of a element using getBoundingClientRect()
You can get the outerWidth using offsetWidth
Porting your solution would be something like this:
window.innerWidth - (element.getBoundingClientRect().left + element.offsetWidth)
For more info you can check this link
You can get the offset left position using the .offsetLeft attribute on an element.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft
For outer width see this answer:
outerWidth without jquery
So it would be written something like:
var rt = function() {
var someElement = document.getElementById('someID');
return window.innerWidth - (someElement.offsetLeft + someElement.offsetWidth);
}
Just grab the window size and subtract the x offset plus the width of the element you want to get the offset for.
function windowOffsetRight (ele) {
let rect = ele.getBoundingClientRect ();
let width = document.documentElement.getBoundingClientRect().width;
return width - ( rect.x + rect.width)
}
You just need to translate the jQuery functions in vanilla JS.
$window() // jQuery
window // Vanilla JS
$whatever // jQuery (probably a variable of $('.whatever'))
document.querySelectorAll('.whatever') // Vanilla JS
offset().left // jQuery
offsetLeft // Vanilla JS
outerWidth() // jQuery
offsetWidth // Vanilla JS
const el = document.getElementById('test');
console.log(window.innerWidth - (el.offsetLeft + el.offsetWidth));
<div id="test"></div>
Of course there are many other ways how to do it.
None of the above answers returned the correct value in my case, if there was scrolling involved. Here's what did the trick in my case:
var clientRect = document.querySelector("#element").getBoundingClientRect();
var offset = {
top: clientRect.top + window.scrollY,
left: clientRect.left + window.scrollX,
};
console.log(offset);

JavaScript get matrix transform from regular CSS and convert matrix2D to matrix3D

I need to get the matrix transform from a regular CSS transform like this one: rotateX(10deg) rotateZ(10deg).
I know there is an existring solution for WebKit (WebKitCSSMatrix) but there is nothing like that for Firefox or IE...
So, I tried to get the matrix by setting the transform to an invisible (not in the DOM) and getting it with getComputedStyle but this method return nothing if the element is hidden or detached from the document.
Is there a good tutorial to convert values to Matrix ?
Then, how to convert a 2D matrix to a 3D ? from 6 to 16 values...
you can calculate the matrix yourself. this pages explains how to describe rotations as a 2D matrix: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix.html
for a rotation this would be:
the matrix values can be accessed through these properties. the last row does not need to be modified for 2d. to initialize a matrix in css use: matrix(a,b,c,d,e,f)
for 3D matrices you can find a nice introduction here: http://www.eleqtriq.com/2010/05/understanding-css-3d-transforms/
than read about how to set up a matrix manually: http://www.eleqtriq.com/2010/05/css-3d-matrix-transformations/
in both cases you will have to multiply several matrices if you want apply more than one transformation. information about how to do this can be found here: http://www.useragentman.com/blog/2011/01/07/css3-matrix-transform-for-the-mathematically-challenged/
NOTE: getComputedStyle method only work's for elements which are appended to your document
let's start with a function that make's a hidden element and append's it into your document :
var make_test_el =
function () {
var el = document.createElement("div");
// some browsers doesn't add transform styles if display is inline
el.style.display = "block";
// to be sure your element won't be shown
el.style.width = "0px";
el.style.height = "0px";
el.style.margin = "0px";
el.style.padding = "0px";
el.style.overflow = "hidden";
document.body.appendChild(el);
return el;
}
then just use it by the following code:
var value = 'rotateX(10deg) rotateZ(10deg)'; // your readable value for transformation
var elem = make_test_el();
elem.style.transform = value;
// take your result and alert it
var result = window.getComputedStyle(elem,null).transform;
alert(result);
//then remove appended element
elem.parentNode.removeChild(elem);
demo : http://jsfiddle.net/hbh7ypc9/1/
the result that you'll see maybe matrix3d(...) or matrix(...)
It depend's on browser's RenderEngine and the given value
for example:
IE10 will always give you matrix3d(...)
but for chrome and opera depend's on given value
but I've no idea about converting a 2D matrix to a 3D one
that's a question I've too
actually matrix values are really hard to understand
good luck...

what is the jQuery outerHeight() equivalent in YUI

In jQuery, I can very easily get the current computed height for an element that includes padding, border, and optionally margin by using outerHeight()...
// returns height of element + border + padding + margin
$('.my-element').outerHeight(true);
How would I do this in YUI? I'm currently using version 2.8.1.
Similar to this question, I can always do getComputedStyle() for height, border, padding, and margin, but that is a lot of manual labor which includes parsing the return values and grabbing the correct values that are needed and doing the math myself.
Isn't there some equivalent function to jQuery's outerHeight() in YUI that does all of this for me?
Solution
I ended up writing my own solution since I couldn't find a jQuery outerheight() equivalent. I've posted the solution as an answer here.
There is no built-in way of getting the outer width of an element with its margin in YUI. Like #jshirley mentions, there is offsetWidth, but it doesn't take margins into account. You can however create a function that adds the margin very easily:
Y.Node.ATTRS.outerHeight = {
getter: function () {
return this.get('offsetHeight') +
parseFloat(this.getComputedStyle('marginTop')) +
parseFloat(this.getComputedStyle('marginBottom'));
}
};
Y.Node.ATTRS.outerWidth = {
getter: function () {
return this.get('offsetWidth') +
parseFloat(this.getComputedStyle('marginLeft')) +
parseFloat(this.getComputedStyle('marginRight'));
}
};
Then you can get the outer width by doing Y.one(selector).get('outerWidth'). Here's an example based on #jshirley's code: http://jsbin.com/aretab/4/.
Just keep in mind that dimensions are usually a source of bugs in browsers and this doesn't take into account some stuff (ie: dimensions of the document) jQuery tries to catch (see https://github.com/jquery/jquery/blob/master/src/dimensions.js).
If you wanted to avoid the manual labor, wrap the element in a div and get the computed style of that.
If it's something you're doing more than once, create a function/plugin to reuse.
According to http://www.jsrosettastone.com/, you should be using .get('offsetHeight').
This example shows the equivalency: http://jsbin.com/aretab/1/edit
I ended up writing my own little utility function for this:
/**
* Calculates the outer height for the given DOM element, including the
* contributions of padding, border, and margin.
*
* #param el - the element of which to calculate the outer height
*/
function calculateElementOuterHeight(el) {
var height = 0;
var attributeHeight = 0;
var attributes = [
'height',
'border-top-width',
'border-bottom-width',
'padding-top',
'padding-bottom',
'margin-top',
'margin-bottom'
];
for (var i = 0; i < attributes.length; i++) {
// for most browsers, getStyle() will get us a value for the attribute
// that is parse-able into a number
attributeHeight = parseInt(YAHOO.util.Dom.getStyle(el, attributes[i]), 10);
// if the browser returns something that is not parse-able, like "auto",
// try getComputedStyle(); should get us what we need
if (isNaN(attributeHeight)) {
attributeHeight = parseInt(YAHOO.util.Dom.getComputedStyle(el, attributes[i]), 10);
}
// if we have an actual numeric value now, add it to the height,
// otherwise ignore it
if (!isNaN(attributeHeight)) {
height += attributeHeight;
}
}
return isNaN(height) ? 0 : height;
}
This seems to work across all modern browsers. I've tested it in Chrome, Firefox (idk about 3.6, but the latest version works), Safari, Opera, & IE 7,8,9. Let me know what you guys think!

How to increase a CSS value by the value of a JS variable?

I have several fixed position divs with the same class at varying distances from the left edge of the window, and I'd like to increase/decrease that distance by an equal amount on each div when a certain action happens (in this case, the window being resized). I've tried positioning them with CSS and percentages rather than pixels, but it doesn't quite do the job.
Is there a way to store the position of each of those divs in an array and then add/subtract a given amount of pixels?
Here's what I've tried so far - I'm still getting my head around JS so this could be really bad for all I know, but here goes:
roomObjects = $('.object-pos');
var objectCount = 0;
for ( var objectCount = 0; objectCount < 10; objectCount++;) {
roomObjects = rooomObjects[objectCount];
console.log(roomObjects.css("background-position").split(" "));
}
Do you mind sharing why percentages wouldn't work? Usually that's what I would recommend if you're wanting the page to scale correctly on window resizes. I guess if you really wanted to you could do something like:
$(window).resize(function() {
$('#whateverdiv').style.whateverproperty = $('#whateverdiv').style.whateverproperty.toString() + (newPosition - oldPosition);
oldPosition = newPosition;
}
this is obviously not the complete code, but you should be able to fill in the blanks. You'll have to set the oldPosition variable on page load with the original position so that the function works the first time.
edit: you'll also have to strip off the units from the x.style.property string, so that you'll be able to add the value to it
A problem you might well be facing is that when retrieving the current left or top properties, they are returned as a string, with px of % on the end. Try running a parseInt() on the returned values to get a number, then you might well be able to add to the values. Just be sure, when reassigning, that you concatenate "px" or "%" on the end as appropriate.
You could use a bit of jQuery :
var el = $("#id");
var top = el.css("top");
el.css("top", top * 1.2); // increase top by 20%
saves mucking around in the DOM
This might be useful if you want to position things relatively: http://docs.jquery.com/UI/Position

How can I get the inherited CSS value using Javascript?

I'm trying to get the value of an inherited CSS property using Javascript. I haven't been able to find a comprehensive answer.
Example CSS:
div {
width: 80%;
}
Example Markup:
<div id="mydiv"> Some text </div>
Using javascript (jQuery, or native), I need to get the width of the element-- not in pixels, but the string "80%".
$('#mydiv').css('width'); // returns in px
$('#mydiv')[0].style.width // empty string
getComputedStyle($('#mydiv')[0]).width // returns in px
The reason I need the value as a string is because I need to copy the style to another element. If it's declared as a percent, the other value needs to be a percent. If it's declared in px, the other value needs to be in px.
The real trick is that this property could be inherited, not declared explicitly on the element (as in my example).
Does anyone have any ideas?
What you are searching for is this quirksmode.org article. It proposes the function
function getStyle(el, styleProp) {
var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
return y;
}
Still, you should read that article carefully. They names of the styleProps are not really cross-browser, and you will see how different browsers handle this. Opera seems to have the best support for reporting the correct values.
There's no way to get the percentage value I'm afraid. You can try something like this:
var widthpx = getComputedStyle($('#mydiv')[0]).width;
var parentWidth = $('#mydiv').parent().css('width')
var width = ( 100 * parseFloat(widthpx) / parseFloat(parentWidth) ) + '%';
get the offSetWidth of the element, and the offsetWidth of its offsetParent, and calculate the percentage from the two integers.
This binds an event handler to an element for the click event and alerts the element's relative width compared to it's parent element.
​$('#mydiv').on('click', function () {
//element width divided by parent width times 100 to make a percentage
alert(Math.round($(this).width() / $(this).parent().width() * 100) + '%');
});​​​​​​​​​​
Here is a demo: http://jsfiddle.net/X67p5/

Categories