I'm trying to build a basic renderer that can update the HTML canvas in real time or on a frame by frame basis.
For example, as soon as a pixel is drawn, it'll either update right away to the screen or wait to be collected for a frame, which is then updated (like 25 frames per second)
At the moment this doesn't happen in any way with my code, and I am not sure how to get it to work.
Right now, the canvas only draws to the screen once all operations are plete.
Canvas.js:
$(document).ready(function(){
main();
});
function main(){
var c = document.getElementById('canvas');
var ctx = c.getContext("2d");
for(var x=0; x<1000000; x++){
drawPixel(ctx, "200", "200", "200", "255", randomNumber(0, 1000), randomNumber(0, 600));
}
}
function drawPixel(context, red, green, blue, alpha, x, y){
context.fillStyle = "rgba(" + red + ", " + green + ", " + blue + ", " + (alpha/255) + ")";
context.fillRect(x, y, 1, 1);
}
function randomNumber(min, max){
return Math.floor(Math.random()*(max-min+1)+min);
}
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Canvas Test</title>
<link rel="stylesheet" type="text/css" href="styles.css" media="screen"></style>
<meta name="viewport" content="initial-scale=1">
</head>
<body>
<div class="container">
<canvas height="600" width="1000" id="canvas">
</canvas>
</div>
<script type="text/javascript" src=".1.3.min.js"></script>
<script type="text/javascript" src="canvas.js"></script>
</body>
</html>
I need to know how to make the screen update when I want, instead of it just updating all at once after my code has finished.
EDIT: Basically, what I want is all the dots to appear gradually so the user can see the dots accumulating. Is there a way I can collect the dots every 25th of a second, render that as a frame and repeat?
I'm trying to build a basic renderer that can update the HTML canvas in real time or on a frame by frame basis.
For example, as soon as a pixel is drawn, it'll either update right away to the screen or wait to be collected for a frame, which is then updated (like 25 frames per second)
At the moment this doesn't happen in any way with my code, and I am not sure how to get it to work.
Right now, the canvas only draws to the screen once all operations are plete.
Canvas.js:
$(document).ready(function(){
main();
});
function main(){
var c = document.getElementById('canvas');
var ctx = c.getContext("2d");
for(var x=0; x<1000000; x++){
drawPixel(ctx, "200", "200", "200", "255", randomNumber(0, 1000), randomNumber(0, 600));
}
}
function drawPixel(context, red, green, blue, alpha, x, y){
context.fillStyle = "rgba(" + red + ", " + green + ", " + blue + ", " + (alpha/255) + ")";
context.fillRect(x, y, 1, 1);
}
function randomNumber(min, max){
return Math.floor(Math.random()*(max-min+1)+min);
}
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Canvas Test</title>
<link rel="stylesheet" type="text/css" href="styles.css" media="screen"></style>
<meta name="viewport" content="initial-scale=1">
</head>
<body>
<div class="container">
<canvas height="600" width="1000" id="canvas">
</canvas>
</div>
<script type="text/javascript" src="https://code.jquery./jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="canvas.js"></script>
</body>
</html>
I need to know how to make the screen update when I want, instead of it just updating all at once after my code has finished.
EDIT: Basically, what I want is all the dots to appear gradually so the user can see the dots accumulating. Is there a way I can collect the dots every 25th of a second, render that as a frame and repeat?
Share Improve this question edited Mar 5, 2015 at 5:21 Joseph asked Mar 5, 2015 at 5:09 JosephJoseph 3,95710 gold badges34 silver badges53 bronze badges 2- This seems impossible to me given the canvas API. – Gabriel Ratener Commented Mar 5, 2015 at 5:13
- Well you can setup a timer every 40 ms and update your canvas from there. Or is there a catch? – kuroi neko Commented Mar 5, 2015 at 5:23
3 Answers
Reset to default 5You just need to break the "synchronousness" of your for
loop as the browser is pleting all drawPixel
calls in the same repaint.
Instead, use requestAnimationFrame
to call a function once at the browser's natural repaint interval (this, instead of setTimeout
or similar). something similar to:
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
var counter = 0;
function run() {
drawPixel(0, 0, 0, 255, randomNumber(0, canvas.width), randomNumber(0, canvas.height));
counter++;
// If our counter is less than 10000, run again at the next repaint
if (counter < 10000) {
window.requestAnimationFrame(run);
}
}
function drawPixel(red, green, blue, alpha, x, y){
context.fillStyle = "rgba(" + red + ", " + green + ", " + blue + ", " + (alpha/255) + ")";
context.fillRect(x, y, 1, 1);
}
function randomNumber(min, max){
return Math.floor(Math.random()*(max-min+1)+min);
}
run();
<canvas height="100" width="100" id="canvas"></canvas>
The requestAnimationFrame
API can be used to allow the browser to decide when it's time to redraw. The problem you have to solve is that your JavaScript likely takes much longer than the 16 milliseconds or so between frames.
There are a variety of ways to handle this, but most of them are going to involve executing the draw mands in batches. Here is one possible solution:
// These variables would need to be outside the main function scope
var c = document.getElementById('canvas');
var ctx = c.getContext("2d");
var batchSize = 1000;
var currentItem = 0;
var lastItem = 1000000;
// Execute a batch of draw mands
function main() {
// Queue the next frame
window.requestAnimatoinFrame(main);
// Draw the pixels
for(var batchEnd = currentItem + batchSize; currentItem < batchEnd; currentItem++) {
drawPixel(ctx, ...);
}
}
// Queue the first frame
window.requestAnimationFrame(main);
Try an interval timer with a limited number updates in each iteration, as in:
$(document).ready(function(){
main();
});
function main(){
var c = document.getElementById('canvas');
var ctx = c.getContext("2d");
var pixelsPerTick = 1000;
// one thousand iterations each tick
window.setInterval(function(){
for(var x=0; x<pixelsPerTick; x++){
drawPixel(ctx, "200", "200", "200", "255", randomNumber(0, 1000), randomNumber(0, 600));
}
}, 1000 / 25); // 25 times per second
}
function drawPixel(context, red, green, blue, alpha, x, y){
context.fillStyle = "rgba(" + red + ", " + green + ", " + blue + ", " + (alpha/255) + ")";
context.fillRect(x, y, 1, 1);
}
function randomNumber(min, max){
return Math.floor(Math.random()*(max-min+1)+min);
}