1

I'm trying to build a beautiful graphic image (animated!), calculating a color for each pixel on a screen and then showing all the pixels at once. So, I'm using a putImageData function on a loop.

But for some reason it doesn't work. Only the last iteration can be seen on a screen (after 1-2 sec).

I've tried to use FillRect after each iteration, but it didn't help.

<html>
<head>
    <title>Full Screen Canvas Test</title>
    <style>
        html, body {
            overflow: hidden;
            margin: 0;
        }
    </style>
</head>
<body>

    <canvas id="mainCanvas"></canvas>

    <script>
        (function () {
            canvas = document.getElementById('mainCanvas');
            ctx = canvas.getContext("2d");              
            canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
            canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
            step = 1;

            function doit() {   
                rx = Math.floor(Math.random()*canvas.width);
                ry = Math.floor(Math.random()*canvas.height);
                gx = Math.floor(Math.random()*canvas.width);
                gy = Math.floor(Math.random()*canvas.height);
                bx = Math.floor(Math.random()*canvas.width);
                by = Math.floor(Math.random()*canvas.height);                                               

                var canvasData = ctx.createImageData(canvas.width, canvas.height);

                for (var i = 0; i < canvas.width; i+=step) {
                    for (var j = 0; j < canvas.height; j+=step) {
                        po = 2;
                        rd = Math.floor(Math.sqrt(Math.pow(rx - i, po)+Math.pow(ry - j, po)));
                        gd = Math.floor(Math.sqrt(Math.pow(gx - i, po)+Math.pow(gy - j, po)));
                        bd = Math.floor(Math.sqrt(Math.pow(bx - i, po)+Math.pow(by - j, po)));
                        maxd = 1400;
                        r = Math.floor((1 - rd/maxd)*255);
                        g = Math.floor((1 - gd/maxd)*255);
                        b = Math.floor((1 - bd/maxd)*255);

                        var index = (i + j * canvas.width) * 4;

                        canvasData.data[index + 0] = r;
                        canvasData.data[index + 1] = g;
                        canvasData.data[index + 2] = b;
                        canvasData.data[index + 3] = 255;


                    }
                }

                ctx.putImageData(canvasData, 0, 0);

            }       

            doit();
            doit();
            doit();
            doit();
            doit();
            doit();
            doit();
            doit();
        })();
    </script>
</body>

  • When I run your code I see an entire canvas filled with varying colours (like a gradient from red to green) is this not what you expect? – Nick Parsons Dec 01 '18 at 03:02
  • I expect it to be done 8 times, not 1. – Roman Nastenko Dec 01 '18 at 03:03
  • Adding a wait interval of 1000 after each iteration doesn't help... – Roman Nastenko Dec 01 '18 at 03:04
  • If you comment out all of the `doit()` method calls and leave the first one, it gives a different result, then if you have two `doit()` calls, you get a different result again. So, it seems that it is happening 8 times – Nick Parsons Dec 01 '18 at 03:06
  • Yes. But only the last iteration of `doit()` is visualized.. edit: I expect to see 8 different images in a row, but I can see only the last one. – Roman Nastenko Dec 01 '18 at 03:07

1 Answers1

0

You need to use setInveral() to call your doit() function multiple times with a time delay between each call. The issue with your current method is that it is running all your doit() results in one iteration, and then displaying the last one only as it overwrites your previous results. Thus, you need to display the results of each sequentially.

See working example below:

<html>

<head>
  <title>Full Screen Canvas Test</title>
  <style>
    html,
    body {
      overflow: hidden;
      margin: 0;
    }
  </style>
</head>

<body>

  <canvas id="mainCanvas"></canvas>

  <script>
    (function() {
      canvas = document.getElementById('mainCanvas');
      ctx = canvas.getContext("2d");
      canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
      canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      step = 1;

      function doit() {
        rx = Math.floor(Math.random() * canvas.width);
        ry = Math.floor(Math.random() * canvas.height);
        gx = Math.floor(Math.random() * canvas.width);
        gy = Math.floor(Math.random() * canvas.height);
        bx = Math.floor(Math.random() * canvas.width);
        by = Math.floor(Math.random() * canvas.height);

        var canvasData = ctx.createImageData(canvas.width, canvas.height);

        for (var i = 0; i < canvas.width; i += step) {
          for (var j = 0; j < canvas.height; j += step) {
            po = 2;
            rd = Math.floor(Math.sqrt(Math.pow(rx - i, po) + Math.pow(ry - j, po)));
            gd = Math.floor(Math.sqrt(Math.pow(gx - i, po) + Math.pow(gy - j, po)));
            bd = Math.floor(Math.sqrt(Math.pow(bx - i, po) + Math.pow(by - j, po)));
            maxd = 1400;
            r = Math.floor((1 - rd / maxd) * 255);
            g = Math.floor((1 - gd / maxd) * 255);
            b = Math.floor((1 - bd / maxd) * 255);

            var index = (i + j * canvas.width) * 4;

            canvasData.data[index + 0] = r;
            canvasData.data[index + 1] = g;
            canvasData.data[index + 2] = b;
            canvasData.data[index + 3] = 255;

          }
        }

        ctx.putImageData(canvasData, 0, 0);
      }
      
      // Use setInterval to display the images sequentially (every 1000 m/s (every second))
      let showImg = setInterval(doit, 1000);
    })();
  </script>
</body>
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64