I have problem with this sprite animation.
sprite-sheet
The script don't change the correct animation, and the speed increases each time you click in the same direction.
<div id="coordinates">MOUSE XY</div>
<div id="map" style="width:960px; height:80px; background-color:black; ">
<div id="player"></div>
</div>
Javascript and Jquery
<style> #player{background-image:url('girl_60x60.png');
width:60px; height:60px; position:relative;
z-index:12; left:465px;}</style>
<script type="text/javascript">
// click event
$('#map').click(function(e) {
// take coordinates
var posX = e.pageX ;
var posY = e.pageY;
//print X e Y
$('#coordinates').html("X: " + posX + " Y: " + posY);
if (posX <= 480) { //Check the click relative to the center.
setInterval('ani_left()',100); //left animation
} else {
setInterval('ani_right()',100); //right animation
}
});
var frame = 1;
// Right animation
function ani_right() {
var left = 60 * frame; //next frame every 60px
var top = 0;
$('#player').css('backgroundPosition','-'+left+'px -'+top+'px');
frame++;
}
// left animation
function ani_left() {
var left = 60 * frame;
var top = 60; //second row of frames
$('#player').css('backgroundPosition','-'+left+'px -'+top+'px');
frame++;
}
</script>
You should stop the execution of previous setInterval with clearInterval(idInterval).
I reccomend you to use setInterval(funcName,100) and not setInterval('funcName()',100);
var idInt = -1; // add this
// click event
$('#map').click(function(e) {
if(idInt != -1)
clearInterval(idInt); // add this
/* .. CUT .. */
if (posX <= 480) { //Check the click relative to the center.
idInt = setInterval(ani_left,100); //left animation
} else {
idInt = setInterval(ani_right,100); //right animation
}
});
/* cut */
Fiddle here
You have to clear your old draw interval before you start a new one
var interval;
if (posX <= 480) { //Check the click relative to the center.
clearInterval(interval);
interval = 0;
interval = setInterval(ani_left,100); //left animation
} else {
clearInterval(interval);
interval = 0;
interval = setInterval(ani_right,100); //right animation
}
Related
I want to create the effect similar to the old mouse trails where the div is delayed but follows the cursor.
I have come reasonably close by using set interval to trigger an animation to the coordinates of the cursor.
$("body").mousemove(function (e) {
if (enableHandler) {
handleMouseMove(e);
enableHandler = false;
}
});
timer = window.setInterval(function(){
enableHandler = true;
}, 250);
function handleMouseMove(e) {
var x = e.pageX,
y = e.pageY;
$("#cube").animate({
left: x,
top: y
}, 200);
}
JSFiddle
There are two problems that remain now:
The 'chasing' div is very jumpy (because of the required use of set interval)
If the mouse move stops before the animation is triggered, the div is left in place, away from the cursor.
I did it slightly differently. Instead of using setInterval (or even setTimeout) - I just made the animation take x amount of milliseconds to complete. The longer the animation, the less responsive the following div will seem to be.
The only problem I notice is that it gets backed up if the mouse is moved a lot.
$(document).ready(function () {
$("body").mousemove(function (e) {
handleMouseMove(e);
});
function handleMouseMove(event) {
var x = event.pageX;
var y = event.pageY;
$("#cube").animate({
left: x,
top: y
}, 1);
}
});
https://jsfiddle.net/jvmravoz/1/
Remove SetInterval and add a $("#cube").stop(); to stop the old animation based on old (x,y) so you can start a new "faster" one.
$(document).ready(function() {
$("body").mousemove(function (e) {
$("#cube").stop();
handleMouseMove(e);
});
function handleMouseMove(event) {
var x = event.pageX,
y = event.pageY;
$("#cube").animate({
left: x,
top: y
}, 50);
}
});
Working example
https://jsfiddle.net/jabnxgp7/
Super late to the game here but I didn't really like any of the options for adding a delay here since they follow the mouse's previous position instead of moving towards the mouse. So I heavily modified the code from Mike Willis to get this -
$(document).ready(function () {
$("body").mousemove(function (e) {
mouseMoveHandler(e);
});
var currentMousePos = { x: -1, y: -1 };
function mouseMoveHandler(event) {
currentMousePos.x = event.pageX;
currentMousePos.y = event.pageY;
}
mouseMover = setInterval(positionUpdate, 15);
function positionUpdate() {
var x_cursor = currentMousePos.x;
var y_cursor = currentMousePos.y;
var position = $("#cube").offset();
var x_box = position.left;
var y_box = position.top;
$("#cube").animate({
left: x_box+0.1*(x_cursor-x_box),
top: y_box+0.1*(y_cursor-y_box)
}, 1, "linear");
}
});
-----------------------------------------------------------------------
body { overflow:hidden; position:absolute; height:100%; width:100%; background:#efefef; }
#cube {
height:18px;
width:18px;
margin-top:-9px;
margin-left:-9px;
background:red;
position:absolute;
top:50%;
left:50%;
}
.circleBase {
border-radius: 50%;
}
.roundCursor {
width: 20px;
height: 20px;
background: red;
border: 0px solid #000;
}
https://jsfiddle.net/rbd1p2s7/3/
It saves the cursor position every time it moves and at a fixed interval, it updates the div position by a fraction of the difference between it and the latest cursor position. I also changed it to a circle since the circle looked nicer.
One concern here is that it triggers very often and could slow down a weak machine, reducing the update frequency makes the cursor jump more than I'd like, but maybe there's some middle ground between update frequency and jumpiness to be found, or using animation methods I'm not familiar with to automate the movement.
Here is a solution that might mimic the mouse-trail a bit more because it is only remembering the last 100 positions and discarding older ones which kind of sets the length of the mouse trail.
https://jsfiddle.net/acmvhgzm/6/
$(document).ready(function() {
var pos = new Array();
$("body").mousemove(function (e) {
handleMouseMove(e);
});
timer = window.setInterval(function() {
if (pos.length > 0) {
$('#cube').animate(pos.shift(),15);
}
}, 20);
function handleMouseMove(event) {
var x = event.pageX,
y = event.pageY;
if (pos.length = 100) {
pos.shift();
}
pos.push({'left':x, 'top':y});
}
});
Old mouse-trail feature used a list of several windows shaped like cursors which updated their positions with every frame. Basically, it had a list of "cursors" and every frame next "cursor" in list was being moved to current cursor position, achieving effect of having every fake cursor update its own position with a delay of fake cursors - 1 frames.
Smooth, on-demand delayed movement for a single object can be simulated using requestAnimationFrame, performance.now and Event.timeStamp. Idea is to hold mouse events in internal list and use them only after specific time passed after their creation.
function DelayLine(delay, action){
capacity = Math.round(delay / 1000 * 200);
this.ring = new Array(capacity);
this.delay = delay;
this.action = action;
this._s = 0;
this._e = 0;
this._raf = null;
this._af = this._animationFrame.bind(this);
this._capacity = capacity;
}
DelayLine.prototype.put = function(value){
this.ring[this._e++] = value;
if (this._e >= this._capacity) this._e = 0;
if (this._e == this._s) this._get();
cancelAnimationFrame(this._raf);
this._raf = requestAnimationFrame(this._af);
}
DelayLine.prototype._get = function(){
var value = this.ring[this._s++];
if (this._s == this._capacity) this._s = 0;
return value;
}
DelayLine.prototype._peek = function(){
return this.ring[this._s];
}
DelayLine.prototype._animationFrame = function(){
if (this._length > 0){
if (performance.now() - this._peek().timeStamp > this.delay)
this.action(this._get());
this._raf = requestAnimationFrame(this._af);
}
}
Object.defineProperty(DelayLine.prototype, "_length", {
get: function() {
var size = this._e - this._s;
return size >= 0 ? size : size + this._capacity;
}
});
var delayLine = new DelayLine(100, function(e){
pointer.style.left = e.x - pointer.offsetWidth/2 + "px";
pointer.style.top = e.y - pointer.offsetHeight/2 + "px";
});
document.addEventListener("mousemove", function(e){
delayLine.put(e);
}, false);
https://jsfiddle.net/os8r7c20/2/
Try removing setInterval , using .css() , css transition
$(document).ready(function () {
var cube = $("#cube");
$("body").mousemove(function (e) {
handleMouseMove(e);
});
function handleMouseMove(event) {
var x = event.pageX,
y = event.pageY;
cube.css({
left: x + cube.width() / 2 + "px",
top: y + cube.height() / 2 + "px"
}).parents("body").mousemove()
}
});
body {
overflow:hidden;
position:absolute;
height:100%;
width:100%;
background:#efefef;
}
#cube {
height:50px;
width:50px;
margin-top:-25px;
margin-left:-25px;
background:red;
position:absolute;
top:50%;
left:50%;
transition:all 1.5s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
<div id="cube"></div>
</div>
How do I run a sprite animation when pressing the left or right arrow keys in JavaScript? Here's my code:
var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;
window.addEventListener('keydown', KeyDown);
function setUpGame() { //This is the function that is called from the html document.
gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
context=gameCanvas.getContext("2d");
context.font = "18px Iceland";
context.textBaseline = "top";
avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
avatarImage.onload=function(){
// avatarImage is now fully loaded and ready to drawImage
context.drawImage(avatarImage, Math.random() * 100, avatarY);
// start the timer
tt = setInterval(function(){counTer()},1000);
setInterval(handleTick, 25);
}
avatarImage.addEventListener('load', startLoop, false);
avatarImage.src = "img/ships.png"; //Ditto from above.
}
function startLoop() {
console.log("Detecting whether moving to the right is: " + moving);
if(moving == 0) {
gameLoop();
}
}
function gameLoop() {
setTimeout(gameLoop, 100);
handleTick();
}
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 0;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 1;
}
break;
}
}
function counTer() {
if(counter == 60) {
clearInterval(tt);
} else {
counter++;
}
}
function handleTick() {
context.clearRect(0,0,gameCanvas.width,gameCanvas.height);
context.drawImage(avatarImage, 32*animationCounter, 0, 32,32, avatarX, avatarY, 64, 64);
context.fillText("Seconds: " + counter, 5, 5);
context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);
animationCounter++
if(animationCounter >1) {
animationCounter = 0;
}
}
There are many ways to implement animation. The one i use is pretty easy and looks something like this:
var player = {
x: 0,
y: 0,
width: 50,
height: 100,
sprite: {
column: 0,
row: 0,
height: 50,
width: 100
},
image: PlayerImage,
animation: {
active: true, //Determines if the animation is running or not.
counter: 0,
progress: 0,
sequence: []
}
}
//This functions fires when the left arrow is pressed.
var onLeft = function(){
player.animation.sequence = [{column: 0, row: 0, t: 12}, {column: 1, row: 0, t: 12}, {column: 2, row: 0, t: 12}];
player.animation.active = true;
}
//This functions fires when the right arrow is pressed.
var onRight = function(){
player.animation.sequence = [{column: 0, row: 1, t: 12}, {column: 1, row: 1, t: 12}, {column: 2, row: 1, t: 12}];
player.animation.active = true;
}
//This function fires when no arrow are pressed.
var standingStill = function(){
player.animation.active = false;
}
var handleTick = function(){
//Clear the canvas.
context.canvas.width = context.canvas.width;
//If the animation is active.
if(player.animation.active){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(player.animation.counter >= player.animation.sequence[player.animation.progress]){
player.animation.counter = 1;
if(player.animation.progress >= player.animation.sequence.length - 1){
player.animation.progress = 0;
}else{
player.animation.progress++;
}
var currentFrame = player.animation.sequence[player.animation.progress];
//Change player.sprite column and row.(new frame)
player.sprite.column = currentFrame.column;
player.sprite.row = currentFrame.row;
}else{
player.animation.counter++;
}
}
context.drawImage(player.image, player.sprite.column * player.sprite.width, player.sprite.row * player.sprite.height, player.sprite.width, player.sprite.height, player.x, player.y, player.width, player.height)
}
The sequence is an array that contains objects that look like that: {column: 0, row: 0, t: 12} Every object is a frame. The column value is the current x of the sprite, the row is the y of the sprite. The script automatically creates the x and the y value, so all you need to add is value like 0, 1, 3, 5, and so on.(Just which frame it is on either x or y axis.) So for example, if the column is 0 and the row is 0, this is the frame that is in the top-left corner(the first frame). The t value stands for tick, this determines how many ticks there has to happend before the animation goes to the next frame.
Player.sprite also has properties width and height, that's the width and the height of the frame, it is often the same value as the width and height of the player object.
You have to make your own player.animation.sequence in onLeft and onRight function so it animates how you want it to animate.
I hope you understood what i meant. This might seem complicated, but it really isn't and if you don't get it now, don't worry, you'll get it eventually. If you really have difficulties with understanding, just ask.
Edit: First of all i highly recommend using objects to store information about entities. It makes game making much easier and cleaner. Just look at the player object, it's much easier to get the x simply by writing player.x than PlayerX. It looks more professional too. :) And when you have to give a lot of information about your entity you don't have to pass many arguments, you pass the whole object. Example:
//Entity properties stored in separate variable.
function animate(EntityX, EntityY, EntitySpriteX, EntitySpriteY, ...){
var x = EntityX;
//And so on...
}
//Entity stored in an object.
function animate(Entity){
var x = Entity.x;
//And so on...
}
Anyway, back to your question. First, we have to add variables that store information about our sprite.
var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.
We also have to add variables that store the information about the animation.
var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.
Then, in your handleTick function you have to add a code that will animate the sprite. You have to add this code before you draw your entity.
//If the animation is active.
if(animationActive){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(animationCounter >= animationSequence[animationProgress]){
animationCounter = 1;
//Reset the progress, so that next time another animation frame shows up.
if(animationProgress >= animationSequence.length - 1){
animationProgress = 0;
}else{
animationProgress++;
}
//Select information about the current animation frame and store it in a variable so it is easier to access.
var currentFrame = animationSequence[animationProgress];
//Change player.sprite column and row.(new frame);
avatarSpriteColumn = currentFrame.column;
avatarSpriteRow = currentFrame.row;
}else{
animationCounter.counter++;
}
}
Ok, now you have a code that animates the sprite, but how do we run it? Well, i see you have a variable called moving. It tells us in what direction the player is moving and if it is moving at all. It looks like you implemented it a little bit wrong. Right now your function that operates the keys looks like this:
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 0;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 1;
}
break;
}
}
The variable is supposed to return 1 if the entity is going to the right, 2 if it is going to the left and 0 if the entity is standing still, right? Right now it shows 0 when the entity is moving to the right and 1 when it is moving to the left. It also doesn't show us if the entity is idle. We have to fix it. Change it to something like this:
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 1;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 2;
}
break;
default:
moving = 0;
}
}
Ok, now we have to add this code to the handleTick function. This code starts the animation and changes the sequence.:
if(moving == 1){ //Moving in the right direction.
animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
animationActive = true; //Run the animation.
}else if(moving == 2){ //Moving to the left.
animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
animationActive = true; //Run the animation.
}else{
animationActive = false; //Stops the animation, but the last frame stays.
/*
Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.
animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
animationActive = true;
*/
}
Now, the last thing we have to do is to draw the entity. In your case, this will look something like this:
context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);
In the end your whole code will look something like this:
var avatarX = 0;
var avatarY = 240;
var avatarImage;
var counter = 1;
var XWIDTH = 0;
var WIDTH = 400;
var dx = 5;
var tt;
var gameCanvas;
var context;
var moving;
var animationCounter = 1;
var avatarSpriteColumn = 0; //Sprite frame on the x axis.
var avatarSpriteRow = 0; //Sprite frame on the y axis.
var avatarSpriteWidth = 50; //The width of a frame.
var avatarSpriteHeight = 100; //The height of a frame.
var animationActive = false; //A variable that controls if the animation is 'running'.
var animationCounter = 0; //How many frames(ticks) have passed since the last frame(animation frame) has changed. (I'm not good at describing variables. :P)
var animationProgress = 0; //Current animation frame.
var animationSequence = []; //Array that stores the sequence of animation, as i explained.
window.addEventListener('keydown', KeyDown);
function setUpGame() { //This is the function that is called from the html document.
gameCanvas = document.getElementById("gameCanvas"); //Declare a new variable & assigns it the id of the CANVAS from the html document.
context=gameCanvas.getContext("2d");
context.font = "18px Iceland";
context.textBaseline = "top";
avatarImage = new Image(); //Declaring a new variable. This is so that we can store the image at a later date.
avatarImage.onload=function(){
// avatarImage is now fully loaded and ready to drawImage
context.drawImage(avatarImage, Math.random() * 100, avatarY);
// start the timer
tt = setInterval(function(){counTer()},1000);
setInterval(handleTick, 25);
}
avatarImage.addEventListener('load', startLoop, false);
avatarImage.src = "img/ships.png"; //Ditto from above.
}
function startLoop() {
console.log("Detecting whether moving to the right is: " + moving);
if(moving == 0) {
gameLoop();
}
}
function gameLoop() {
setTimeout(gameLoop, 100);
handleTick();
}
function KeyDown(evt) {
switch (evt.keyCode) {
case 39: /*Arrow to the right*/
if(avatarX + dx <WIDTH && avatarX + dx >XWIDTH) {
avatarX += dx;
moving = 1;
}
break;
case 37: /*Arrow to the left*/
if(avatarX - dx >XWIDTH) {
avatarX -= dx;
moving = 2;
}
break;
default:
moving = 0;
}
}
function counTer() {
if(counter == 60) {
clearInterval(tt);
} else {
counter++;
}
}
function handleTick() {
context.clearRect(0,0,gameCanvas.width,gameCanvas.height);
if(moving == 1){ //Moving in the right direction.
animationSequence = []; //Animation of moving in the right direction. Change the sequence to your own.
animationActive = true; //Run the animation.
}else if(moving == 2){ //Moving to the left.
animationSequence = []; //Animation of moving to the left. Change the sequence to your own.
animationActive = true; //Run the animation.
}else{
animationActive = false; //Stops the animation, but the last frame stays.
/*
Alternatively, if you want a separate frame or animation that is animating when the entity is standing, you run this code.
animationSequence = []; // Your sequence. If you want a single frame, with no animation just add one frame to the sequence.
animationActive = true;
*/
}
//If the animation is active.
if(animationActive){
//If the counter >= tick in the sequence. If not, just keep on increasing the counter value.
if(animationCounter >= animationSequence[animationProgress]){
animationCounter = 1;
//Reset the progress, so that next time another animation frame shows up.
if(animationProgress >= animationSequence.length - 1){
animationProgress = 0;
}else{
animationProgress++;
}
//Select information about the current animation frame and store it in a variable so it is easier to access.
var currentFrame = animationSequence[animationProgress];
//Change player.sprite column and row.(new frame);
avatarSpriteColumn = currentFrame.column;
avatarSpriteRow = currentFrame.row;
}else{
animationCounter.counter++;
}
}
context.drawImage(avatarImage, avatarSpriteColumn * avatarSpriteWidth, avatarSpriteRow * avatarSpriteHeight, avatarWidth, avatarHeight, avatarX, avatarY, 64, 64);
context.fillText("Seconds: " + counter, 5, 5);
context.fillText("1 is Right, 2 is Left, 0 is idle: " + moving, 20, 20);
}
The only thing you have to do right now is to make your own animationSequences and check if it works, let me know if you have any problems with that.
Of course, the code i am using is more complicated and has more "abilities" and is easier to use(the code behind is more complicated), but hopefully this will help you.
I must also apoligize for making this thing seem so complicated, when it's not. I am bad at explaining.
I am trying to make an image move 360° (not rotate) back it's course, but so far I was able to move only to a specific direction, if I add left & bottom course, then the image going diagonal to left & bottom. Here are the properties:
CSS
#circle{
background:red;
border-radius:100px;
height:100px; width:100px;
position:absolute;
}
JavaSript
(function() {
var speed = 10,
moveBox = function(){
var el = document.getElementById("circle"),
left = el.offsetLeft,
moveBy = 3;
el.style.left = left + moveBy + "px";
if(left > 200){
clearTimeout(timer);
}
};
var timer = setInterval(moveBox, speed);
}());
HTML:
<div id='circle'></div>
JsFiddle Online Demo
The problem is looping back the red circle, I want it to move to left > bottom > right > up
in a circular manner.
thanks for the help.
Using Math.sin and Math.cos to describe the circle: http://jsfiddle.net/E3peq/7/
(function() {
var speed = 10,
moveX = 0.1,
moveY = 0.1,
increment = 0.1,
amp = 10,
moveBox = function(){
var el = document.getElementById("circle"),
left = el.offsetLeft,
top = el.offsetTop;
moveX += increment;
moveY += increment;
var moveXBy = Math.cos(moveX) * amp;
var moveYBy = Math.sin(moveY) * amp;
el.style.left = (left + moveXBy) + "px";
el.style.top = (top + moveYBy) + "px";
if(left > 200){
clearTimeout(timer);
}
};
var timer = setInterval(moveBox, speed);
}());
Edit: Abraham's answer in the comments is actually a lot nicer looking than this...
So far I have this:
a sprite sheet of w 5507px X H 2100px
the scenes are 550 x 700
and the png is named animation png or something
the image is on the background of the div, and it goes to the coordinates background position, but so far, the animation goes for a loop and I need it to stop, I've been trying some solutions but nothing...I will appreciate any idea, please check the code
<style>
#anim{
width:550px;
height:700px;
background-image:url(anim3.png);
}
</style>
<title>Untitled Document</title>
</head>
<body onload="init()">
<script>
var imageWidth=5500,
imageHeight=2100,
xpos=0,
ypos=0,
index=0,
numFrames= 30,
frameSize=550,
frameHeight=700,
div;
function init(){
div = document.getElementById('anim');
loop();
setInterval(loop, 1000 / 10);
}
function loop() {
//multiplying by -1 because we want to move the image to the left and up to reveal the area we want to see.
div.style.backgroundPosition = (-xpos)+"px "+(-ypos)+"px";
//each time around we add the frame size to our xpos, moving along the source image.
xpos += frameSize;
ypos +=frameHeight;
//increase the index so we know which frame of our animation we are currently on.
index += 1;
//if our index is higher than our total number of frames, we're at the end and better start over.
if (index == 30) {
div.style.backgroundPosition =(imageWidth)+"px"+(imageHeight)+"px";
//if we've gotten to the limit of our source image's width, we need to move down one row of frames.
} else if (xpos +frameSize > imageWidth){
xpos =0;
ypos += 700;
}
}
</script>
try this one, using clearInterval() to stop loop:
var result;
function init(){
div = document.getElementById('anim');
loop();
result = setInterval(loop, 1000 / 10);
}
function loop() {
//multiplying by -1 because we want to move the image to the left and up to reveal the area we want to see.
div.style.backgroundPosition = (-xpos)+"px "+(-ypos)+"px";
//each time around we add the frame size to our xpos, moving along the source image.
xpos += frameSize;
ypos +=frameHeight;
//increase the index so we know which frame of our animation we are currently on.
index += 1;
//if our index is higher than our total number of frames, we're at the end and better start over.
if (index == 30) {
div.style.backgroundPosition =(imageWidth)+"px"+(imageHeight)+"px";
//if we've gotten to the limit of our source image's width, we need to move down one row of frames.
clearInterval(result) ;
} else if (xpos +frameSize > imageWidth){
xpos =0;
ypos += 700;
}
}
Try this:
http://jsfiddle.net/BgSnL/3/
var div,
imageWidth = 427,
imageHeight = 140,
frameWidth = 61,
frameHeight = 70,
curFrame = { x: 0, y: 0 };
function init(){
div = document.getElementById('anim');
loop();
setInterval(loop, 1000 / 10);
}
function loop()
{
var xOffset = frameWidth * curFrame.x,
yOffset = frameHeight * curFrame.y;
div.style.backgroundPosition = -(xOffset) + "px " + -(yOffset) + "px";
// if we can, iterate to the next column
if ((xOffset + frameWidth) < imageWidth) {
curFrame.x += 1;
// else if we can, drop down a row
} else if ((yOffset + frameHeight) < imageHeight) {
curFrame.x = 0;
curFrame.y += 1;
// reset
} else {
curFrame.x = 0;
curFrame.y = 0;
}
}
init();
The current frame x/y offset is tracked via an object. Each iteration we want to do one of:
Move over to the next column
Reach the end of the row, drop down a row
Reach the end of the animation, restart
I'd like to make an animation of a single line using JavaScript and Canvas tag. I'm able to do it without any problems, except:
it works fine if you're trying to do a straight line - I have an interval (10ms) adding 1px, so if it's going from 150px (x)/20px (Y) to 150px (X)/200px (Y) - everything looks cool.
Problem is with lines going to the right or left -- eg from 150px (x) / 20px (Y) to 35px (X)/200px (Y)
Here my animation fails because by adding 1px every 10ms to both X and Y makes the line hit left side (35px) first and then going from there to my end point Y.
Here's my code (you will need Firefox or Opera) -- as you can see line hits left side sooner and that's my problem. :(
<html>
<script type="text/javascript" src="http://www.prototypejs.org/assets/2008/9/29/prototype-1.6.0.3.js"></script>
<style>
body {background: #fff; color: #ccc;}
</style>
<script type="text/javascript">
var startpointx = 150;
var startpointy = 25;
var curposx = 150;
var curposy = 25;
var myinterval;
function init() {
myinterval = setInterval( ' animate(35, 250) ', 10);
}
function random (n)
{
return (Math.floor (Math.random() * n));
}
function animate(endpointx, endpointy) {
if (curposx == endpointx && curposy == endpointy){
clearInterval(myinterval);
drawShape(endpointx, endpointy);
return false;
} else {
if(curposx != endpointx){
if(endpointx > curposx) {
curposx = curposx + 1;
} else {
curposx = curposx - 1;
}
}
if(curposy <= endpointy){
curposy = curposy + 1;
}
}
drawShape(curposx, curposy, "#000");
}
function drawShape(tendpointx, tendpointy, clor){
var canvas = document.getElementById('cnvs');
var ctx = canvas.getContext('2d');
ctx.clearRect(0,0,310,400);
ctx.strokeStyle = clor;
ctx.beginPath();
ctx.moveTo(startpointx ,startpointy );
ctx.lineTo(tendpointx,tendpointy);
ctx.stroke();
}
//
init();
</script>
<body>
<canvas id="cnvs" width="310" height="400" style="border: 1px solid #ccc;"></canvas>
</body>
</html>
Let's say you want to draw a straight line from point (0, 0) to (100, 200). Horizontal distance is 100, vertical distance is 200, which means that when you move your end point by 1 pixel horizontally, you need to move it by 2 pixels vertically (or, for one pixel vertically 0.5 pixel horizontally).
To calculate the difference you can use this algorithm:
var deltaX = Math.abs( endpointx - startpointx );
var deltaY = Math.abs( endpointy - startpointy );
var diffX = 1, diffY = 1;
if( deltaX > deltaY ){
diffY = deltaY / deltaX;
}
else if( deltaX < deltaY ) {
diffX = deltaX / deltaY;
}
Then in your animation you need to increment/decrement curposx and curposy not by 1, but by diffX and diffY respectively. This calculation should be done outside of your animate() function (because it always returns the same result).