forcing canvas update

17,794

Solution 1

Another thing you could do to allow the canvas to display before you do the longer task is begin FakeLoad after a short timeout:

    var canvas = document.getElementById('cnv');
    ctx = canvas.getContext('2d');

    ctx.fillStyle = "rgb(255, 0, 0)";
    ctx.fillRect(0,0,300,300);

    setTimeout(function() {
      FakeLoad();

      ctx.fillStyle = "rgb(0, 255, 0)";
      ctx.fillRect(0,0,300,300);
    }, 20); // 20 ms - should be enough to draw something simple

Solution 2

If I understand you correctly, there's no way to update a canvas in the same way that you may be able to re-render/paint in WPF or re-flow the HTML DOM.

This is because a canvas uses intermediate mode graphics. Essentially, the only thing that the canvas retains knowledge of is the pixels which make up the canvas. When you call draw rect or draw line, the pixels that make up the rectangle or line are added to the canvas and as far as the canvas is concerned, it forgets all about the draw rect or draw circle call and therefore we cannot refresh the canvas and get the same result.

If your looking for something that 'retains' knowledge of the graphics rendered into it, you could try SVG, this uses retained mode graphics. Essentially it has it's own DOM (heirachy of objects (circle, rect etc)), which are re-rendered each time a region is made dirty.

In short, this page is very good at helping you understand the difference between immediate mode graphics and retained mode graphics: http://msdn.microsoft.com/en-us/library/ie/gg193983(v=vs.85).aspx

All that said, if I'm misunderstanding your question, please accept my apologies!

Update

From the extra info in the question,

The reason why you never see the green square is because the main javascript thread is always busy with your five second loop. It never has any time to update the UI. To allow time for the canvas to update with your loading screen, you'll need to do all your loading asynchronously.

What sort of loading will you be doing? If it's images etc, you can grab them using $.ajax and jQuery. This will asynchronously get the images from their location and once the last image has been retrieved, you can then clear and repaint the canvas with your content.

I guess something like this:

<script type="text/javascript">  

    var ctx;

    function init()
    {
        var canvas = document.getElementById('cnv');
        ctx = canvas.getContext('2d');

        ctx.fillStyle = "rgb(255, 0, 0)";
        ctx.fillRect(0,0,300,300);

        FakeLoad(); 
    }

    function FakeLoad()
    {
        $.ajax({
          url: "www.foo.com/bar.jpg",
          success: function(data)
          {
              // Do something with the data (persist it)
              RenderApp();
          }
        });
    }

    function RenderApp()
    {
        // Rendering the rest of the application / game
        ctx.fillStyle = "rgb(0, 255, 0)";
        ctx.fillRect(0,0,300,300);
    }

</script>

Obviously this is kinda psudo-code, but hopefully it'll give you some idea!

let me know if you need any clarification!

Share:
17,794
David Burford
Author by

David Burford

Updated on June 26, 2022

Comments

  • David Burford
    David Burford almost 2 years

    Is there any way to force a canvas to update? I'd like to display a loading message but the game locks up loading before it displays. I feel like I need to tell the canvas to "draw now" before load function is called, but maybe there is a another way...

    EDIT:

    ok, just to be clear i've written a very small dirty script (best i can do in my tea break :P) to demonstrate what i'm trying to over come. Here:

    <html>
    <head>
        <title>test page</title>
    </head>
    
    <body onload="init();">
        <canvas id="cnv" width="300" height="300">
            canvas not supported.<br/>
        </canvas>
    </body>
    </html>
    
    <script type="text/javascript">  
    
        var ctx;
    
            function init()
        {
            var canvas = document.getElementById('cnv');
            ctx = canvas.getContext('2d');
    
            ctx.fillStyle = "rgb(255, 0, 0)";
            ctx.fillRect(0,0,300,300);
    
            FakeLoad();
    
            ctx.fillStyle = "rgb(0, 255, 0)";
            ctx.fillRect(0,0,300,300);
        }
    
        function FakeLoad()
        {
            var d = new Date();
            var start = d.getTime();
    
            while (new Date().getTime() - start < 5000)
            {
                //emulate 5 secs of loading time
            }
        }
    </script>
    

    now the idea is the script should draw a red square to show its "loading" and a green square when finished. but all you will see if you copy that into a html file is a pause of 5 seconds then the green appears, never red. In my head I wanted to have some command like ctx.Refresh(); after i draw the green square to tell it "update now! don't wait!" but judging from replies this is not the way to handle the problem.

    what should I do? :)

  • David Burford
    David Burford almost 12 years
    was not quite what I was after, but was still very interesting - thanks for the info!
  • David Burford
    David Burford almost 12 years
    brilliant answer and I learned alot from it! In this case i've gone for the setTimeout() method below because it was simplest with the kind of loading im doing (generating alot of procedural data, loading sprites, intialising databases, etc!) but i've also voted this up because I think its very relevent and useful. I do appreiciate your time :)
  • David Burford
    David Burford almost 12 years
    accepted as answer - simple and effective, just delaying a little bit gives canvas a chance to update so perfect for single static loading screens - thanks :)
  • Andy
    Andy almost 12 years
    No worries! Thanks for the feedback! :)