最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Update HTML Canvas In A Non Blocking Way - Stack Overflow

programmeradmin1浏览0评论

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
Add a ment  | 

3 Answers 3

Reset to default 5

You 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);
}
发布评论

评论列表(0)

  1. 暂无评论