Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to exact set a dynamic style transform using Javascript?

I know method of setting transform, but I want to set the rotate and to keep others such as scale and skew.

Perhaps, we can write a function as:

// A variable of element, not parameter. separate out it make more clear.
var el = document.getElementById('el');
function setTransform (p_name, p_value) {
  // how to write some code to set the el transform style...
}

Moreover, I have a element:

<div id="el" style="transform: rotate(45deg) skew(45deg);"></div>

And to us our function setTransform:

setTransform('rotate', '30deg');

I hope the element is this:

<div id="el" style="transform: rotate(30deg) skew(45deg);"></div>

So my question is how to write content of the function setTransform?

like image 459
Tychio Avatar asked Oct 30 '13 07:10

Tychio


2 Answers

Note: you should use skewX and/or skewY instead of skew. See the MDN info here.

It would be easier to keep track of the transforms in a variable:

var elRot,    // the rotation 'counter' for the element 'el'
    elScale,  // the scale 'counter' for the element 'el'
    elSkewX,  // the skewX 'counter' for the element 'el'
    elSkewY;  // the skewY 'counter' for the element 'el'

// initialize values
elRot = 0;
elScale = 1;
elSkewX = 0;
elSkewY = 0;

or an object:

var elTranform = {
    rot: 0,   // the rotation 'counter' for the element 'el'
    sca: 1,   // the scale 'counter' for the element 'el'
    skx: 0,   // the skewX 'counter' for the element 'el'
    sky: 0    // the skewY 'counter' for the element 'el'
};

So now you can start with the function (you will still use var el for the element), the first step is getting the values, so you change the arguments given to the function:

// use this with separate vars
function setTransform (element, rotationArg, scaleArg, skewXArg, skewYArg) {
    // how to write some code to set the el transform style...
}

// use this with the object
function setTransform (element, elTransformArg) {
    // how to write some code to set the el transform style...
}

Next you have re-specify any other transforms that are 'staying', in the example you give, the skewX remains 45deg:

function setTransform (element, rotationArg, scaleArg, skewXArg, skewYArg) {
    // the brackets cause the string to be evaluated before being assigned
    element.style.transform = ("rotate() scale() skewX() skewY()");
}

or

function setTransform (element, elTransformArg) {
    element.style.transform = ("rotate() scale() skewX() skewY()");
}

Now you have to put the arguments into the string:

function setTransform (element, rotationArg, scaleArg, skewXArg, skewYArg) {
    element.style.transform = ("rotate(" + rotationArg + "deg ) scale(" + scaleArg
        + ") skewX(" + skewXArg + "deg ) skewY(" + skewYArg + "deg )");
}

or

function setTransform (element, elTransformArg) {
    element.style.transform = ("rotate(" + elTransformArg.rot + "deg ) scale("
        + elTransformArg.sca + ") skewX(" + elTransformArg.skx + "deg ) skewY("
        + elTransformArg.sky + "deg )");
}

A bit messy, so put that string in a variable (this will be beneficial for the prefixes):

function setTransform (element, rotationArg, scaleArg, skewXArg, skewYArg) {
    var transformString = ("rotate(" + rotationArg + "deg ) scale(" + scaleArg
        + ") skewX(" + skewXArg + "deg ) skewY(" + skewYArg + "deg )");
    
    // now attach that variable to each prefixed style
    element.style.webkitTransform = transformString;
    element.style.MozTransform = transformString;
    element.style.msTransform = transformString;
    element.style.OTransform = transformString;
    element.style.transform = transformString;
}

or

function setTransform (element, elTransformArg) {
    var transformString= ("rotate(" + elTransformArg.rot + "deg ) scale("
        + elTransformArg.sca + ") skewX(" + elTransformArg.skx + "deg ) skewY("
        + elTransformArg.sky + "deg )");
    
    // now attach that variable to each prefixed style
    element.style.webkitTransform = transformString;
    element.style.MozTransform = transformString;
    element.style.msTransform = transformString;
    element.style.OTransform = transformString;
    element.style.transform = transformString;
}

Now call the function:

setTransform(el, elRot, elScale, elSkewX, elSkewY);

or

setTransform(el, elTransform);

To change values, change the variables or object values and call:

elRot = 45;
elSkewX = 30;
setTransform(el, elRot, elScale, elSkewX, elSkewY);

or

elTransform.rot = 45;
elTransform.skx = 30;
setTransform(el, elTransform);

This way you only have to change the 'counter' values for each transform, and call the function to apply the transform. As mentioned above, it is important to keep any transforms that are not changed as this simply replaces the previous CSS value for the transform with the new one. Giving multiple values means only the last one is used (the C part of CSS).

like image 125
thisiate Avatar answered Oct 23 '22 04:10

thisiate


The absolute best answer here would be a real API that allows us to affect any existing value of computed style without having to parse values. Such a thing exists in some abandonned and non-cross-browser form with the WebkitCSSMatrix API and the W3C "official" equivalent DOMMatrix. I've seen talks of reformatting and consolidating those two APIs, but they don't seem to agree on implementation. Here's a shim to make it work cross-browser : CSSMatrix class from github user arian.

How this works is that you can pass it the computed transform string (ex.: "translsate3d(0px, 0px, 100px) scale(1.2) skew(2)") and it returns an object that you can manipulate with rotate, transform, translate, skew functions. Every functions return an existing instance of itself with the newly manipulated value and you can simply re-apply its "toString" value to the element style property.

A lot of words, but here's an example (Chrome and Safari only because of the WebkitCSSMatrix usage) :

var computedStyle = window.getComputedStyle(document.querySelector('.btn'));
var matrix = new WebKitCSSMatrix(computedStyle.transform);

// Every second, we add +6 degrees of rotation, no need to read the initial value since WebkitCSSMatrix has parsed it for us
window.setInterval(function(){
  matrix = matrix.rotate(6);
  // matrix = matrix.translate(2, 0, 0);
  // matrix = matrix.scale(1.8);
  document.querySelector('.btn').style.transform = matrix.toString();
}, 1000);
body{
			padding-top: 100px;
			text-align: center;
		}

		.btn{
			text-transform: uppercase;
			border-radius:200%;
			border:1px solid #000;
			width: 2em;
			height: 2em;
			display: inline-block;
			text-align: center;
			line-height: 2em;
			text-decoration: none;
			font-family: sans-serif;
			color: #000;
      
      // It is already rotated and scaled
			transition: transform 1000ms cubic-bezier(.28,.73,.31,1);
      transform: rotate(45deg);
      -webkit-transform: rotate(45deg);
		}

		.btn:hover{
			background:#000;
			color:#fff;
      
      transform: rotate(0deg) scale(1.5);
		}
<a class="btn" href="#">|</a>
like image 27
davidwebca Avatar answered Oct 23 '22 02:10

davidwebca