Using multiple .style.transform on same element - javascript

It seems that by using two cases of obj.style.transform in succession results in only the first statement being executed. Please see the below code. A full example is on CodePen.
function animateObject(x, y, z){
object = document.getElementsByClassName('cub-1')[0];
object.style.transform = "rotateX(" + x + "deg)";
object.style.transform = "rotateY(" + y + "deg)";
alert("")
}
In the full example, I am reading lines from a text area which contains x, y and z positions of an object, converting the values from radians to degrees and then animating my 3d object using these values.

When applying multiple transforms to the same element, they should be added as space separated values to the same property like below. Otherwise, they would get overwritten (only the rotateY will be applied because it is the latest).
object.style.transform = "rotateX(" + x + "deg)";
object.style.transform += "rotateY(" + y + "deg)";
I have added an alert of the object.style.transform to both the original snippet and the modified version and we can see how the original one always outputs only the rotateY whereas the changed one outputs both rotateX() and rotateY() together.
Original Code with Alerts added |
Modified Code with Alerts added

You could use DOMMatrix to build/chain your CSS transform.
Then stringify the resultant matrice with its build in DOMMatrixReadOnly.toString(). Which returns CSS ready transform syntax.
window.onload = () => {
const getStyle = id => document.getElementById(id).style;
// Rotate in plane
getStyle('Ⅰ').transform = new DOMMatrix('rotateZ(45deg)');
// Rotate from [1,1] vector (diagonal) (same as Ⅰ)
getStyle('Ⅱ').transform = new DOMMatrix().rotateFromVectorSelf(1, 1);
// Rotate matrix on Z axis. (same as Ⅰ & Ⅱ)
getStyle('Ⅲ').transform = new DOMMatrix().rotateAxisAngleSelf(0, 0, 1, 45);
// Rotate matrix on X axis. Then rotate matrix on Y axis.
getStyle('Ⅳ').transform = new DOMMatrix('rotateX(45deg) rotateY(45deg)');
// Rotate matrix on X axis. Then rotate matrix on Y axis (same as Ⅳ)
getStyle('Ⅴ').transform = new DOMMatrix('rotateX(45deg)').multiply(new DOMMatrix('rotateY(45deg)'));
// Rotate matrix on Y axis. Then rotate matrix on X axis.
getStyle('Ⅵ').transform = new DOMMatrix('rotateY(45deg)').multiply(new DOMMatrix('rotateX(45deg)'));
// Rotate matrix on Y/X axis. (same as Ⅵ)
getStyle('Ⅶ').transform = new DOMMatrix().rotateSelf(45, 45);
};
.element {
transition: transform 1s;
padding: 5px;
opacity: .7;
}
.element::after {
content: attr(id);
}
#Ⅰ { background: red; transition-delay: 0s;}
#Ⅱ { background: green; transition-delay: 1s; }
#Ⅲ { background: blue; transition-delay: 2s; }
#Ⅳ { background: orange; transition-delay: 3s; }
#Ⅴ { background: purple; transition-delay: 4s; }
#Ⅵ { background: pink; transition-delay: 5s; }
#Ⅶ { background: coral; transition-delay: 6s;}
.frame {
position: relative;
margin: 20px;
display: grid;
grid-auto-flow: column;
grid-auto-columns: 80px;
grid-auto-rows: 80px;
border: 1px solid;
}
<div class="frame">
<div class="element" id="Ⅰ"></div>
<div class="element" id="Ⅱ"></div>
<div class="element" id="Ⅲ"></div>
<div class="element" id="Ⅳ"></div>
<div class="element" id="Ⅴ"></div>
<div class="element" id="Ⅵ"></div>
<div class="element" id="Ⅶ"></div>
</div>

Related

Add css to elements rendered using js in VueJs

I want to add css to elements which I rendered in a method using js.
buttonClicked(event) {
console.log(event);
let x = event.clientX - event.target.offsetLeft;
let y = event.clientY - event.target.offsetTop;
let ripples = document.createElement("span");
console.log(ripples);
ripples.style.left = x + "px";
ripples.style.top = y + "px";
document.getElementById("btn").appendChild(ripples);
}
So this is a function which get called when a user clicks on a button. I want to add the css to <span> which gets created in this method.
The css for <span> element is not rendering when I'm using scoped css. Its working fine without the scoped keyword.
I googled the problem and find this link. Here it's told we can use /deep/ or >>> operator to access the span elements. But it's still not working.
Here's the CSS
button >>> span {
z-index: 3;
position: absolute;
background: white;
transform: translate(-50%, -50%);
pointer-events: none;
border-radius: 50%;
animation: animate 1s linear infinite;
}
I believe you are correct that it is necessary to use /deep/ or >>> with injected HTML when using scoped. Your code essentially works. However, I had to add some width and height to the actual appended element for anything visually to appear. Not sure what the rest of your code looks like, but the following component works on my machine:
<template>
<button #click="makeRipple">
CLICK ME
</button>
</template>
<script>
export default {
name: 'Button',
methods: {
makeRipple (event) {
const x = event.clientX - event.target.offsetLeft
const y = event.clientY - event.target.offsetTop
const ripples = document.createElement('span')
ripples.style.left = x + 'px'
ripples.style.top = y + 'px'
event.target.appendChild(ripples)
}
}
}
</script>
<style scoped>
#keyframes ripple {
to {
opacity: 0;
transform: scale(4);
}
}
button >>> span {
z-index: 3;
position: absolute;
background: white;
transform: translate(-50%, -50%);
pointer-events: none;
border-radius: 50%;
animation: ripple 1s linear infinite;
width: 6px;
height: 6px;
}
</style>

Need some help in creating a visual representation of device orientation using JS

Basically, I am wanting to create a visual representation of the device orientation values alpha, beta, and gamma. So far I have managed to display the values in plain text using innerHTML, but I want to create a series of "bars" for each value. I drew a very crude drawing of what I had in mind:
Basically, I want the bars to move in relation to changes in the alpha, beta and gamma values. This is how my code looks now.
<!DOCTYPE HTML>
<html>
<body>
<p>Alpha: <span id="alpha"></span></p>
<p>Beta: <span id="beta"></span></p>
<p>Gamma: <span id="gamma"></span></p>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
// Listen for device orientation event
window.ondeviceorientation = function(eventData)
{
// Show alpha, beta and gamma values
document.getElementById('alpha').innerHTML = Math.round(eventData.alpha);
document.getElementById('beta').innerHTML = Math.round(eventData.beta);
document.getElementById('gamma').innerHTML = Math.round(eventData.gamma);
}
</script>
</body>
</html>
I highly doubt I can do this using inner HTML because I think I would need to use CSS styling. This makes me think that the canvas might work, but I have trouble initializing it using the ondeviceorientation. I would appreciate any help in accomplishing this.
You don't need a canvas. You can do this just by altering the width of your spans along with using CSS to set the colors.
Firstly make sure your spans have a CSS property of display : inline-block or display : blockor else changing the width will do nothing. Alternatively you can make them divs instead of spans. Also make sure it has a height property set such as 30px.
Next you can use css or inline-styles to set the background-color property for alpha, beta, and gamma. Then simply change the Element.style.width property (in px) based on the device orientation using javascript.
Something you might want to consider deeply is what you want the size of the bars to represent and their precise behavior. That design decision is up to you, so I won't explain in excruciating detail how the following code works, but basically I size them relative to the range of the values. I turn the value of alpha, beta, and gamma respectively into a percentage of their total range and then multiply that by the max width I would like for the bars.
I grabbed the ranges from here: https://developer.mozilla.org/en-US/docs/Web/API/Detecting_device_orientation
The general formula is for values in range [a, b] and a maximum bar width of max_w, and alpha, beta, or gamma value of value, the calculated width of the bar is:
width = max_w * ( ( -a + value ) / (b - a) )
And don't forget to add "px" to the end.
// Listen for device orientation event
window.ondeviceorientation = function(eventData)
{
let maxWidth = 200;
// Show alpha, beta and gamma values
document.getElementById('alpha').style.width = Math.round(maxWidth * eventData.alpha / 360) + "px";
document.getElementById('beta').style.width = Math.round(maxWidth * (180 + eventData.beta) / 360) + "px";
document.getElementById('gamma').style.width = Math.round(maxWidth * (90 + eventData.gamma) / 180) + "px";
}
p span{
height : 30px;
display : inline-block;
}
#alpha{
background-color : green;
}
#beta {
background-color : yellow;
}
#gamma {
background-color : purple
}
<p> Alpha: <span id="alpha"> </span> </p>
<p> Beta: <span id="beta"> </span> </p>
<p> Gamma: <span id="gamma"> </span></p>
The previous poster, Khauri McClain, posted a good suggestion for a static representation of your orientation values. If by "move" you mean, however, an animation (and hence refer to canvas), then you can still do it without canvas, but instead using CSS keyframes. Here is quick example.
html,
body {
height: 100%;
}
body {
background-color: #f5f7f9;
color: #6c6c6c;
margin: 0;
position: relative;
}
.container {
width: 30em;
margin: 2em;
}
.label {
float: left;
width: 5em;
height: 2em;
}
.orientation {
float: right;
background-color: #e5e9eb;
height: 2em;
position: relative;
width: 24em;
}
.alpha {
animation-duration: 3s;
animation-name: alpha-anim;
animation-fill-mode: forwards;
background-color: #ff2d55;
height: 100%;
position: relative;
}
.beta {
animation-duration: 3s;
animation-name: beta-anim;
animation-fill-mode: forwards;
background-color: #4cd964;
height: 100%;
position: relative;
}
.gamma {
animation-duration: 3s;
animation-name: gamma-anim;
animation-fill-mode: forwards;
background-color: #007aff;
height: 100%;
position: relative;
}
#keyframes alpha-anim {
0% {
width: 0;
}
100% {
width: 14em;
}
}
#keyframes beta-anim {
0% {
width: 0;
}
100% {
width: 3em;
}
}
#keyframes gamma-anim {
0% {
width: 0;
}
100% {
width: 20em;
}
}
<div class="container">
<div class="label">Alpha:</div>
<div class="orientation">
<div class="alpha"></div>
</div>
</div>
<div class="container">
<div class="label">Beta:</div>
<div class="orientation">
<div class="beta"></div>
</div>
</div>
<div class="container">
<div class="label">Gamma:</div>
<div class="orientation">
<div class="gamma"></div>
</div>
</div>

DOM Coordinates are wrong when using CSS Transformations

I'm trying to solve how to get the correct coordinates and movement of the element but find that the CSS Transformation doesn't align with the elements DOM coordinates.
I've tried to also change the properties of the element's CSS Transformation via the JS code itself.
The problem you can see in the demo is that the element doesn't reach all four corners of the #wrap div.
Is it also better to incorporate a skew or perspective property rather than rotations? I've just read Top & Left position with Transform Rotate (posted as a duplicated question), but this doesn't explain how to rotation of this example's prespective would work?
HTML
<div id="wrap">
<div id="thing"></div>
</div>
JS
$(function() {
$("#wrap").click(function(e) {
var offset = $(this).offset();
var relativeX = (e.pageX - offset.left);
var relativeY = (e.pageY - offset.top);
document.getElementById("thing").style.left = relativeX + "px";
document.getElementById("thing").style.top = relativeY + "px";
document.getElementById("thing").innerHTML = relativeX + "<br />" + relativeY;
});
});
CSS
#wrap {
height: 300px;
width: 500px;
background: green;
position: relative;
overflow: hidden;
transform: rotateX(60deg) rotateZ(-30deg);
}
#thing {
background: blue;
width: 50px;
height: 50px;
position: absolute;
transition: 1s;
left: 0;
top: 0;
}
Live: https://jsfiddle.net/h9ad4k63/

How to increase rotate value

The Problem
I want to increase the rotate value to a div by using jquery, i know you can increase the value of height and width by $("#div").css('height','+=200px') but you cant do that with transform property because it got many value like translate, rotate, scale, and skew.
Question
How to increase rotate value transform: rotate(30deg); by 30deg to become 60deg ?
i dont want to do transform: rotate(60deg); with css or$("#mydiv").css('transform','rotate(60deg)') with Jquery.
Code
// Any idea ?
#container{
padding: 100px;
}
#mydiv{
height: 200px;
width: 200px;
background: pink;
transform: rotate(30deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="mydiv"></div>
</div>
Hint
I tried $("#mydiv").css('transform') it return matrix value.
You can do it by adding rotate into your css('transform' call:
var value = 60;
$("#mydiv").css('transform', 'rotate(' + value + 'deg)');
More demos with CSS3 transitions using jQuery here
Solution
the getRotationDegrees() function will calculate the rotate degress and return the value.
function getRotationDegrees(obj) {
var matrix = 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;
}
var rotate = getRotationDegrees($("#mydiv")) + 30;
$('#mydiv').css('transform', 'rotate('+rotate+'deg)')
#container{
padding: 100px;
}
#mydiv{
height: 200px;
width: 200px;
background: pink;
transform: rotate(30deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="mydiv"></div>
</div>
EDIT: oops ... I just saw that you don't want to use css, but I will leave answer here for reference
isn't this the purpose of transition?
.my_div_class__closed
{ transform : rotate(30deg) ;
transition : transform 200 ;
/* You could substitute 200 (as in milliseconds) to 0
if you want instantaneous change.
*/
}
.my_div_class__opened
{ transform : rotate(60deg) ;
}
NOTE: vendor prefixes not used in example ... if you don't know vendor prefixes, then copy/paste css snippet into service like autoprefixer .. and be sure to use filter value: >0%

Preserving and adding new transform on hover (CSS/LESS)

To make it simple, I have a div that I rotate by default with a JS code. But then I want to add a :hover class, so that it translates when hovering over it. The problem is, that either the new transform does not apply, or the old is not preserved.
How can I make it work? Btw, I am using LESS, so if there's a solution with LESS, would be happy to hear it.
P.S. The angle is being generated according to the number of siblings in JS. Maybe I would be able to do a rotation with LESS and then do a :hover there?
document.getElementById("box").style.transform = "rotate(" + 40 + "deg)";
#box {
width: 50px;
height: 50px;
background-color: red;
transition: all 0.5s ease-in;
}
#box:hover {
background-color: blue;
transform: translate(50px) !important;
}
<div id="box">
</div>
you cannot achieve the desired result using CSS/LESS. You have to use JavaScript to generate dynamic styles. A script similar to below can do the task on your hand:
var dynamic_styles = '';
var counter = 1;
$('.box').each(function() {
$(this).attr('data-num', counter);
dynamic_styles += '.box[data-num="' + counter + '"] {transform: rotate(40deg);}';
dynamic_styles += '.box[data-num="' + counter + '"]:hover {transform: rotate(40deg) translate(50px);}';
counter++;
});
$('head').append('<style>' + dynamic_styles + '</style>');
Please check the codepen here:
http://codepen.io/anon/pen/LGzXEM
P.S. You can change the rotation 40deg with your dynamically calculated values.

Categories