Reputation:
Currently I've got this code which continuously spins the text with a 3d effect. However, what I want to do is get the text to do one complete rotation or 360 degree spin the left, then pause for a moment, then do the same to the right and keep going with the same. I would appreciate any advice how to approach this in Javascript but not Jquery or CSS as I particularly want to practice my Javascript skills, thankyou.
function spin()
{
document.getElementById("myDIV");
setInterval(function()
{
myDIV.style.transform += "rotate3d(0,10,0,10deg)";
}, 80);
}
spin();
<div style="text-align:center;"><h1 id='myDIV'>my 3d text</h1>
Upvotes: 1
Views: 366
Reputation: 12422
I wanted to provide an example of how you could do this with requestAnimationFrame to provide a more fluid, consistent animation. Instead of relying on setInterval
s sometimes inconsistent intervals to drive how often the degrees are updated, when using requestAnimationFrame
, you calculate how much change should have taken place since the last paint and then update accordingly.
I also added the abilty to pass in an id instead of using a fixed element and my function returns a function that can be used to stop the animation.
function spin (id) {
// just a flag to allow us to cancel the animation if we want to
let keepGoing = true;
// function that will be returned to allow us to cancel the animation
const stop = () => keepGoing = false;
const el = document.getElementById(id);
let degrees = 0;
let dir = 1; // current direction of animation; 1 === forward, -1 === backward
// your original code moves the animation 10 deg per 80 ms,
// which is equivalent to 8 deg per ms, thus the speed of 8
const speed = 8;
// lastTime will be used to track how many ms have passed since the last time
// the callback was called. Since the first call to the callback will be
// manual instead of via requestAnimationFrame, we need to manually get a
// DOMHighResTimeStamp via performance.now().
let lastTime = performance.now();
// this callback will be used with requestAnimationFrame to run the animation,
// it expects to get the a DOMHighResTimeStamp as its parameter, which
// requestAnimationFrame will provide, on every call after the initial manual
// call to it using the lastTime we generated above.
const callback = currentTime => {
// calculate number of ms between now and the last time this callback ran
const delta = currentTime - lastTime;
lastTime = currentTime;
// calculate how many degrees we should move based on how long it has been
// since the last callback (ms / deg per ms)
const change = delta / speed;
// dir will be either 1 or -1, multiplying by dir will either increase
// or decrease "degrees" by "change" degrees.
degrees += dir * change;
// apply the new transformation
el.style.transform = `rotate3d(0, 1, .2, ${degrees}deg`;
// reverse directions if needed
if (degrees >= 360) {
dir = -1;
} else if (degrees <= 0) {
dir = 1;
}
if (keepGoing) {
requestAnimationFrame(callback);
}
};
// start the animation by manually calling the callback
callback(lastTime);
return stop;
}
let stopMyDivSpinning = spin('my-div');
// stop spinning after 20 seconds
setTimeout(stopMyDivSpinning, 20000);
#my-div {
font-size: 3em;
text-align:center;
background: linear-gradient(0.25turn, #3f87a6, #f69d3c);
background-clip: text;
-webkit-background-clip: text;
color: rgba(0,0,0,0);
}
<div id="my-div">My 3D Text</div>
Further reading
Upvotes: 1
Reputation: 14561
You don't need JS for this. It can be accomplished using CSS Animation.
In the snippet below, I have set the div to rotate in one direction through the keyframes defined, and then by specifying animation-direction: alternate;
it rotates in alternating directions.
Note that I have kept the z
component of rotation to 0.2 so that I could visualize that it's working. For what you need, the z
component should be zero.
#myDIV {
animation: 5s linear infinite alternate rotate ;
}
@keyframes rotate {
0%,
100% {
transform: rotate3d(0, 1, 0.2, 0deg);
}
50% {
transform: rotate3d(0, 1, 0.2, 360deg)
}
}
<div style="text-align:center;">
<h1 id='myDIV'>my 3d text</h1>
</div>
JS Version:
With JS, I think you need to keep track of the current angle of rotation (so that you can increase it in the next iteration) and current direction of rotation (so that you can decide whether to increase the angle or decrease it).
I chose against appending to the style (myDIV.style.transform += "rotate3d(0,10,0,10deg)";
) because I suspect at some point the browser might start getting slow. So instead I am managing the rotation through the global variables (i.e. instead of having two 10deg rotation, keeping one 20deg rotation).
I believe this can be simplified much further, but hopefully it demonstrates a possible approach. Also, you can improve the animation timing accuracy (as compared to setInterval
) by using requestAnimationFrame
if you are interested.
var currentAngle = 0;
var currentDirection = 0; // 0 - Increasing, 1 - Decreasing
function spin() {
document.getElementById("myDIV");
setInterval(function() {
if(currentDirection == 0) {
// Allow one complete rotation.
if(currentAngle < 360) {
myDIV.style.transform = "rotate3d(0,1,0.2,"+ currentAngle +"deg)";
currentAngle += 10;
} else {
// Change the direction.
currentDirection = 1;
currentAngle -= 10;
myDIV.style.transform = "rotate3d(0,1,0.2,"+ currentAngle +"deg)";
}
} else {
// Allow one complete rotation.
if(currentAngle > 0) {
myDIV.style.transform = "rotate3d(0,1,0.2,"+ currentAngle +"deg)";
currentAngle -= 10;
} else {
// Change the direction.
currentDirection = 0;
currentAngle += 10;
myDIV.style.transform = "rotate3d(0,1,0.2,"+ currentAngle +"deg)";
}
}
}, 80);
}
spin();
<div style="text-align:center;">
<h1 id='myDIV'>my 3d text</h1>
</div>
Upvotes: 2