Animating with parameters in Javascript using a timer - javascript

I'm trying to animate a dot from one point to another on a map. Right now I have the following code:
function animate(){
//animation
var pt = oldLoc;
for(i = 0; i < 1000; i++){
pt.y += 5
pt.x += 5
graphic.setGeometry(pt); //sets the new point coordinates
graphic.show(); //redraws the display
dojo.byId("info").innerHTML += "testingcheck"; //print check
}
}
When I run the code right now, the dot does move, but it "jumps" from the beginning location to the final location. It seems like the show() doesn't execute until the entire loop has been run through.
I know I need something that looks like setTimeOut(animate(), 20), but I don't know how to incorporate it into my code (do I make a new function?) and how to specify when to stop the animation. Any insight would be much appreciated. Thanks in advance!

You could also easily replace your for loop for a setInterval call, e.g.:
function animate(){
var pt = oldLoc, i = 0, timer; // no global variables declared...
timer = setInterval(function () {
pt.y += 5;
pt.x += 5;
graphic.setGeometry(pt);
graphic.show();
dojo.byId("info").innerHTML += "testingcheck";
if (i >= 1000) { // stop condition
clearInterval(timer);
}
i++;
}, 100);
}

You are using dojo, so why not using it also for animation ?
Suppose your point is a floating div with an absolute positioning, which id is "point", you could do :
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.4.0/dojo/dojo.xd.js" djConfig="parseOnLoad: true, isDebug: true"></script>
<script type="text/javascript">
function moveNodeByXY(movingNode, shiftX, shiftY) {
var startPos = dojo.position(movingNode);
var endX = startPos.x + shiftX;
var endY = startPos.y + shiftY;
console.debug("Point moving from (" + startPos.x + ", " + startPos.y + ") to (" + endX + ", " + endY + ")");
dojo.fx.slideTo({ node: movingNode, left:endX, top:endY, units:"px" }).play()
}
dojo.addOnLoad(function() {
dojo.require("dojo.fx");
});
</script>
<style type="text/css">
#point {
position : absolute;
z-index : 1000;
height : 10px;
width : 10px;
left : 50px;
top : 50px;
background-color : #3C3C3C;
}
</style>
</head>
<body>
<div id="point" onClick="moveNodeByXY(this, 5, 5);"></div>
</body>
</html>

dojo.require("dojox.fx._Line"); // multidimensional curve support
dojo.ready(function(){
new dojo.Animation({
curve: new dojox.fx._Line([ [startx, endx], [starty, endy] ]),
onAnimate:function(currentx, currenty){
graphic.setGeometry({ x: currentx, y: currenty });
graphic.show();
},
duration:1000,
rate:10 // framerate, aka: setInterval(..., rate)
}).play();
});

Something along the lines of:
function animate(){
....;
}
var timer = setInterval(animate, 50);
//To stop
clearInterval(timer);
Ideally you want to measure the real time which has passed between the animate calls and move the object taking in account that time. But this should be a start. JavaScript timers are little bit tricky, intervals aren't that accurate in JavaScript.
Two good links to get you started:
One
Two
And here's a good starting tutorial on the topic.

Something like
var currentPoint = oldLoc;
var i = 0;
function animate()
{
i++;
if ( i >= 1000 )
{
i = 0;
clearInterval ( timeOutId );
}
else
{
currentPoint.y += 5;
currentPoint.x += 5
graphic.setGeometry(currentPoint); //sets the new point coordinates
graphic.show(); //redraws the display
dojo.byId("info").innerHTML += "testingcheck"; //print check
}
}
var timeOutId = setInterval(animate, 20);

Related

Paperjs bounce animation

Theres some wierd behaviour when playing with Paperjs, i was trying to curve a line up with 7 points separately - which works fine once, but when trying to make the link overshoot and return to 3 different points (to create a bounce effect) doesn't seem to play ball. On the second if statement, the 'counter' variable doesnt seem to increase instead of decrease, '+ steps' instead of '- steps'.
Maybe i'm not using if statements properly in this case, or paperjs has some strange behaviour?
Heres the codepen for it in full, click above the blue line to trigger it off. . Following is one setInterval for one of the points of the segment.
var seg6first = true;
var seg6sec = false;
var seg6thir = false;
setInterval(function() {
if (seg6first == true) {
counter = counter - steps;
if (counter >= 230) {
path.segments[6].point.y = counter;
path.smooth(); }
else {
seg6first = false;
seg6sec = true;
}
}
if (seg6sec == true) {
counter = counter + steps;
if (counter <= 260) {
path.segments[6].point.y = counter;
path.smooth();}
else {
seg6sec = false;
seg6thir = true;
}
}
if (seg6sec == true) {
counter = counter - steps;
if (counter >= 250) {
path.segments[6].point.y = counter;
path.smooth(); }
else {
seg6thir = false;
}
}
}, mintiming);
Thanks!
Rather than manually building your bounce effect, you can use an animation library like GSAP.
It has a lot of features that will make your task easier (see easing documentation).
Here is an example of what you are trying to do (click on the canvas to animate the line).
html,
body {
margin: 0;
overflow: hidden;
height: 100%;
}
canvas[resize] {
width: 100%;
height: 100%;
}
<canvas id="canvas" resize></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.11.8/paper-full.min.js"></script>
<script type="text/paperscript" canvas="canvas">
// user defined constants
var SEGMENTS_COUNT = 6;
var CURVE_HEIGHT = 80;
var ANIMATION_DURATION = 2;
// init path
var path = new Path({
fillColor: 'orange',
selected: true
});
// add points
for (var i = 0; i <= SEGMENTS_COUNT; i++) {
path.add([view.bounds.width * i / SEGMENTS_COUNT, view.center.y]);
}
// on mouse down...
function onMouseDown() {
// ...animate points
for (var i = 0, l = path.segments.length; i < l; i++) {
// get a reference to the point
var point = path.segments[i].point;
// calculate offset using sine function to form a curve
var offset = CURVE_HEIGHT * Math.sin(point.x * Math.PI / view.bounds.width);
// register animation
TweenLite.fromTo(
// target
point,
// duration
ANIMATION_DURATION,
// initial value
{ y: view.center.y },
{
// final value
y: view.center.y - offset,
// easing
ease: Elastic.easeOut.config(1, 0.3),
// on update...
onUpdate: function() {
// ...smooth the path
path.smooth();
}
}
);
}
}
</script>

Using animate.css (link in description) how do I trigger an animation when a particular event is finished

I have an an image moving across the screen and out of viewport, when the image reaches a particular absolute position (right: - 200), I want to trigger the below animation. I am relatively new to programming, not sure how to track when a particular function is done so that I can trigger the below animation.
var $startLessonButton = $('.startLessonButtonUp');
$startLessonButton.mouseup(function() {
$(this).addClass('animated slideInLeft');
});
---------
var movingOutAnimationCounter = 2;
var movingOutCurrentPosition = window.innerWidth / 2 - 200
function moveTrumpOut() {
movingOutCurrentPosition -= 2;
trumpyWrapper.style.right = movingOutCurrentPosition + 'px';
if (movingOutAnimationCounter < 9 ) {
trumpy.src = '../images/trump_walking_out_' + movingOutAnimationCounter + '.png';
movingOutAnimationCounter += 1;
} else {
movingOutAnimationCounter = 1;
trumpy.src = '../images/trump_walking_out_' + movingOutAnimationCounter + '.png';
}
if (movingOutCurrentPosition > -200 ) {
requestAnimationFrame(moveTrumpOut);
}
}
All the best!
If you know time, when moving element is hidden, you can use this function:
setTimeout(function(){ $('.elem').addClass("animCssClass") }, 1000);
Last parameter, in this example: 1000 is time in ms, when function inside should execute. Run this function on mouseup when you adding class to moving element.

JS : Using a setTimeout inside a setInterval, the setTimeout has no effect

I'm trying to make random images move upwards then return to their original position.
<script>
var looper = setInterval(animateAll, 2000, myArray);
function animateAll(myArray) {
// Gets a random image ID
var randomId = myArray[Math.floor(Math.random()*myArray.length)];
// Make that random icon bounce
bounce(randomId) ;
}
function bounce(randomId) {
var icon = document.getElementById(randomId)
var top = icon.offsetTop;
setTimeout ( icon.style.top = top-20 + "px", 500) ;
setTimeout ( icon.style.top = top + "px", 500) ;
}
</script>
Both setTimeout lines work fine. With only one line, well the images will move without returning to their original position. With both lines, images don't move at all, probably because there's no delay between each.
Thanks for your help !
The problem is that you're executing the code in your setTimeout calls immediately. You're effectively saying "execute the result of setting the icon.style.top = whatever in 500 milliseconds" ... which does nothing.
Try this instead:
icon.style.top = top-20 + "px";
setTimeout ( function() { icon.style.top = top + "px"; }, 500) ;
... and I just blew 15 minutes on this, lol:
var steps = 7;
var increment = (Math.PI) / steps;
var bounceHeight = 20;
function doStep(icon, start, major, minor, height) {
if (minor == steps) {
major--;
height /= 2;
minor = 0;
icon.style.top = start;
}
if (major < 0) {
return;
}
if (minor < steps) {
pos = Math.sin((minor + 1) * increment);
icon.style.top = (start - height * pos) + "px";
setTimeout( function() { doStep(icon, start, major, minor + 1, height); }, 500/steps );
}
}
function bounce(randomId) {
var icon = document.getElementById(randomId)
var top = icon.offsetTop;
setTimeout ( function() { doStep(icon, top, 3, 0, bounceHeight); }, 500/steps ) ;
}
How about moving the image up immediately when you call bounce and then returning it to the original position after a timeout?
function bounce(randomId) {
var icon = document.getElementById(randomId)
var top = icon.offsetTop;
icon.style.top = top-20 + "px";
setTimeout ( icon.style.top = top + "px", 500) ;
}

Move each character of a div based on mouse movement

I'm developing a site and I don't know how to create a javascript animation that looks like this:
I have a div that have some text on it, and when the user moves his mouse over this text, I want each character to move independently of each other, in order to maintain a certain distance from it (the mouse). Also, I want this animation to have rotation, but it isn't that important now. Here's an image explanation:
Here's what I did so far:
HTML:
<div class="div1">Hello World</div>
Javascript:
var chars = $(".div1").html().split('');
$(".div1").empty();
for(var i = 0; i < chars.length; i++){
$(".div1").append("<span class='letter'>"+chars[i]+"</span>");
}
JSFiddle
Can someone help me to achieve this effect? I don't know how to proceed and there's no site or answer that helped me. You can use jQuery or pure JavaScript but, please, keep it simple! Thank you.
Oh here we go, I've found a solution for this.
What I did was using a different class name for each character (.letter + character number) and then created a way of moving the characters depending on the mouse position and distance compared to each character, so, for example, when the distance between the mouse and a character is less than X, and the mouse Y is less than the character Y, then the character will go down.
Thanks to adeneo and Derek
Here's the relevant code:
JavaScript:
var chars = $(".div1").html().split('');
$(".div1").empty();
for (var i = 0; i < chars.length; i++) {
$(".div1").append("<span class='letter" + i + "'>" + chars[i] + "</span>");
$(".letter" + i).css({
"position":"relative",
});
$(".letter" + i).css({
"transition": "0.5s"
});
}
$(document).on("mousemove", function (e) {
for (var i = 0; i < chars.length; i++) {
var x = e.pageX,
y = e.pageY;
var distx = x - $(".letter" + i).offset().left + ($(".letter" + i).width() / 2);
var disty = y - $(".letter" + i).offset().top;
if (Math.abs(distx) < 24 && Math.abs(disty) < 24) {
if (distx > 6 || distx < -6) {
if (x < $(".letter" + i).offset().left) {
$(".letter" + i).css({
"left": + (24 / Math.abs(distx) * Math.abs(distx)),
"position": "relative"
});
} else {
$(".letter" + i).css({
"left": - (24 / Math.abs(distx) * Math.abs(distx)),
"position": "relative"
});
}
}
if (disty > 12 || disty < -12) {
if (y < $(".letter" + i).offset().top + 6) {
$(".letter" + i).css({
"top": + (24 / Math.abs(disty) * Math.abs(disty)),
"position": "relative"
});
} else {
$(".letter" + i).css({
"top": - (24 / Math.abs(disty) * Math.abs(disty)),
"position": "relative"
});
}
}
}
distx = 0;
disty = 0;
}
});
HTML:
<div class="div1">Hello World</div>
Updated JSFiddle with CSS Transitions to improve smoothness
Well since you say yo want to learn, i'll give a code to help you out, but you have to work your way through, i haven't test it, i just wrote it blindly so it propably won't work but might give you a good idea of what must be done.
Html:
<div class="container">
<div id="coolDiv" class="scatterContainer">Hello World</div>
</div>
Css:
*{margin:0;}
span:hover{
color:#0CF;
}
.scatterContainer{
display: inline;
}
.container {
margin: 30px auto;
}
Javascript
LetterScatterer = (function() {
function LetterScatterer(id) {
this.id = id
this.$el = $('#' + this.id);
this.rangeOfaction = 3; // Number of characters to affect
this.maxVerticalMovement = 10; // Value in px
this.minVerticalMovement = 2
this.duration = 100; // In miliseconds
// Event Listeners
this.$el.on(mousemove((function(_this){
return function(e){
var x = e.pageX;
var y = e.pageY;
return _this.scatter(x, y);
}
})(this));
}
LetterScatterer.prototype.splitCharacters = function() {
var nodes = [];
var nodesQ = 0;
var _this = this;
this.chars = $el.text().split('');
$el.empty();
for(var i = 0; i < chars.length; i++){
var markup = "<span class='letter'>"+chars[i]+"</span>";
nodes.push(markup);
}
this.$nodes = $(nodes);
this.nodesWidth = [];
this.$nodes.each(function(){
var width = $(this).outerWidth();
_this.nodesWidth.push(width);
});
$el.append(this.$nodes);
}
LetterScatterer.prototype.scatter = function(x, y) {
var epicenter;
var offset = 0;
var midPoint, farestLeft;
for(var i = 0, len = this.nodesWidth.length; i < len; i++){
offset += this.nodesWidth[i];
if(x <= offset){
epicenter = i;
break;
}
}
leftRange = (this.rangeOfaction - 1) / 2; // We remove one, this is our epicenter, then we get left and right halves
farestLeft = epicenter - leftRange;
for(var i = farestLeft; i < this.rangeOfaction; i++){
this.animateY($node[i]);
}
}
LetterScatterer.prototype.animateY = function(node, verticalDisplacement) {
var $node = $(node);
$node.animate({margin-top: verticalDisplacement + 'px'}, this.duration);
}
return LetterScatterer;
})();
letterScatterer = new LetterScatterer('coolDiv');
What you see in the code is a classlike function, first you pass it the id of the element containing the text that will be scattered. There are some config varaibles, range of action is lets say, if you mouse over one character, how many characters to the left and to the right (also including the current hovered element) should be animated, the max and min verticalMovement, determines how much should move the one that is hovered (max) and those further apart will use min, those in between should interpolate, but i didn't code that far.
We then got a mousemove listener, that calls the method scatter, this method finds which items is currently hovered by adding up each character widht, but now i think about it, it should be easier to just add a listener to the span, and get the current index of that element with the jQuery method index(), then based on that index you animate that one and those in the range. You must create the code that calculates the rotation, and x movement if you want to, but i think i gave you a lot to start, it took me a while to code it, so i hope it helps and this answer satisfies your question. :)

displaying sprites after Collision detection

So when I shoot the enemies they get wiped from the screen, this works.
However what I want to happen is I want to place an explosion (4 pngs one after another)
basically where the enemy was. The code for the explosion works on its own but im stuck trying to integrate it with my code.
Here is the explosion class, as you can see I am having some trouble with the interval as I have no experience with them. I think the error or wrong logic lies in this object.
Also for some reason it wipes the other canvas layers :/
Try it here: http://www.taffatech.com/DarkOrbit.html
function Explosion()
{
this.srcX = 0;
this.srcY = 1250;
this.drawX = 0;
this.drawY = 0;
this.width = 70;
this.height = 70;
this.currentFrame =0;
this.totalFrames =5;
this.hasHit = false;
}
Explosion.prototype.draw = function() //makes it last 10 frames using total frames
{
if(this.currentFrame <= this.totalFrames)
{
this.currentFrame++;
Exploder(this.drawX,this.drawY);
}
else
{
this.hasHit = false;
currentFrame =0;
}
}
function Exploder(srcX,srcY)
{
whereX = this.srcX;
whereY = this.srcY;
intervalT = setInterval(BulletExplosionAnimate, 80);
}
var bulletExplosionStart = 0;
var whereX =0;
var whereY =0;
function BulletExplosionAnimate(intervalT)
{
var wide = 70;
var high = 70;
if (bulletExplosionStart > 308)
{
bulletExplosionStart = 0;
clearInterval(intervalT);
}
else
{
ctxExplosion.clearRect(0,0,canvasWidth,canvasHeight)
ctxExplosion.drawImage(spriteImage,bulletExplosionStart,1250,wide,high,whereX,whereY,wide,high);
bulletExplosionStart += 77;
}
}
my Bullet object:
function Bullet() //space weapon uses this
{
this.srcX = 0;
this.srcY = 1240;
this.drawX = -20;
this.drawY = 0;
this.width = 11;
this.height = 4;
this.bulletSpeed = 10;
this.bulletReset = -20;
this.explosion = new Explosion();
}
Bullet.prototype.draw = function()
{
this.drawX += this.bulletSpeed;
ctxPlayer.drawImage(spriteImage,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
this.checkHitEnemy();
if (this.drawX > canvasWidth)
{
this.recycle();
}
}
Bullet.prototype.fire = function(startX, startY)
{
this.drawX = startX;
this.drawY = startY;
}
Bullet.prototype.checkHitEnemy = function()
{
for(var i = 0; i < enemies.length; i++)
{
if( this.drawX >= enemies[i].drawX && this.drawX <= enemies[i].drawX + enemies[i].enemyWidth && this.drawY >= enemies[i].drawY && this.drawY <= enemies[i].drawY + enemies[i].enemyHeight)
{
this.explosion.drawX = enemies[i].drawX - (this.explosion.width/2);
this.explosion.drawY = enemies[i].drawY;
this.explosion.hasHit = true;
this.recycle(); //bullet resets after hit enemy
enemies[i].recycleEnemy(); //change this soon to have if loop if health is down
}
}
}
Bullet.prototype.recycle = function()
{
this.drawX = this.bulletReset;
}
In my player object I have a function that checks if it has hit an enemy, it works:
Player.prototype.drawAllBullets = function()
{
for(var i = 0; i < this.bullets.length; i++)
{
if(this.bullets[i].drawX >= 0)
{
this.bullets[i].draw();
}
if(this.bullets[i].explosion.hasHit)
{
this.bullets[i].explosion.draw();
}
}
}
Currently when I shoot an enemy they disappear but not explosion happens, I know my interval is not great coding, so I need some help with it, thanks!
Playing a spritesheet in canvas
It’s becoming best practice to use requestAnimationFrame to do your animations. It does some nice event grouping and performance enhancing. Here’s a good post on requestAnimationFrame: http://creativejs.com/resources/requestanimationframe/
This is how you can use requestAnimationFrame to play a spritesheet:
In this case, it’s a 4x4 spritesheet that will play over 1 second:
var fps = 16;
function explode() {
// are we done? ... if so, we're outta here
if(spriteIndex>15){return;}
// It's good practice to use requestAnimation frame
// We wrap it in setTimeout because we want timed frames
setTimeout(function() {
// queue up the next frame
requestAnimFrame(explode);
// Draw the current frame
var x=spriteIndex%(cols-1)*width;
var y=parseInt(spriteIndex/(rows-1))*height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(sheet,x,y,width,height,0,0,width,height);
// increment the sprite counter
spriteIndex++;
}, 1000 / fps);
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/nSGyx/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// This is Paul Irish's great cross browser shim for requestAnimationFrame
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
// define the spritesheet
var spriteIndex=0;
var width=64;
var height=64;
var rows=4;
var cols=4;
// load the sheet image
var sheet=document.createElement("img");
sheet.onload=function(){
canvas.width=width;
canvas.height=height;
// call the animation
explode();
}
sheet.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/explodeSprite.png";
var fps = 16;
function explode() {
// are we done? ... if so, we're outta here
if(spriteIndex>15){return;}
// It's good practice to use requestAnimation frame
// We wrap it in setTimeout because we want timed frames
setTimeout(function() {
// queue up the next frame
requestAnimFrame(explode);
// Draw the current frame
var x=spriteIndex%(cols-1)*width;
var y=parseInt(spriteIndex/(rows-1))*height;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(sheet,x,y,width,height,0,0,width,height);
// increment the sprite counter
spriteIndex++;
}, 1000 / fps);
}
$("#explode").click(function(){ spriteIndex=0; explode(); });
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=64 height=64></canvas><br>
<button id="explode">Explode</button>
</body>
</html>
.
.
.
[Edited to show more details of how animation fits into your code]
This is a recoding of your explosion functions.
Declare your explosion related variables outside the functions:
var bulletExplosionStart;
var whereX =0;
var whereY =0;
var wide = 70;
var high = 70;
Next, in Exploder(), set where the explosion will occur and reset the sprite index (bulletExplosionStart) to 0
Possible error: Check your Exploder function: you supply srcX,srcY but then do whereX=this.srcX, whereY=this.srcY. I assume you meant to use the srcX,srcY supplied as arguments to Exploder() instead of this.srcX,this.srcY.
function Exploder(srcX,srcY)
{
whereX = srcX;
whereY = srcY;
bulletExplosionStart=0;
BulletExplosionAnimate();
}
This is the recoded bulletExplosionAnimate function that plays the 4 frames of the spritesheet.
After 4 frames this animation automatically stops.
var fps = 2;
function bulletExplosionAnimate() {
// are we done? ... if so, we're outta here
if(bulletExplosionStart>308){return;}
// It's good practice to use requestAnimation frame
// We wrap it in setTimeout because we want timed frames
setTimeout(function() {
// queue up the next frame
requestAnimFrame(bulletExplosionAnimate);
// Draw the current frame
ctxExplosion.clearRect(0,0,canvasWidth,canvasHeight)
ctxExplosion.drawImage(spriteImage,
bulletExplosionStart,1250,wide,high,
whereX,whereY,wide,high);
// increment the sprite position
bulletExplosionStart += 77;
}, 1000 / fps);
}

Categories

Resources