how do i change a variable value when it gets tangled in various getintervals? - javascript

I have a little jquery script for a stop motion animation. It uses moment.js to get the time and then does some math to get a "frame" number and then does some padding to match it to a filename in my directory, spits that into an img src and then iterates +1. I have two setInterval functions going-one that controls the frame rate (getframe) and one that controls how often the client checks for the proper time (gettime).
I've just discovered there are a bunch of dead frames in my directory though-- image files that I want to skip over but I can't just delete without screwing up my whole sequence, to be exact I want to my script to skip from image-029399.jpg to image-031170.jpg. Because a client might log in in the middle of that dead space, I was thinking I should have some kind of statement like if (frame>=29399 && <=31170; {frame=31171};) but I can't quite figure out how to insert that into my code without making everything stop working... below is my code:
window.onload = $(function () {
gettime();
setinterval(gettime,10000);
setInterval(getframe,580);
var frame;
function gettime() {
now = moment().zone('+0045');
if (now.hour()<=17) {
now =now.subtract('day',1)
}
if (now.hour() >= 18) {
now = now.subtract('hour', 18).subtract('minute', 30);
}
else {
now = now.add('hour', 6).subtract('minute', 30);
}
frame = ((now.hour() * 3600) + (now.minute() * 60) + now.second()) * 2 +7463;
}
function getframe() {
var framestr = frame? frame.toString() : "";
function pad (str, max) {
return str.length < max ? pad("0" + str, max) : str;
}
framerun = pad (framestr,6);
var src = "https://s3.amazonaws.com/combined11/image-"+ framerun +".jpg";
framerun1=parseInt(framerun);
$("#frame_placeholder").attr("src", src);
frame=framerun1 += 1;
}
});

Change it in the place where you set frame, i.e. gettime. Add this below your frame =... line:
function gettime() {
now = moment().zone('+0045');
if (now.hour()<=17) {
now =now.subtract('day',1)
}
if (now.hour() >= 18) {
now = now.subtract('hour', 18).subtract('minute', 30);
}
else {
now = now.add('hour', 6).subtract('minute', 30);
}
frame = ((now.hour() * 3600) + (now.minute() * 60) + now.second()) * 2 +7463;
if (frame >= 29399) {
frame += 1771;
}
}
Now, why?
First you change it where you're setting frame because it's the problem of the settor, not the gettor. And of course, since you're recalculating it each time, make sure you put the new code after the recalculation.
At first, I considered what you did: if (frame >= 29399 && frame <= 31170) frame = 31171;, but that essentially makes the program hang on the same frame for 1771 frames.
Then I considered if (frame >= 29399 && frame <= 31170) frame += 1771, but that's even worse - that would jump to the right frame, advance for 1771 frames, and then jump back to frame 31171, which isn't desired.
No, all you want to do is skip a gap, and all frames after that gap must make the same jump. So as soon as you hit the low side of the gap, just add the distance (31170 - 29399) of the gap to all values.
EDIT Actually, I don't know enough about the rest of your system to know if this is the right answer. If other things depend on the value of frame, you actually may want to make the change in the gettor without changing the base value of frame:
function getframe() {
var framestr = frame ? (frame >= 29399) ? (frame + 1771).toString() : frame.toString() : "";
And depending on what behavior you want in the deadzone, you may need to use any of the other function variations I discussed.
var framestr = frame? frame.toString() : "";

It looks like the top of getFrame would make the most sense, no?
function getframe() {
if (frame && ((frame >= 29399) && (frame <= 31170))) {
frame = 31171;
}
var framestr = frame ? frame.toString() : "";
// etc.

Related

setting a time delay between two frame when animation a sprite sheet

This is my jsfiddle :http://jsfiddle.net/Z7a5h/
As you can see the animation of the sprite sheet when the player is not moving is too fast so I was trying to make it slow by declaring two variable lastRenderTime: 0,RenderRate: 50000
but my code is not working and it seem I have a misunderstanding of the algorithm I am using so can anyone lay me a hand to how can I fix it?
if (!this.IsWaiting) {
this.IsWaiting = true;
this.Pos = 1 + (this.Pos + 1) % 3;
}
else {
var now = Date.now();
if (now - this.lastRenderTime < this.RenderRate) this.IsWaiting = false;
this.lastRenderTime = now;
}
Yes, your logic is wrong. You were using the wrong operator < instead of >. Also, you needed to update the lastRenderTime only when the condition is statisfied, otherwise it keeps getting updated and the value of now - this.lastRenderTime never ends up becoming more than 20 or so.
if (!this.IsWaiting) {
this.IsWaiting = true;
this.Pos = 1 + (this.Pos + 1) % 3;
}
else {
var now = Date.now();
if (now - this.lastRenderTime > this.RenderRate) {
this.IsWaiting = false;
this.lastRenderTime = now;
}
}
Here is your updated fiddle.

Avoid javascript's variables reset when user uses back and foward

Well,
I Have a countdown timer, and I'm facing the following problem:
My countdown starts at 90 seconds. If the user waits until it reaches 2 seconds, for example, then he goes back using browser's button and after goes forward (backing to the same page), the countdown restarts at 90 seconds, not at 2 as I need, because when the timer reaches 0 I "click" at a button which post the form.
I know I need to handle the back and forward button and set my variable with the new value but I don't have any idea how can I do it. Any help will be great.
My code is below:
var count = 90;
var screenCount = count;
var newCount = 0;
function countFunction() {
if (screenCount != 0) {
var minutes = Math.floor(count / 60);
var seconds = count - minutes * 60;
if (count > 60){
if (seconds < 10)
seconds = "0" + seconds;
screen = minutes + "m:" + seconds + "s";
$('.timer').css('width',"120px")
}
else{
if (count < 10)
screen = "0" + count;
else
screen = count + "s";
$('.timer').css('width',"60px")
}
document.getElementById('tempo').innerHTML = screen;
if (count == 0) {
set('temporizador', screenCount);
$(":submit").removeAttr("disabled");
$('#responder').click();
}
if (count != 0) {
set('temporizador',screenCount - count );
count = count - 1;
setTimeout("countFunction()", 1000);
}
}
else {
document.getElementById('tempo').innerHTML = '∞';
set('temporizador', newCount);
newCount++;
setTimeout("countFunction()", 1000);
}
}
When the user presses back a whole new page is loaded, with an entirely new Javascript context. If you want to pass information from the context of one page to the context of another, there are several ways to do it.
In your particular situation, using LocalStorage is the easiest:
// count down 90 seconds, including page navigation on this site
var count = +localStorage.getItem('timerCount') || 90;
function countDown() {
count--;
localStorage.setItem('timerCount', count);
if (count<0) window.clearInterval(myInterval);
}
var myInterval = window.setInterval(countDown, 1000);
Suggestion by #DmitryVolokh
In this example i stored the remaining time in localStorage. If you want to track the elapsed time from a particular moment, you would be better served to store the starting time instead and compute the difference.
You use local storage for this as suggested above but there is the slight issue that some older browsers don't support localStorage: http://caniuse.com/#search=local%20storage
Since you are only storing a single number you could also use a cookie:
var match, count;
if (match = /timerCount=(\d+);/.exec(document.cookie)) {
count = match[1];
} else {
count = 90
}
function countDown() {
count--;
document.cookie = 'timerCount=' + count + ';';
if (count<0) window.clearInterval(myInterval);
}
var myInterval = window.setInterval(countDown, 1000);
You can use the onbeforeunload javascript event to see when the users leave the page, and then act as you want : changing the window.location to redirect the user (and give additional parameters like your timer), or prevent him from leaving the page.
You can also create a cookie or use localstorage to store the timer and get it back next time user comes to your page.

Cannot get set interval to work?

No matter what I do I cannot get this bit of code to work, the part where you set an interval in the draw method and will call the Loop method 4 times in two seconds, each call displaying a different image. Currently it shows nothing? And the issue is not with an images etc as it works with one image fine. Been at this for 2 days..
function Explosion() //space weapon uses this
{
this.srcX = 0;
this.srcY = 1250;
this.drawX = 0;
this.drawY = 0;
this.width = 70;
this.height = 70;
this.currentFrame = 0;
this.totalFrames = 10;
this.hasHit = false;
this.frame = 0;
}
Explosion.prototype.draw = function()
{
if(this.hasHit == true && this.frame < 5)
{
var t=setTimeout(Explosion.Loop,500);
}
if(this.frame == 5)
{
clearTimeout(t);
this.hasHit = false;
this.frame = 0;
}
}
Explosion.prototype.Loop = function()
{
ctxExplosion.clearRect ( 0 , 0, canvasWidth , canvasHeight );
if(this.frame == 1)
{
ctxExplosion.drawImage(spriteImage,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
frame++;
}
else if(this.frame == 2)
{
ctxExplosion.drawImage(spriteImage,this.srcX,(this.srcY + 77),this.width,this.height,this.drawX,this.drawY,this.width,this.height);
frame++;
}
else if(this.frame == 3)
{
ctxExplosion.drawImage(spriteImage,this.srcX,(this.srcY + 154),this.width,this.height,this.drawX,this.drawY,this.width,this.height);
frame++;
}
else if(this.frame == 4)
{
ctxExplosion.drawImage(spriteImage,this.srcX,(this.srcY + 231),this.width,this.height,this.drawX,this.drawY,this.width,this.height);
frame++;
}
}
You've got a few problems:
Explosion.Loop does not exist; in normal classical languages, your error would be known as "trying to call an instance method as if it were static." What you could do is instead pass Explosion.prototype.Loop or this.Loop, but that's no good either: JavaScript's this is dynamic and you'll end up trying to get and set properties on window rather than your object.
What you need to do is use this.Loop, but make sure the this isn't lost. On newer browsers, that can be done with bind1:
setTimeout(this.Loop.bind(this), 500);
1 If they're new enough to support canvas, they probably support bind.
setTimeout will only call your function once; if you want it to be called every half a second rather than only once half a second from now, you'll need to use setInterval instead.
Accessing instance variables as if they were local variables. In several places (for example, frame in Loop), you're accessing frame like this:
frame++;
Unfortunately, frame is not a local variable; it's a property of this. Unlike some other languages, you have to explicitly qualify it:
this.frame++;
As previously mentioned, frame is not the only variable with this problem.

Javascript animate math

I'm struggling to get my head around such simple Math, well at least it seems it should be simple.
I'm basically trying to mirror what jQuery's .animate does, but to no luck.
Here's a simplified version of what I have so far:
var args = {
speed: 1000, // 1 second.
left: 65 // distance.
}, rot, step;
// Terrible math.
rot = step = (((args.left / args.speed) * 10) - 0.10);
var t = setInterval(function() {
if(elem.style.left >= args.left) {
clearInterval(t);
return;
}
rot += step;
elem.style.left = rot;
}, 10);
Please excuse any illogical code (or math), I've been messing around for a good few hours and totally lost my sanity.
Edit:
Here's the way I would do it.
var start_time = Date.now();
// Get the starting time in milliseconds
var t = setInterval(function() {
var delta_time = Date.now() - start_time;
// Get time that has elapsed since starting
if (delta_time >= 1000) {
// if it's been a second
clearInterval(t);
// Stop the timer
elem.style.left = args.left + 'px';
// Set the element to exactly the value it should be (avoids having it set to a float value)
return;
}
elem.style.left = delta_time * args.left / args.speed + 'px';
// Move the element according to how much time has elapsed
}, 10);​
This method has a few advantages. For example, you can adjust the interval to make it more or less smooth, and it won't mess up the animation.
The reason why your solution was taking longer than one second is because of how you used setInterval. setInterval doesn't account for the time your code takes to run, so the total time is always increased by a bit. You can fix this by using delta timing (like in my example).
Try using useing sin and cos to calculate rotation Some what like this
newx = distance * Math.cos(direction) + x
newy = distance * Math.sin(direction) + y
Not sure , this will solve your problem I guess you want to to do a smooth rotation
Try making it as a function it will work , I am not seeing any problem in your math ,
like this
function move(elem) {
var left = 0
function frame() {
left++ // update parameters
elem.style.left = left // show frame
if (left == 100) // check finish condition
clearInterval(id)
}
var id = setInterval(frame, 10) // draw every 10ms
}
Well for one it should be
var args = { ... }
assuming you have the elem set up correctly, you're going to need a inline styling of the attribute you want to animate. Also, you're going to need to parse the style since it has the 'px' attached to it, but you can always add that after you do the math within the interval function.
I set up something here so you can mess around with the settings and whatnot.
edit:
http://jsfiddle.net/mb4JA/2/
edit2:
this should be one second
http://jsfiddle.net/mb4JA/4/
final answer ;) http://jsfiddle.net/mb4JA/10/
You should be able to put any speed in there, and have it animate for that amount of seconds.

Animate counter using Javascript

I have a couple of fairly simple javascript functions which animate the transition of a number, going up and down based on user actions. There are a number of sliders on the page which within their callback they call recalculateDiscount() which animates the number up or down based on their selection.
var animationTimeout;
// Recalculate discount
function recalculateDiscount() {
// Get the previous total from global variable
var previousDiscount = totalDiscount;
// Calculate new total
totalDiscount = calculateDiscount().toFixed(0);
// Calculate difference
var difference = previousDiscount - totalDiscount;
// If difference is negative, count up to new total
if (difference < 0) {
updateDiscount(true, totalDiscount);
}
// If difference is positive, count down to new total
else if (difference > 0) {
updateDiscount(false, totalDiscount);
}
}
function updateDiscount(countUp, newValue) {
// Clear previous timeouts
clearTimeout(animationTimeout);
// Get value of current count
var currentValue = parseInt($(".totalSavingsHeader").html().replace("$", ""));
// If we've reached desired value, end
if (currentValue === newValue) { return; }
// If counting up, increase value by one and recursively call with slight delay
if (countUp) {
$(".totalSavingsHeader").html("$" + (currentValue + 1));
animationTimeout = setTimeout("updateDiscount(" + countUp + "," + totalDiscount + ")", 1);
}
// Otherwise assume we're counting down, decrease value by one and recursively call with slight delay
else {
$(".totalSavingsHeader").html("$" + (currentValue - 1));
animationTimeout = setTimeout("updateDiscount(" + countUp + "," + totalDiscount + ")", 1);
}
}
The script works really well for the most part however there are a couple of problems. Firstly, older browsers animate more slowly (IE6 & 7) and get confused if the user moves the slider again whilst it is still within the animation.
Newer browsers work great EXCEPT for on some occasions, if the user moves the slider mid-animation, it seems that it starts progressing in the wrong direction. So for updateDiscount() gets called with a new value and a directive to count up instead of down. As a result the animation goes the wrong direction on an infinite loop as it will never reach the correct value when it's counting in the wrong direction.
I'm stumped as to why this happens, my setTimeout() experience is quite low which may be the problem. If I haven't provided enough info, just let me know.
Thank you :)
Here is how you use setTimeout efficiently
animationTimeout = setTimeout(function {
updateDiscount(countUp,totalDiscount);
},20);
passing an anonymous function help you avoid using eval.
Also: using 1 millisecond, which is too fast and will freeze older browsers sometimes. So using a higher which will not even be noticed by the user can work better.
Let me know if this works out for you
OK think it's fixed...
Refactored code a little bit, here's final product which looks to have resolved bug:
var animationTimeout;
function recalculateDiscount() {
var previousDiscount = parseInt(totalDiscount);
totalDiscount = parseInt(calculateDiscount());
if (($.browser.msie && parseFloat($.browser.version) < 9) || $.browser.opera) {
$(".totalSavingsHeader").html("$" + totalDiscount);
}
else {
if (previousDiscount != totalDiscount) {
clearTimeout(animationTimeout);
updateDiscount(totalDiscount);
}
}
}
function updateDiscount(newValue) {
var currentValue = parseInt($(".totalSavingsHeader").html().replace("$", ""));
if (parseInt(currentValue) === parseInt(newValue)) {
clearTimeout(animationTimeout);
return;
}
var direction = (currentValue < newValue) ? "up" : "down";
var htmlValue = direction === "up" ? (currentValue + 1) : (currentValue - 1);
$(".totalSavingsHeader").html("$" + htmlValue);
animationTimeout = setTimeout(function () { updateDiscount(newValue); }, 5);
}
Will give points to both Ibu & prodigitalson, thank you for your help :)

Categories

Resources