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.
Add a transform value to the current transforms that are already on the element?
You could use the +=
operator to append the rotateX(20deg)
to the already existing transformation.
el.style.webkitTransform += "rotateX(20deg)";
Note: I have used a different transformation in the below snippet for the visual effect but method is the same.
window.onload = function() { var el = document.getElementsByTagName("div")[0]; el.style.webkitTransform += "rotateZ(20deg)"; console.log(el.style.webkitTransform); document.getElementById("changeDeg").onclick = changeDeg; //event handler}
function changeDeg() { var el = document.getElementsByTagName("div")[0]; var re = /(rotateZ)(\(.*(?:deg\)))/g; //regex to match rotateZ(...deg) var newDeg = 40; if (el.style.webkitTransform.match(re).length != -1) { el.style.webkitTransform = el.style.webkitTransform.replace(re, '$1(' + newDeg + 'deg)'); // $1 is first capturing group which is "rotateZ" } console.log(el.style.webkitTransform);}
div { background: red; margin-bottom: 20px;}
<div class="display-object child0" style="-webkit-transform: translateX(43.5px) translateY(6px); width: 50px; height: 50px;"></div><button id="changeDeg">Change Rotation</button>
change values of transform: translate(-13px, 0px) scale(1, 1) rotate(0deg) separately
I solved it by using split
var observer = new MutationObserver(function(mutations) {
arrsplit = document.getElementsByTagName('span')[0].style.transform.split(/[\(,)px]+/);
replace = arrsplit[7].replace('deg','')
mirror= arrsplit[0]+"("+parseFloat(arrsplit[1])*-1+"px"+", "+parseFloat(arrsplit[2])*1+"px"+")"
+arrsplit[3]+"("+parseFloat(arrsplit[4])*1+", "+parseFloat(arrsplit[5])*1+")"+
arrsplit[6]+"("+parseFloat(replace)*-1+"deg"+")";
mutations.forEach(function(mutationRecord) {
document.getElementsByTagName('span')[3].style.transform = mirror
console.log('style changed!');
}
var observer1 = new MutationObserver(function(mutations) {
arrsplit = document.getElementsByTagName('span')[3].style.transform.split(/[\(,)px]+/);
replace = arrsplit[7].replace('deg','')
mirror= arrsplit[0]+"("+parseFloat(arrsplit[1])*-1+"px"+", "+parseFloat(arrsplit[2])*1+"px"+")"
+arrsplit[3]+"("+parseFloat(arrsplit[4])*1+", "+parseFloat(arrsplit[5])*1+")"+
arrsplit[6]+"("+parseFloat(replace)*-1+"deg"+")";
mutations.forEach(function(mutationRecord) {
var transform1 = document.getElementsByTagName('span')[3].style.transform;
document.getElementsByTagName('span')[0].style.transform = mirror
});
});
var target = document.getElementsByTagName('span')[0];
var target2 = document.getElementsByTagName('span')[3];
observer1.observe(target2, { attributes : true, attributeFilter : ['style'] });
observer.observe(target, { attributes : true, attributeFilter : ['style'] });
How to apply multiple transforms in CSS?
You have to put them on one line like this:
li:nth-child(2) {
transform: rotate(15deg) translate(-20px,0px);
}
When you have multiple transform directives, only the last one will be applied. It's like any other CSS rule.
Keep in mind multiple transform one line directives are applied from right to left.
This: transform: scale(1,1.5) rotate(90deg);
and: transform: rotate(90deg) scale(1,1.5);
will not produce the same result:
.orderOne, .orderTwo { font-family: sans-serif; font-size: 22px; color: #000; display: inline-block;}
.orderOne { transform: scale(1, 1.5) rotate(90deg);}
.orderTwo { transform: rotate(90deg) scale(1, 1.5);}
<div class="orderOne"> A</div>
<div class="orderTwo"> A</div>
Apply two different CSS transforms simultanesouly
transform
is a single property, so you can't target from CSS for only part of it, e.g, you cannot set different CSS transition-duration
for two transform-functions applied in the same transform
property.
You could write everything through js, updating yourself both transform-functions values over time, but that would be a lot of work, for a potentially non-hardware accelerated result, while there is a simple workaround.
The easiest solution is to change a little bit your structure so that you apply the scale
on a wrapper element, and the translate on the inner-one.
This way, both transforms are applied on your inner <img>
, but they don't conflict each other.
// JavaScript source codevar catchX = 0, catchY = 0, x = 0, y = 0, burn = 1 / 28;
function imageWatch() { x += (catchX - x) * burn;
translate = 'translate(' + x + 'px, ' + y + 'px)';
$('.image-area img').css({ '-webit-transform': translate, '-moz-transform': translate, 'transform': translate });
window.requestAnimationFrame(imageWatch);}
$(window).on('mousemove click', function(e) {
var mouseX = Math.max(-100, Math.min(100, $(window).width() / 2 - e.clientX)); catchX = (26 * mouseX) / 100;
});
imageWatch();
html,body { height: 100%}
body { margin: 0; padding: 0;}
*,*::before,*::after { content: "\0020"; box-sizing: border-box;}
.poster { display: inline-block; width: 32vw; height: 100vh; position: relative; overflow: hidden !important}
.image-area { position: absolute; width: 100%; height: 100vh; opacity: .24; transition: 2.5s ease;}
.image-area { opacity: 1;}
.image-area img { margin-top: -312px; margin-left: -913px; width: auto; /* height: auto */ height: 1000px; /* here we can remove the transition */}
/* scaling on hover is only applied on the parent elmt */
.image-area>.scaler { transform: scale(1, 1); transition: 8s transform;}
.poster:hover .image-area>.scaler { transform: scale(1.3, 1.3);}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div class="poster"> <div class="image-area"> <!-- the scaling wrapper--> <div class="scaler"> <img class="poster" src="https://vignette1.wikia.nocookie.net/logopedia/images/f/fc/Sky_Believe_in_better_logo.jpg/revision/latest?cb=20110910152552" alt="Sky" /> </div> </div></div>
<div class="poster"> <div class="image-area"> <!-- the scaling wrapper--> <div class="scaler"> <img class="poster" src="https://vignette1.wikia.nocookie.net/logopedia/images/f/fc/Sky_Believe_in_better_logo.jpg/revision/latest?cb=20110910152552" alt="Sky" /> </div> </div></div>
<div class="poster"> <div class="image-area"> <!-- the scaling wrapper--> <div class="scaler"> <img class="poster" src="https://vignette1.wikia.nocookie.net/logopedia/images/f/fc/Sky_Believe_in_better_logo.jpg/revision/latest?cb=20110910152552" alt="Sky" /> </div> </div></div>
How do I use other values in a vector in a std::transform?
You can add lambda capture to store the previous element's value.
E.g.
std::vector<int> v2(v1.size());
std::transform(v1.begin(), v1.end(), v2.begin(),
[pv = 0](int val) mutable { int nv = pv + val; pv = val; return nv; });
LIVE
PS: Captures with initializer was supported since C++14.
r, dplyr: how to transform values in one column based on value in another column using gsub
str_remove
is vectorized for the pattern
instead of gsub
library(stringr)
library(dplyr)
df <- df %>%
mutate(x = str_remove(x, y))
-output
df
x y
1 bc a
2 ac b
3 abc d
If we want to use sub/gsub
, then may need rowwise
df %>%
rowwise %>%
mutate(x = sub(y, "", x)) %>%
ungroup
Transform all Array Keys with Values from another Array
This should do the trick:
var data = [['id', 'name', 'value'], [0, 'foo', true], [2, 'bar', false], [3, 'baz', null], [4, 'foobar', undefined] ];
var keys = data.shift(); // Get the first row, containing the keysvar result = data.map(function(row) { var current = {}; // Create a new element for (var i = 0; i < keys.length; i++) { current[keys[i]] = row[i]; // Map the current row to keys on the new element } return current; // Return the new element, to be used in the result.});
console.log(result);
Related Topics
How to Grab and Drag an Element Around a Circle
How to Add a Space After Ng-Repeat Element
Turn Off CSS3 Animation with Jquery
How to Use Feature Detection to Know If Browser Supports Border-Radius? (Including IE9)
Iframe Dynamic Height Width Change Based on Inner Content
How to Find Element Has Specific Color Using Jquery
How to Display Select Options as Buttons
Laravel 8 + Nginx - App.CSS and App.Js Resources from Public/ Not Loading - 404 Not Found
Variable in JavaScript Statement
Rotating Clickable Elements in IE8+
JavaScript to Print Contents of Only Specific <Div>
Trigger a Click on a Different Element When Clicking an Other Div
Does Animating the Value of a CSS3 Transform with JavaScript Rule Out Hardware Acceleration