I'm newer to js coding and I can't find any answers to my question. I'm working with the tag in html and trying to get my JS code to redraw the canvas when I want. I've tried using a simple while loop to do it, but that just goes through the while loop then draws the end result without showing the updates in between. My current code (below is using the setTimeout/clearTimeout calls, but it produces the same result. Not sure if this is even possible. Maybe it's just how I'm updating my canvas?
This is my code for calling my function to update my arrays I'm storing my data in and then update the canvas.
var done = false;
var count = 0;
while (!done) {
timer = setTimeout(updateGrid(grid), 500);
clearTimeout(timer);
done = stop(count, allDone);
count++;
}
The functions I'm using to draw on the canvas:
context = canvas.getContext("2d");
context.fillStyle = color;
context.fillRect(x, y, w, h);
Is there something I'm missing?
clearTimeout is nullifying your updateGrid timeout.
I think what you want is to use setInterval instead. But you can also use setTimeout and adjust the timeout time (500 * (i + 1) or something) and set up all your timeouts like that
while (!done) {
timer = setTimeout(updateGrid(grid), 500);
clearTimeout(timer); //this is nullifying the line above
done = stop(count, allDone);
count++;
}
Related
I am attempting to make a 'web player' that plays music when you click the play button, and displays how far along you are in the track on a bar. I have made a function that plays the audio and checks how far along the track you are to set the width of the playback bar, but for the life of me i can't get it to recurse. I know the function works, because the playback bar jumps to the correct position when you click the play button, but i cant seem to automate it. Here is the code:
function play(x) {
var audio = document.getElementById(x);
audio.play();
var progress = audio.currentTime;
var duration = audio.duration;
var percent = progress/duration;
var width = percent*100;
var progbar = document.getElementById("play-line-elapsed");
var width = width + "%";
progbar.style.width = width;
setTimeout(play("Bring-Out-Yer-Dead"), 5000);
}
const createClock = setInterval(play, 100);
I have tried while loops, do while loops, setTimeout and finally setInterval so far. I am also a complete beginner to javascript, so it'll probably be completely obvious when someone points it out to me. Thanks in advance
Here is the code that should work
function play(x) {
var audio = document.getElementById(x);
audio.play();
var progress = audio.currentTime;
var duration = audio.duration;
var percent = progress/duration;
var width = percent*100;
var progbar = document.getElementById("play-line-elapsed");
var width = width + "%";
progbar.style.width = width;
setTimeout(function () {play("Bring-Out-Yer-Dead")}, 5000);
}
const createClock = setTimeout(function () {play("Bring-Out-Yer-Dead")}, 100);
What you did was to create an interval that calls play every 0.1 seconds, without any arguments. I suppose that wouldn't work as the function requires an argument.
Your setTimeout at the end of play wouldn't work too, because you're just calling it. You should provide a function object (not very correct word, but you get it) to setTimout, not calling it. The way you did it is to call play and give its return value (which is undefined) to setTimout, which makes setTimeout do nothing.
The corrected code creates a timeout that calls play after 0.1 seconds, then play continues to call itself every 5 seconds.
You have to provide a 0 arity function to setTimeout/setInterval, meaning a function that accepts no arguments. I used an anonymous function for that, but you could write another function with no arguments and use it there.
But I think you would be better off using events. I haven't tested any of these, but these events seem promising for what you are trying to do.
https://www.w3schools.com/jsref/event_ondurationchange.asp
https://www.w3schools.com/jsref/event_onplaying.asp
https://www.w3schools.com/jsref/event_onplay.asp
I need to display a series of RGB colors inside my ASP.NET web page. I was hoping to accomplish this using an ASP Update Panel but the update has to take place in sequence without the user intervention, every 4 or 5 seconds.
My initial JavaScript code looks like this :
document.getElementById('div').style.backgroundColor = "rgb(0,0,255)";
Problem is getting the next RGB color combination to display.
I experimented with a wait 'loop' found here in another post :
wait(7000); //7 seconds in milliseconds
function wait(ms) {
var start = new Date().getTime();
var end = start;
while (end < start + ms) {
end = new Date().getTime();
}
}
Problem is that, it does not work. I tried with :
document.getElementById('fondRGB').style.backgroundColor = "rgb(0,0,255)";
wait(7000);
document.getElementById('fondRGB').style.backgroundColor = "rgb(128,128,128)";
wait(7000);
document.getElementById('fondRGB').style.backgroundColor = "rgb(0,0,0)";
but only the very first rgb color is ever honored?
running a blocking while loop in javascript is a really bad idea. There is only one thread so if you do that the user will not be able to interact with your application until your while loop is complete.
A better solution is to use setTimeout to run the timer asynchronously and call the callback when the timer is complete.
var el = document.getElementById('fondRGB')
function wait(ms, callback) {
setTimeout(callback, ms)
}
wait(7000, function(){
el.style.backgroundColor = "rgb(0,0,255)"
})
wait(14000, function(){
el.style.backgroundColor = "rgb(128,128,128)"
})
wait(21000, function(){
el.style.backgroundColor = "rgb(0,0,0)"
})
So even if that did work it wouldn't be what you want since the wait function is attempting to block the only execution thread which would just make the whole browser hang. The wait method you are looking for is called setTimeout and it works a little different than you are probably used to.
setTimout lets you specify a function and an amount of milliseconds before it will execute that function so in your case if you want to accomplish changing the background color every 7 seconds you would probably do something like this:
var colors = ['rgb(0,0,255)', 'rgb(128,128,128)', 'rgb(0,0,0)'];
for (var i = 0; i < colors.length; i++) {
setTimeout(function(color) {
document.getElementById('fondRGB').style.backgroundColor = color;
}.bind(null, colors[i]), i * 7000);
}
Sorry that the code got a little complex, look up closures if you are wondering why the .bind part is necessary (if you are not already familiar).
I've written some code in JS that allows the user to click on the screen to create a square, and hold down the mouse to increase the size of the square before stamping it. The problem is that the speed at which the size of the square increases while the mouse is held down slows once the mouse is moved from the originally clicked position. I'm using intervals to change the size over a time of 1 millisecond. Here is the JS code (with Jquery):
UPDATE: If you run the code snippet you won't see the issue. Try saving it as a file and running it, then the issue will probably occur.
<!DOCTYPE html>
<html>
<head>
<title>My Canvas</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
var mouseDown
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
var objects = []
c.addEventListener("mousedown", onMouseDown);
c.addEventListener("mouseup", onMouseUp);
function createSquare(x, y, size) {
this.x = x;
this.y = y;
this.size = size;
this.draw = draw;
this.drawStylus = drawStylus;
this.clear = clear;
};
function draw() {
ctx.fillRect(this.x, this.y, this.size, this.size);
};
function drawStylus() {
ctx.fillRect(this.x, this.y, this.size, this.size);
};
function clear() {
ctx.clearRect(this.x, this.y, this.size, this.size);
}
// var mySquare = new createSquare(100,100,100);
// mySquare.draw();
function onMouseDown() {
mouseDown = true
x = event.clientX
y = event.clientY
size = 100
console.log('clicked')
interval = setInterval(function () {
size = size + 5
var cursorSquare = new createSquare(x,y,size);
cursorSquare.clear();
cursorSquare.drawStylus();
}, 1);
};
function onMouseUp() {
console.log('up')
if (mouseDown) {
clearInterval(interval);
var newSquare = new createSquare(x,y,size);
newSquare.draw();
mouseDown = false
};
};
});
</script>
</head>
<body>
<canvas id='myCanvas' width="5000" height="5000" style="border:1px solid #000000;">
</canvas>
</body>
</html>
The problem is the interval,
First. 1 millisecond is too short a time for any rendering, the mouse is only updated around 1/60th of a second, and rendering above 1/60th (shorter period) will put an overly heavy load on the browser and as the screen refresh is also at 1/60th of a second most of the rendering will be lost before it even gets a chance to make it to the the display.
Secondly, though 1 millisecond is too short a time for some browsers (forget the min interval time for each browser) the problem is that when you present a task that is longer than the interval period the browser still keeps adding the function calls to the call stack, effectively delaying other events and browser upkeep. Continued use of setInterval in such a situation will result in a call stack overflow, crashing all javascript on the page.
The simple rule is NEVER use setInterval for any reason. Use setTimeout instead, as it protects from call stack overflows and stops uncontrolled calls being placed on the call stack. Using setTimeout can actually result in better timed intervals.
// simple timeout
var interval = 50
function myTimer(){
setTimeout(myTimer,interval); // set up the next interval
}
// start it
setTimeout(myTimer,interval);
By getting the time via new Date().valueOf() you can adjust the timeout for the next call to stay as close as possible to the required interval, something that setInterval makes very hard to do. To stop the calls simply don't call setTimeout if a stop flag is set.
But all that said for graphics you should be using requestAnimationFrame which is very similar to setTimeout but you do not provide the timeout, the browser will get the best time to keep you in sync with the rendering and layout engines and also with the display hardware so you dont get flickering and or shearing.
function update(time){ // requestAnimationFrame calls the function with the time in milliseconds
// do what is needed
requestAnimationFrame(update); // get next frame when browser is ready 1/60th second
}
requestAnimationFrame(update); // start it going
For coordinating with a mouse just have your mouse listeners set some variables like mouseX,mouseY and buttonState and do nothing more. In the update function use these values to handle the mouse. This produces a much more manageable mouse interface.
I'm wanting to animate an element using setInterval. I've put my code into an object with 2 functions one to initialize and one to animate using setInterval. When I try to run the code the animation works once then causes the browser to hang. The only thing I can think of is an infinite loop being created somewhere however I can't see anywhere in my code that would cause this.
What is causing the browser to crash, how can this be overcome ?
<div id='box' style='position:absolute;height:100px;width:100px;background-color:#44e'>box</div>
<script>
var box = {
init : function(elemId) {
box.elem = document.getElementById(elemId);
box.timer = setInterval;
box.tick = 0;
box.animate();
},
animate: function() {
if(box.tick < 100) {
box.elem.style.top = box.tick +'px';
box.elem.style.left = box.tick +'px';
box.tick++;
} else {
clearInterval(box.timer);
}
var timer = setInterval(box.animate, 50)
}
}
box.init('box');
</script>
setInterval sets up a function that will be called repeatedly by the browser until you cancel the interval timer. Your code isn't doing that, because the only call to clearInterval is using box.timer, which is never set to a timer handle (the return value from setInterval). So you end up scheduling thousands of calls (a new series every time animate is called) and bringing the browser to its kneeds.
At the very least, this:
var timer = setInterval(box.animate, 50)
should probably be:
box.timer = setInterval(box.animate, 50);
Or you may want setTimeout (which schedules only one call back).
I am trying to make a function that starts in exact intervals to keep stanble update rate. The problem is that it seems to execute in 2 channels. This is the log:
timeElapsed=141; lastDraw=1314040922291
timeElapsed=860; lastDraw=1314040923151
timeElapsed=141; lastDraw=1314040923292
timeElapsed=860; lastDraw=1314040924152
timeElapsed=141; lastDraw=1314040924293
timeElapsed=860; lastDraw=1314040925153
timeElapsed=141; lastDraw=1314040925294
timeElapsed=860; lastDraw=1314040926154
timeElapsed=141; lastDraw=1314040926295
timeElapsed=859; lastDraw=1314040927154
timeElapsed=143; lastDraw=1314040927297
timeElapsed=858; lastDraw=1314040928155
timeElapsed=143; lastDraw=1314040928298
timeElapsed=858; lastDraw=1314040929156
timeElapsed=142; lastDraw=1314040929298
First, I exectute my function using
drawTimer = setTimeout(function(){ draw() }, 1);
and the function looks like this:
var draw = function(){
if(!running)
return;
var miliseconds = getCurrentMiliseconds();
var timeElapsed = miliseconds - lastDraw;
lastDraw = miliseconds;
console.log("timeElapsed=" + timeElapsed + "; lastDraw=" + lastDraw);
onDrawListener(timeElapsed);
if(timeElapsed < timeLapse)
miliseconds = timeLapse - timeElapsed;
else
miliseconds = 1;
drawTimer = setTimeout(function(){ draw() }, miliseconds);
}
It happens in both, Chrome and Firefox. Do you know what is it caused by? And... How to fix it?
P.S. Since everyone seems to be so confused about the running variable, here it is: it's a private parent object member that indicates whether the mechanism is still running or has stopped. It's set by other functions and is just there to make sure this function doesn't continue working after stop() is called.
-- update --
timeLapse is set to 1000 (1 time per seconds) and never changed again.
onDrawListener is set to this function:
function(timeElapsed){
canvas.clear();
moveSnake();
if(snake.body[0] == food){
food = getRandomFreePosition();
++snake.body.lenght;
}
drawBackground();
drawFood();
drawSnake();
}
to explain it: canvas is kinda the engine that takes care of callbacks, key listening and also has a few functions. Other than that seems kinda self-explaining. they do nothing other than some int algorithms and drawing in the canvas.
-- Figured out --
I understood that I should calculate time spent for current function and not since the last one started. My old method worked not in 2 channels but rather in long-short-long-short-long-... delayes
first of all you dont set the running bool and also when you enter the function immediately do a on clearTimeout on drawTimer.
clearTimeout(drawTimer);
In a loop like that, you should consider to write:
if(timeElapsed >= AMOUNT_OF_TIME)
{
// run code
}