I really hope I explain this well.
How I want / envision the animation to work
The animation is a wheel that turns six times. On each stop / rotation a triangular highlight mark should come out to the right of the most right facing icon (If a clock then at 3 o clock) to illustrate this icon is selected and to highlight text (text is not currently there).
My Issue
Although the way I want it to work currently works there is a delay however of when the triangular highlight mark appears which I hope to get to appear as soon as the rotation stops. I have a JSFiddle below as an example, although you will need to open the animation in the JSFiddle to full screen to see what I mean. Just for further clarification please see this very short video highlight what I mean. I apoligise if the video is a little overkill I just want my issue to be clear
Please note the JSFiddle needs to be open in full screen
JSFiddle
HTML
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<div class="container animation-banner-container">
<div class="row">
<div class="col-lg-6 col-md-12">
<div class="outCircle">
<div class="rotate">
<div class="counterrotate"></div>
</div>
</div>
<div class="outCircle">
<div class="imgmap-container">
<!-- Image Map Generated by http://www.image-map.net/ -->
<img src="https://wordpress-84115-2057283.cloudwaysapps.com/wp-content/uploads/2021/08/inner-circle.png" usemap="#image-map">
<map name="image-map">
<area target="" alt="one" title="one" href="" coords="702,350,824,276,837,299,846,315,852,330,857,344,861,361,865,372,878,378,890,387,900,396,910,405,918,414,922,423,929,431,934,444,938,456,940,472,940,493,936,509,932,524,921,538,915,549,907,561,890,575,870,583,863,604,854,626,840,657,834,673,828,679,702,609,716,572,724,551,730,522,736,471,729,427,718,378" shape="poly">
<area target="" alt="two" title="two" href="" coords="699,608,828,677,816,702,802,722,784,745,764,769,776,791,775,806,774,835,763,864,743,888,716,910,672,920,641,916,606,903,576,873,536,882,480,887,480,737,537,731,587,711,631,685,671,650" shape="poly">
<area target="" alt="three" title="three" href="" coords="481,738,480,887,450,885,413,882,384,876,358,894,330,902,290,902,252,885,222,849,209,811,209,784,175,751,150,720,132,694,127,685,253,612,285,654,323,689,354,710,409,729,448,736" shape="poly">
<area target="" alt="four" title="four" href="" coords="251,612,125,687,109,653,96,617,87,591,48,574,16,538,2,488,7,452,21,420,44,392,74,377,85,371,101,331,111,311,120,293,126,281,246,351,231,383,222,417,215,457,214,504,226,557" shape="poly">
<area target="" alt="five" title="five" href="" coords="125,280,247,352,277,305,310,275,339,255,382,234,413,222,442,218,466,217,476,217,474,76,432,80,406,83,388,86,372,70,341,51,297,46,253,57,225,75,205,104,192,135,192,179,195,192,167,221,146,246" shape="poly">
<area target="" alt="six" title="six" href="" coords="475,218,474,76,507,77,548,82,574,50,607,32,642,25,672,28,698,37,722,53,744,74,756,99,765,135,762,165,754,188,782,216,798,235,815,257,826,278,802,292,755,318,713,343,702,349,659,293,622,260,569,235,521,222" shape="poly">
</map>
</div>
</div><!-- Close Outer Circle -->
</div>
<div class="col-lg-6 col-md-12">
<div class="highlight-container">
</div>
</div>
</div>
</div>
CSS
.animation-banner-container {
height: 600px;
}
.highlight-container {
height: 600px;
background-size: cover !important;
margin-left: -15% !important;
}
.counterrotate {
width: 500px;
height: 500px;
background: url('https://wordpress-84115-2057283.cloudwaysapps.com/wp-content/uploads/2021/08/alarm-inner.png');
background-size: 500px 500px;
background-repeat: no-repeat !important;
padding: 150px !important;
}
.rotate {
width: 500px;
height: 500px;
background-size: 500px 500px;
}
.outCircle {
width: 500px;
height: 500px;
position: absolute;
top: 50px;
-moz-border-radius: 100px;
-webkit-border-radius: 100px;
border-radius: 100px;
z-index: 2;
pointer-events: none;
}
.imgmap-container{
position: relative;
width: 500px !important;
height: 500px !important;
z-index: 1;
}
.imgmap-container img{
width: 500px;
height: 500px;
}
.img-map area:focus {
outline: 0 !important;
}
#keyframes circle-one {
from { transform: rotateZ(0deg); }
to { transform: rotateZ(60deg); }
}
#keyframes circle-two {
from { transform: rotateZ(60deg); }
to { transform: rotateZ(120deg); }
}
#keyframes circle-three {
from { transform: rotateZ(120deg); }
to { transform: rotateZ(180deg); }
}
#keyframes circle-four {
from { transform: rotateZ(180deg); }
to { transform: rotateZ(240deg); }
}
#keyframes circle-five{
from { transform: rotateZ(240deg); }
to { transform: rotateZ(300deg); }
}
#keyframes circle-six {
from { transform: rotateZ(300deg); }
to { transform: rotateZ(360deg); }
}
#keyframes ccircle-one {
from { transform: rotateZ(360deg); }
to { transform: rotateZ(300deg); }
}
#keyframes ccircle-two {
from { transform: rotateZ(300deg); }
to { transform: rotateZ(240deg); }
}
#keyframes ccircle-three {
from { transform: rotateZ(240deg); }
to { transform: rotateZ(180deg); }
}
#keyframes ccircle-four {
from { transform: rotateZ(180deg); }
to { transform: rotateZ(120deg); }
}
#keyframes ccircle-five {
from { transform: rotateZ(120deg); }
to { transform: rotateZ(60deg); }
}
#keyframes ccircle-six {
from { transform: rotateZ(60deg); }
to { transform: rotateZ(0deg); }
}
Javascript / JQuery
var seconds = 8000;
var tid = setInterval(mycode, seconds);
// Deterimes whether to start or stop
var start = 1;
// Set to first Slide
var slides = 1;
function mycode(val) {
if(!val) {
/* Controls the Stop and Start */
if(start == 0) {
$(".rotate").css({"animation-play-state": "paused"});
$(".counterrotate").css({"animation-play-state": "paused"});
$(".imgmap-container").css({"animation-play-state": "paused"});
$(".highlight-container").css({"background":"url('https://wordpress-84115-2057283.cloudwaysapps.com/wp-content/uploads/2021/08/highlight.png')"});
// Starts the Animation
start = 1;
}
else {
// Plays Animations
$(".rotate").css({"animation-play-state": "running"});
$(".counterrotate").css({"animation-play-state": "running"});
$(".imgmap-container").css({"animation-play-state": "running"});
$(".highlight-container").css({"background":"none"});
console.log("Rotating");
if(slides == 1) {
console.log("Slide 1");
/* Animations */
$(".rotate").css({"animation": "circle-two 4s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-two 4s forwards linear"});
$(".imgmap-container").css({"animation": "circle-two 4s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 2) {
console.log("Slide 2");
$(".rotate").css({"animation": "circle-three 4s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-three 4s forwards linear"});
$(".imgmap-container").css({"animation": "circle-three 4s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 3) {
console.log("Slide 3");
$(".rotate").css({"animation": "circle-four 4s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-four 4s forwards linear"});
$(".imgmap-container").css({"animation": "circle-four 4s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 4) {
console.log("Slide 4");
$(".rotate").css({"animation": "circle-five 4s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-five 4s forwards linear"});
$(".imgmap-container").css({"animation": "circle-five 4s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 5) {
console.log("Slide 5");
$(".rotate").css({"animation": "circle-six 4s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-six 4s forwards linear"});
$(".imgmap-container").css({"animation": "circle-six 4s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 6) {
console.log("Slide 6");
$(".rotate").css({"animation": "circle-one 4s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-one 4s forwards linear"});
$(".imgmap-container").css({"animation": "circle-one 4s forwards linear"});
slides = 1;
}
// Pauses the Animation
start = 0;
} // Close else
/* Close Controls the Stop and Start */
}
else {
abortTimer();
tid = setInterval(mycode, seconds);
}
if(val == 1 || val == 2 || val == 3 || val == 4 || val == 5 || val == 6) {
slides = val;
start = 1;
mycode();
}
}
function abortTimer() { // to be called when you want to stop the timer
clearInterval(tid);
}
$(document).ready(function(){
slides = 1;
mycode();
});
OK I got it. It was basically the seconds and the animation time needed to be changed. So originally my animation was 8000 seconds and the css forwards change animation was 4s. I ended up just changing to 6000 seconds and 6s and worked perfect.
JS Fiddle Example
The code change below
JS
// Seconds between each Animation
var seconds = 6000;
var tid = setInterval(mycode, seconds);
// Deterimes whether to start or stop
var start = 1;
// Set to first Slide
var slides = 1;
function mycode(val) {
if(!val) {
/* Controls the Stop and Start */
if(start == 0) {
$(".rotate").css({"animation-play-state": "paused"});
$(".counterrotate").css({"animation-play-state": "paused"});
$(".imgmap-container").css({"animation-play-state": "paused"});
$(".highlight-container").css({"background":"url('https://wordpress-84115-2057283.cloudwaysapps.com/wp-content/uploads/2021/08/highlight.png')"});
// Starts the Animation
start = 1;
}
else {
// Plays Animations
$(".rotate").css({"animation-play-state": "running"});
$(".counterrotate").css({"animation-play-state": "running"});
$(".imgmap-container").css({"animation-play-state": "running"});
$(".highlight-container").css({"background":"none"});
console.log("Rotating");
if(slides == 1) {
console.log("Slide 1");
/* Animations */
$(".rotate").css({"animation": "circle-two 6s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-two 6s forwards linear"});
$(".imgmap-container").css({"animation": "circle-two 6s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 2) {
console.log("Slide 2");
$(".rotate").css({"animation": "circle-three 6s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-three 6s forwards linear"});
$(".imgmap-container").css({"animation": "circle-three 6s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 3) {
console.log("Slide 3");
$(".rotate").css({"animation": "circle-four 6s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-four 6s forwards linear"});
$(".imgmap-container").css({"animation": "circle-four 4s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 4) {
console.log("Slide 4");
$(".rotate").css({"animation": "circle-five 6s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-five 6s forwards linear"});
$(".imgmap-container").css({"animation": "circle-five 6s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 5) {
console.log("Slide 5");
$(".rotate").css({"animation": "circle-six 6s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-six 6s forwards linear"});
$(".imgmap-container").css({"animation": "circle-six 6s forwards linear"});
// Increments to Next Slide
slides = slides + 1;
}
else if (slides == 6) {
console.log("Slide 6");
$(".rotate").css({"animation": "circle-one 6s forwards linear"});
$(".counterrotate").css({"animation": "ccircle-one 6s forwards linear"});
$(".imgmap-container").css({"animation": "circle-one 6s forwards linear"});
slides = 1;
}
// Pauses the Animation
start = 0;
} // Close else
/* Close Controls the Stop and Start */
}
else {
abortTimer();
tid = setInterval(mycode, seconds);
}
if(val == 1 || val == 2 || val == 3 || val == 4 || val == 5 || val == 6) {
slides = val;
start = 1;
mycode();
}
}
function abortTimer() { // to be called when you want to stop the timer
clearInterval(tid);
}
$(document).ready(function(){
slides = 1;
mycode();
});
So, I've got this -webkit-animation rule:
#-webkit-keyframes shake {
0% {
left: 0;
}
25% {
left: 12px;
}
50% {
left: 0;
}
75% {
left: -12px;
}
100% {
left:0;
}
}
And some CSS defining some of the animation rules on my box:
#box{
-webkit-animation-duration: .02s;
-webkit-animation-iteration-count: 10;
-webkit-animation-timing-function: linear;
}
I can shake the #box like this:
document.getElementById("box").style.webkitAnimationName = "shake";
But I can't shake it again later.
This only shakes the box once:
someElem.onclick = function(){
document.getElementById("box").style.webkitAnimationName = "shake";
}
How can I re-trigger a CSS animation via JavaScript without using timeouts or multiple animations?
I found the answer based on the source code and examples at the CSS3 transition tests github page.
Basically, CSS animations have an animationEnd event that is fired when the animation completes.
For webkit browsers this event is named “webkitAnimationEnd”. So, in order to reset an animation after it has been called you need to add an event-listener to the element for the animationEnd event.
In plain vanilla javascript:
var element = document.getElementById('box');
element.addEventListener('webkitAnimationEnd', function(){
this.style.webkitAnimationName = '';
}, false);
document.getElementById('button').onclick = function(){
element.style.webkitAnimationName = 'shake';
// you'll probably want to preventDefault here.
};
and with jQuery:
var $element = $('#box').bind('webkitAnimationEnd', function(){
this.style.webkitAnimationName = '';
});
$('#button').click(function(){
$element.css('webkitAnimationName', 'shake');
// you'll probably want to preventDefault here.
});
The source code for CSS3 transition tests (mentioned above) has the following support object which may be helpful for cross-browser CSS transitions, transforms, and animations.
Here is the support code (re-formatted):
var css3AnimationSupport = (function(){
var div = document.createElement('div'),
divStyle = div.style,
// you'll probably be better off using a `switch` instead of theses ternary ops
support = {
transition:
divStyle.MozTransition === ''? {name: 'MozTransition' , end: 'transitionend'} :
// Will ms add a prefix to the transitionend event?
(divStyle.MsTransition === ''? {name: 'MsTransition' , end: 'msTransitionend'} :
(divStyle.WebkitTransition === ''? {name: 'WebkitTransition', end: 'webkitTransitionEnd'} :
(divStyle.OTransition === ''? {name: 'OTransition' , end: 'oTransitionEnd'} :
(divStyle.transition === ''? {name: 'transition' , end: 'transitionend'} :
false)))),
transform:
divStyle.MozTransform === '' ? 'MozTransform' :
(divStyle.MsTransform === '' ? 'MsTransform' :
(divStyle.WebkitTransform === '' ? 'WebkitTransform' :
(divStyle.OTransform === '' ? 'OTransform' :
(divStyle.transform === '' ? 'transform' :
false))))
//, animation: ...
};
support.transformProp = support.transform.name.replace(/([A-Z])/g, '-$1').toLowerCase();
return support;
}());
I have not added the code to detect “animation” properties for each browser. I’ve made this answer “community wiki” and leave that to you. :-)
You have to first remove the animation, then add it again. Eg:
document.getElementById("box").style.webkitAnimationName = "";
setTimeout(function ()
{
document.getElementById("box").style.webkitAnimationName = "shake";
}, 0);
To do this without setTimeout remove the animation during onmousedown, and add it during onclick:
someElem.onmousedown = function()
{
document.getElementById("box").style.webkitAnimationName = "";
}
someElem.onclick = function()
{
document.getElementById("box").style.webkitAnimationName = "shake";
}
Following the suggestion from https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Tips, remove and then add the animation class, using requestAnimationFrame to ensure that the rendering engine processes both changes. I think this is cleaner than using setTimeout, and handles replaying an animation before the previous play has completed.
$('#shake-the-box').click(function(){
$('#box').removeClass("trigger");
window.requestAnimationFrame(function(time) {
window.requestAnimationFrame(function(time) {
$('#box').addClass("trigger");
});
});
});
http://jsfiddle.net/gcmwyr14/5/
A simple but effective alternative:
HTML:
<div id="box"></div>
<button id="shake-the-box">Shake it!</button>
css:
#box{
background: blue;
margin:30px;
height:50px;
width:50px;
position:relative;
-moz-animation:shake .2s 0 linear 1;
-webkit-animation:shake .2s 0 linear 1;
}
#box.trigger{
display:table;
}
#-webkit-keyframes shake {
0% {
left: 0;
}
25% {
left: 12px;
}
50% {
left: 0;
}
75% {
left: -12px;
}
100% {
left:0;
}
}
#-moz-keyframes shake {
0% {
left: 0;
}
25% {
left: 12px;
}
50% {
left: 0;
}
75% {
left: -12px;
}
100% {
left:0;
}
}
jQuery:
$('#shake-the-box').click(function(){
$('#box').toggleClass('trigger');
});
Demo:
http://jsfiddle.net/5832R/2/
Issues:
I don't know if it works on Firefox, because the animation doesn't seem to work there...
Clone works pretty good on paused Karaoke:
On IE11 had to force a reflow (R. Krupiński's shorter version).
$('#lyrics').text("Why does it hurt when I pee?");
changeLyrics('3s');
function changeLyrics(sec) {
str = 'lyrics '+ sec + ' linear 1';
$('#lyrics').css( 'animation', str);
$('#lyrics').css( 'animation-play-state', 'running' );
$('#lyrics').replaceWith($('#lyrics').clone(true));
}
or you can use the following:
function resetAnimation(elm) {
$('#'+elm).replaceWith($('#'+elm).clone(true));
}
Reset the value first. Use reflow to apply the change without using timeout:
function shake() {
var box = document.getElementById("box");
box.style.animationName = null;
box.offsetHeight; /* trigger reflow */
box.style.animationName = "shake";
}
#keyframes shake {
0% { left: 0; }
25% { left: 12px; }
50% { left: 0; }
75% { left: -12px; }
100% { left: 0; }
}
#box {
position: absolute;
width: 75px; height: 75px;
background-color: black;
animation-duration: .02s;
animation-iteration-count: 10;
animation-timing-function: linear;
}
button {
position: absolute;
top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>
In contrast to the accepted answer that recommends animationEnd, this method resets the animation even when it's still in progress. This might be or might be not what you want.
An alternative would be to create a duplicate #keyframes animation and switch between the two:
function shake() {
var box = document.getElementById("box");
if (box.style.animationName === "shake")
box.style.animationName = "shake2";
else
box.style.animationName = "shake";
}
#keyframes shake {
0% { left: 0; }
25% { left: 12px; }
50% { left: 0; }
75% { left: -12px; }
100% { left: 0; }
}
#keyframes shake2 {
0% { left: 0; }
25% { left: 12px; }
50% { left: 0; }
75% { left: -12px; }
100% { left: 0; }
}
#box {
position: absolute;
width: 75px; height: 75px;
background-color: black;
animation-duration: .02s;
animation-iteration-count: 10;
animation-timing-function: linear;
}
button {
position: absolute;
top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>
Is there an issue with using setTimeout() to remove the class and then read it 5ms later?
svg.classList.remove('animate');
setTimeout(function() {
svg.classList.add('animate');
}, 10);
With your javascript, you could also add (and then remove) a CSS class in which the animation is declared. See what I mean ?
#cart p.anim {
animation: demo 1s 1; // Fire once the "demo" animation which last 1s
}
1) Add animation name to the #box.trigger in css
#box.trigger{
display:table;
animation:shake .2s 0 linear 1;
-moz-animation:shake .2s 0 linear 1;
-webkit-animation:shake .2s 0 linear 1;
}
2) In java-script you cannot remove the class trigger.
3) Remove the the class name by using setTimeOut method.
$(document).ready(function(){
$('#shake-the-box').click(function(){
$('#box').addClass('trigger');
setTimeout(function(){
$("#box").removeClass("trigger")},500)
});
});
4) Here is the DEMO.