I'm simulating a bowling game in jQuery. So, I throw the ball (through animate function) and when it hits a pin I simulate it falling over (also through animate function). But I can only make it rotate. I want it to fall over in place, to the left or to the right. Like this. This is the jQuery code for the pin animation:
this.animation = function (pinID) {
var rdm = ((Math.random()*10)+1);
var degree;
if (rdm <= 5)
degree = -90;
else
degree = 90;
$(pinID).animate({ deg: degree },
{
duration: 1000,
step: function (now) {
// In the step-callback (that is fired each step of the animation),
// the pin will rotate to the current degree of the animation
$(pinID).css({
transform: 'rotate(' + now + 'deg)'
});
},
complete: function () {
// When the animation is complete, removes the pin from play
$(pinID).css({
"left": -200, "top": -200
});
}
});
}
I tried to have a left and top in the beginning of the animate function the it just simulated a weird movement.
I'd appreciate it if anyone could help me. Thanks.
EDIT Here's the result (thanks to Zs V):
this.animation = function (pinID) {
if (knockedPins.indexOf(pinID) == -1) {
var rdm = ((Math.random() * 10) + 1);
var degree;
var transFormOrigin;
if (rdm <= 5) {
degree = -90;
transFormOrigin = '0% 100%';
}
else {
degree = 90;
transFormOrigin = '100% 100%';
}
$(pinID).css({ "transform-origin": transFormOrigin });
knockedPins.push(pinID);
$(pinID).animate({ deg: degree },
{
duration: 1000,
step: function (now) {
// In the step-callback (that is fired each step of the animation),
// the pin will rotate to the current degree of the animation
$(pinID).css({
transform: 'rotate(' + now + 'deg)'
});
},
complete: function () {
// When the animation is complete, removes the pin from play
$(pinID).css({
"left": -200, "top": -200
});
}
});
}
}
I added the transform-origin property and had to make use of an array to store the ids of the pins that were already knocked, otherwise it would shake until it was put to rest. hehe
You have to rotate the object (the picture) around its corner instead of the center. Here it is a discussion how to do that: https://stackoverflow.com/a/6633676/6624619
I'm trying to rotate a fixed image in sync with fullpage.js and it works for the most part.
In order to prevent unwanted rotation I have to stack css rotate() values.
It works when I scroll down and it stacks as I wanted (ie. 180, 360, 540, ..)
It doesn't work when I scroll up.
I tried to use alerts to identify if the calculation is done, there seems to be no problem on the stacking, but scroll up portion of the code simply doesn't print to the HTML document.
Here's my code;
var rotation = 0,
rotationInc = 180,
miniLogo = $('#mini-logo');
$(document).ready(function () {
$('#home').fullpage({
verticalCentered: false,
scrollingSpeed: 300,
onLeave: function (index, nextIndex, direction) {
if (direction == 'down') {
rotation += rotationInc;
setTimeout(function () {
miniLogo.addClass('enlarge');
}, 400);
miniLogo.each(function () {
alert(rotation);
});
setTimeout(function () {
miniLogo.css({
'transform': 'rotate(' + rotation + 'deg)'
});
}, 800);
setTimeout(function () {
miniLogo.removeClass('enlarge');
}, 1200);
}
if (direction == 'up') {
rotation -= rotationInc;
setTimeout(function () {
miniLogo.addClass('enlarge');
}, 400);
miniLogo.each(function () {
alert(rotation);
});
setTimeout(function () {
miniLogo.css({
'transform': 'rotate(' + rotation + 'deg);'
});
}, 800);
setTimeout(function () {
miniLogo.removeClass('enlarge');
}, 1200);
}
}
});
});
The first if statement works perfectly. The second gives the alert I wanted but doesn't print the reduced degree on the html.
Any help would be much appreciated, I'm sure I've done a rookie mistake.
Try this :
rotation = 0;
rotationInc = 180;
miniLogo = $('#mini-logo');
$(document).ready(function () {
$('#home').fullpage({
verticalCentered: false,
scrollingSpeed: 300,
onLeave: function (index, nextIndex, direction) {
var rotation = (direction == 'down')
? rotation += rotationInc
: rotation -= rotationInc;
setTimeout(function () {
miniLogo.addClass('enlarge');
}, 400);
miniLogo.each(function () {
alert(rotation);
});
setTimeout(function () {
miniLogo.css({
'transform': 'rotate(' + rotation + 'deg)'
});
}, 800);
setTimeout(function () {
miniLogo.removeClass('enlarge');
}, 1200);
}
}
});
});
I'm trying to shake an html element for my game.
I found this code here:
shake = function (sprite, magnitude = 16, angular = false) {
//A counter to count the number of shakes
var counter = 1;
//The total number of shakes (there will be 1 shake per frame)
var numberOfShakes = 10;
//Capture the sprite's position and angle so you can
//restore them after the shaking has finished
var startX = sprite.x,
startY = sprite.y,
startAngle = sprite.rotation;
// Divide the magnitude into 10 units so that you can
// reduce the amount of shake by 10 percent each frame
var magnitudeUnit = magnitude / numberOfShakes;
//The `randomInt` helper function
var randomInt = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
//Add the sprite to the `shakingSprites` array if it
//isn't already there
if(shakingSprites.indexOf(sprite) === -1) {
//console.log("added")
shakingSprites.push(sprite);
//Add an `updateShake` method to the sprite.
//The `updateShake` method will be called each frame
//in the game loop. The shake effect type can be either
//up and down (x/y shaking) or angular (rotational shaking).
sprite.updateShake = () => {
if(angular) {
angularShake();
} else {
upAndDownShake();
}
};
}
//The `upAndDownShake` function
function upAndDownShake() {
//Shake the sprite while the `counter` is less than
//the `numberOfShakes`
if (counter < numberOfShakes) {
//Reset the sprite's position at the start of each shake
sprite.x = startX;
sprite.y = startY;
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Randomly change the sprite's position
sprite.x += randomInt(-magnitude, magnitude);
sprite.y += randomInt(-magnitude, magnitude);
//Add 1 to the counter
counter += 1;
}
//When the shaking is finished, restore the sprite to its original
//position and remove it from the `shakingSprites` array
if (counter >= numberOfShakes) {
sprite.x = startX;
sprite.y = startY;
shakingSprites.splice(shakingSprites.indexOf(sprite), 1);
}
}
//The `angularShake` function
//First set the initial tilt angle to the right (+1)
var tiltAngle = 1;
function angularShake() {
if (counter < numberOfShakes) {
//Reset the sprite's rotation
sprite.rotation = startAngle;
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Rotate the sprite left or right, depending on the direction,
//by an amount in radians that matches the magnitude
sprite.rotation = magnitude * tiltAngle;
counter += 1;
//Reverse the tilt angle so that the sprite is tilted
//in the opposite direction for the next shake
tiltAngle *= -1;
}
//When the shaking is finished, reset the sprite's angle and
//remove it from the `shakingSprites` array
if (counter >= numberOfShakes) {
sprite.rotation = startAngle;
shakingSprites.splice(shakingSprites.indexOf(sprite), 1);
//console.log("removed")
}
}
}
However it only works for canvas sprites. How can I get it to work with HTML elements? Thanks.
You can use css animation like this example
#-webkit-keyframes shake {
0% { -webkit-transform: translate(2px, 1px) rotate(0deg); }
10% { -webkit-transform: translate(-1px, -2px) rotate(-1deg); }
20% { -webkit-transform: translate(-3px, 0px) rotate(1deg); }
30% { -webkit-transform: translate(0px, 2px) rotate(0deg); }
40% { -webkit-transform: translate(1px, -1px) rotate(1deg); }
50% { -webkit-transform: translate(-1px, 2px) rotate(-1deg); }
60% { -webkit-transform: translate(-3px, 1px) rotate(0deg); }
70% { -webkit-transform: translate(2px, 1px) rotate(-1deg); }
80% { -webkit-transform: translate(-1px, -1px) rotate(1deg); }
90% { -webkit-transform: translate(2px, 2px) rotate(0deg); }
100% { -webkit-transform: translate(1px, -2px) rotate(-1deg); }
}
.shake:hover {
-webkit-animation-name: shake;
-webkit-animation-duration: 0.5s;
-webkit-transform-origin:50% 50%;
-webkit-animation-iteration-count: infinite;
}
.shake {
display:inline-block
}
<div class="shake">Shake me</div>
<img class="shake" src="https://www.w3.org/2008/site/images/logo-w3c-screen-lg" />
To change speed of shaking, change values of animation-duration, translate(), rotate().
If you want to shake element using javascript see jsfiddle
I have adapted your function so that it works on DOM elements. It is a pretty hefty shake though, you might want to play with the parameters to damped it a little bit:
var shakingElements = [];
var shake = function (element, magnitude = 16, angular = false) {
//First set the initial tilt angle to the right (+1)
var tiltAngle = 1;
//A counter to count the number of shakes
var counter = 1;
//The total number of shakes (there will be 1 shake per frame)
var numberOfShakes = 15;
//Capture the element's position and angle so you can
//restore them after the shaking has finished
var startX = 0,
startY = 0,
startAngle = 0;
// Divide the magnitude into 10 units so that you can
// reduce the amount of shake by 10 percent each frame
var magnitudeUnit = magnitude / numberOfShakes;
//The `randomInt` helper function
var randomInt = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
//Add the element to the `shakingElements` array if it
//isn't already there
if(shakingElements.indexOf(element) === -1) {
//console.log("added")
shakingElements.push(element);
//Add an `updateShake` method to the element.
//The `updateShake` method will be called each frame
//in the game loop. The shake effect type can be either
//up and down (x/y shaking) or angular (rotational shaking).
if(angular) {
angularShake();
} else {
upAndDownShake();
}
}
//The `upAndDownShake` function
function upAndDownShake() {
//Shake the element while the `counter` is less than
//the `numberOfShakes`
if (counter < numberOfShakes) {
//Reset the element's position at the start of each shake
element.style.transform = 'translate(' + startX + 'px, ' + startY + 'px)';
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Randomly change the element's position
var randomX = randomInt(-magnitude, magnitude);
var randomY = randomInt(-magnitude, magnitude);
element.style.transform = 'translate(' + randomX + 'px, ' + randomY + 'px)';
//Add 1 to the counter
counter += 1;
requestAnimationFrame(upAndDownShake);
}
//When the shaking is finished, restore the element to its original
//position and remove it from the `shakingElements` array
if (counter >= numberOfShakes) {
element.style.transform = 'translate(' + startX + ', ' + startY + ')';
shakingElements.splice(shakingElements.indexOf(element), 1);
}
}
//The `angularShake` function
function angularShake() {
if (counter < numberOfShakes) {
console.log(tiltAngle);
//Reset the element's rotation
element.style.transform = 'rotate(' + startAngle + 'deg)';
//Reduce the magnitude
magnitude -= magnitudeUnit;
//Rotate the element left or right, depending on the direction,
//by an amount in radians that matches the magnitude
var angle = Number(magnitude * tiltAngle).toFixed(2);
console.log(angle);
element.style.transform = 'rotate(' + angle + 'deg)';
counter += 1;
//Reverse the tilt angle so that the element is tilted
//in the opposite direction for the next shake
tiltAngle *= -1;
requestAnimationFrame(angularShake);
}
//When the shaking is finished, reset the element's angle and
//remove it from the `shakingElements` array
if (counter >= numberOfShakes) {
element.style.transform = 'rotate(' + startAngle + 'deg)';
shakingElements.splice(shakingElements.indexOf(element), 1);
//console.log("removed")
}
}
};
DEMO
Have a look at the demo in the fiddle. The red block is the regular upAndDownShake, whereas the green one uses angularShake:
https://jsfiddle.net/12aueufy/1/
Maybe you should take a look in Animate.css, https://daneden.github.io/animate.css/, this is a css library that provides a lot of animations, including a shake one... I hope that this might work for your problem!
function shake(e, oncomplete, distance, time) {
var time = 500;
var distance = 5;
var start = (new Date()).getTime();
animate();
function animate() {
var now = (new Date()).getTime();
// Get current time
var elapsed = now - start;
// How long since we started
var fraction = elapsed / time;
// What fraction of total time?
if (fraction < 1) {
var x = distance * Math.sin(fraction * 4 * Math.PI);
e.style.left = x + "px";
// We're aiming for a smooth 40 frames/second animation.
setTimeout(animate, Math.min(25, time - elapsed));
} else {
// Otherwise, the animation is complete
if (oncomplete) oncomplete(e);
// Invoke completion callback
}
}
}
function shakeme(event1) {
shake(event1.target);
}
document.getElementById("wood").addEventListener("mouseover", shakeme, false);
HTML Element
<button id="wood">Hello World</button>
Source
http://javascriipt.blogspot.com/2015/02/how-to-mimic-shake-animation-effect.html
You could use some library for javascript animations like Velocity
It's really flexible and easy to use.
Please check this working sample, I'm pretty sure that you can create wished effect in minutes
Hope it help
It's possible to have the animation done entirely with very simple CSS and JS. The strategy involves two things:
transition: all 500ms; — This bit of CSS means that anytime we want to do a transition (i.e., animation), that transition will complete in 500ms.
transform(rotate) — Then every CSS change takes place in 500ms, so, we can shake the icon with margin-left and margin-right, or, we can use transform(rotate), let's try the latter!
Note: You can use any type of CSS effect here, try experimenting with something else! I'm curious if there's anything better than transform(rotate).
Demo
const wiggletime = 100;
function rotateElement(el) {
el.classList.add('rotateable');
el.style.transform = 'rotate(20deg)';
setTimeout(function() {
el.style.transform = 'rotate(-20deg)';
setTimeout(function() {
el.style.transform = 'rotate(0deg)';
}, wiggletime);
}, wiggletime);
return true;
}
function squishElement(el) {
el.classList.add('rotateable');
el.style.transform = 'scaleX(1.5)';
setTimeout(function() {
el.style.transform = 'scaleX(0.5)';
setTimeout(function() {
el.style.transform = 'scaleX(1)';
}, wiggletime);
}, wiggletime);
return true;
}
function shakeElement(el) {
el.classList.add('rotateable');
el.style.marginLeft = '20px';
setTimeout(function() {
el.style.marginLeft = '-20px';
setTimeout(function() {
el.style.marginLeft = '0px';
}, wiggletime);
}, wiggletime);
return true;
}
function skewElement(el) {
el.classList.add('rotateable');
el.style.transform = 'skewX(20deg)';
setTimeout(function() {
el.style.transform = 'skewX(-20deg)';
setTimeout(function() {
el.style.transform = 'skewX(0deg)';
}, wiggletime);
}, wiggletime);
return true;
}
function borderElement(el) {
el.classList.add('rotateable');
el.style.border = '4px solid black';
el.style.marginLeft = '-4px';
el.style.marginTop = '-4px';
setTimeout(function() {
el.style.border = '2px solid black';
el.style.marginLeft = '-2px';
el.style.marginTop = '-2px';
setTimeout(function() {
el.style.border = '1px solid black';
el.style.marginLeft = '0px';
el.style.marginTop = '0px';
}, wiggletime);
}, wiggletime);
return true;
}
document.getElementById('rotate-me').addEventListener('click', function(ev) {
rotateElement(this);
});
document.getElementById('shake-me').addEventListener('click', function(ev) {
shakeElement(this);
});
document.getElementById('squish-me').addEventListener('click', function(ev) {
squishElement(this);
});
document.getElementById('skew-me').addEventListener('click', function(ev) {
skewElement(this);
});
document.getElementById('border-me').addEventListener('click', function(ev) {
borderElement(this);
});
.rotateable {
transition: all 100ms;
}
<button id="shake-me">Shake Me!</button>
<br><br>
<button id="rotate-me">Rotate Me!</button>
<br><br>
<button id="squish-me">Squish Me!</button>
<br><br>
<button id="skew-me">Skew Me!</button>
<br><br>
<button id="border-me" style="position:absolute;">Border Me!</button>
Demo - Extended
Why not extended animations?
const wiggletime = 100;
function rotateElement(el) {
el.classList.add('rotateable');
el.style.transform = 'rotate(20deg)';
setTimeout(function() {
el.style.transform = 'rotate(-20deg)';
setTimeout(function() {
el.style.transform = 'rotate(10deg)';
setTimeout(function() {
el.style.transform = 'rotate(-10deg)';
setTimeout(function() {
el.style.transform = 'rotate(0deg)';
}, wiggletime);
}, wiggletime);
}, wiggletime);
}, wiggletime);
return true;
}
function squishElement(el) {
el.classList.add('rotateable');
el.style.transform = 'scaleX(1.5)';
setTimeout(function() {
el.style.transform = 'scaleX(0.5)';
setTimeout(function() {
el.style.transform = 'scaleX(1.25)';
setTimeout(function() {
el.style.transform = 'scaleX(0.75)';
setTimeout(function() {
el.style.transform = 'scaleX(1)';
}, wiggletime);
}, wiggletime);
}, wiggletime);
}, wiggletime);
return true;
}
function skewElement(el) {
el.classList.add('rotateable');
el.style.transform = 'skewX(20deg)';
setTimeout(function() {
el.style.transform = 'skewX(-20deg)';
setTimeout(function() {
el.style.transform = 'skewX(10deg)';
setTimeout(function() {
el.style.transform = 'skewX(-10deg)';
setTimeout(function() {
el.style.transform = 'skewX(0deg)';
}, wiggletime);
}, wiggletime);
}, wiggletime);
}, wiggletime);
return true;
}
function shakeElement(el) {
el.classList.add('rotateable');
el.style.marginLeft = '20px';
setTimeout(function() {
el.style.marginLeft = '-20px';
setTimeout(function() {
el.style.marginLeft = '10px';
setTimeout(function() {
el.style.marginLeft = '-10px';
setTimeout(function() {
el.style.marginLeft = '0px';
}, wiggletime);
}, wiggletime);
}, wiggletime);
}, wiggletime);
return true;
}
document.getElementById('rotate-me').addEventListener('click', function(ev) {
rotateElement(this);
});
document.getElementById('shake-me').addEventListener('click', function(ev) {
shakeElement(this);
});
document.getElementById('squish-me').addEventListener('click', function(ev) {
squishElement(this);
});
document.getElementById('skew-me').addEventListener('click', function(ev) {
skewElement(this);
});
.rotateable {
transition: all 100ms;
}
<button id="shake-me">Shake Me!</button>
<br><br>
<button id="rotate-me">Rotate Me!</button>
<br><br>
<button id="squish-me">Squish Me!</button>
<br><br>
<button id="skew-me">Skew Me!</button>
I have a jQuery function that loops. What I want to do is for the $bird_wing_left element to rotate 30 degrees and then rotate back to 0 degree (in an infinite loop).
$(document).ready(function() {
var rotate = 0;
setInterval(function(){
rotate = 30;
$bird_wing_left.css({ transform: "rotate(" + rotate + "deg)" }).delay(1000).queue(function(){
rotate = 0;
$(this).css({ transform: "rotate(" + rotate + "deg)" });
});
}, 3000);
});
The first time it did rotate 30 degrees, then to 0 degrees, then to 30 degrees. However, afterwards, it seems to ignore the callback (which resets the degree value to 0), hence, it just keeps on being at 30 degrees on and on.
What could be the issue?
This is the jsFiddle: https://jsfiddle.net/iamacatperson/86z26hdw/
When you queue a function, within the function you have to dequeue (or call "next", more below) to allow the queue to continue processing (as shown in the examples). Just add $(this).dequeue() within your queue callback:
var $bird_wing_left = $("#wing");
$(document).ready(function() {
var rotate = 0;
setInterval(function() {
rotate = rotate + 30;
$bird_wing_left.css({
transform: "rotate(" + rotate + "deg)"
}).delay(1000).queue(function() {
rotate = rotate - 30;
$(this).css({
transform: "rotate(" + rotate + "deg)"
}).dequeue(); // <====================
});
}, 3000);
});
body {
padding-top: 2em;
}
<div id="wing" style="width: 10em">Bird wing</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Alternately, since jQuery 1.4 the queue callback has been given an argument (traditionally called next) it can call to keep the queue going:
var $bird_wing_left = $("#wing");
$(document).ready(function() {
var rotate = 0;
setInterval(function() {
rotate = rotate + 30;
$bird_wing_left.css({
transform: "rotate(" + rotate + "deg)"
}).delay(1000).queue(function(next) { // <=====
rotate = rotate - 30;
$(this).css({
transform: "rotate(" + rotate + "deg)"
});
next(); // <=====
});
}, 3000);
});
body {
padding-top: 2em;
}
<div id="wing" style="width: 10em">Bird wing</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Side note: You can use += and -= if you like, e.g. rotate += 30; and rotate -= 30;
Quick fix could be to check rotate variable value before setting it.
if(rotate == 0)
rotate = rotate + 30;
else
rotate = 0;
How could I do clearTimeout if I have multiple settimeout?
Here I have a code:
var $elie = $(".gear"), degree = 0, timer;
function rotate() {
$elie.css({ WebkitTransform: 'rotate(' + degree + 'deg)'});
$elie.css({ '-moz-transform': 'rotate(' + degree + 'deg)'});
$elie.css({ 'transform': 'rotate(' + degree + 'deg)'});
timer = setTimeout(function() {
++degree; rotate();
$('.gear').attr('timeout',timer);
},25);
}
$(".google").hover(function() {
clearTimeout($('.gear').attr('timeout'));
});
$(".gear").hover(function() {
rotate();
});
That is: http://jsfiddle.net/T9YxL/1/
The problem is: I hover on the gear once, than hover on Google logo — everything stops as it has. But when I hover on the gear twice, I have to hover on Google logo twice and so on. How to clear all these settimeout at once even for example I hovered on the gear 100 times?
I looked here:
clearTimeout on multiple setTimeout
but it didn't help.
timer = setTimeout(function() {
++degree; rotate();
$('.gear').attr('timeout',timer);
},25);
should be
timer = setTimeout(function() {
++degree; rotate();
},25);
$('.gear').attr('timeout',timer);
and :
$(".gear").hover(function() {
rotate();
});
should be
$(".gear").hover(function() {
clearTimeout($('.gear').attr('timeout'));
rotate();
});
fiddle