Search code examples
javascripthtmlcanvasz-indextransparency

Overlayed HTML Canvas Elements


I have a WWWeb page with stacked <canvas> elements. The goal is to draw something persistent in the lower canvas and draw, clear, and redraw, repeatedly, in the upper canvas. According to w3.org and this StackOverflow article (How do I make a transparent canvas in html5?), canvas elements are, by default, transparent. What I am seeing is that not only are they not transparent, but that overlaying via z-index is not working. Here's a "vanilla" version of the page's code (complete and used to generate the images):

    <html>
    <head>
        <title>Canvas Stack</title>
        <script>
            function doStuff() {
                drawStuff(document.getElementById("lowerCanvas"), 0, 1);
                drawStuff(document.getElementById("upperCanvas"), 1, 0);
            }
            function drawStuff(cvs, p0X, p1X) {
                var ctx = cvs.getContext("2d");
                ctx.clearRect(0, 0, cvs.width, cvs.height);
                ctx.strokeStyle = cvs.style.color;
                ctx.beginPath();
                ctx.moveTo(p0X * cvs.width, 0);
                ctx.lineTo(p1X * cvs.width, cvs.height);
                ctx.stroke();
            }
        </script>
    </head>
    <body onload="doStuff();" style="border:solid;">
        <canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;" />
        <canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:inherit;top:0;width:300px;z-index:1;" />
    </body>
    </html>

and here's the result:

enter image description here

If I swap the order of the canvas elements

    <canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:inherit;top:0;width:300px;z-index:1;" />
    <canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;" />

the result is

enter image description here

It seems as if the z-index has been ignored and that the order of declaration has primacy.

What I want is

enter image description here

(synthetic image)

The behavior is identical in Chrome, Edge, Firefox, and Internet Explorer under Windows 10. That makes me confident that I'm just missing some detail rather than experiencing an anomaly. However, I'm getting a flattened forehead from whacking my head against a wall and would really appreciate some guidance, here.

Thank you, all!

Some notes (maybe irrelevant; maybe not):

  • style="position:absolute;... (without the left and top entries) seems to do the same thing as style="left:0;position:absolute;top:0;...
  • In similar fashion, style="position:inherit;... is probably necessary if the canvas is to reside within a table's <td> and that <td> is other than the first one in a <tr>.

Solution

  •     <html>
        <head>
            <title>Canvas Stack</title>
            <script>
                function doStuff() {
                    drawStuff(document.getElementById("lowerCanvas"), 0, 1);
                    drawStuff(document.getElementById("upperCanvas"), 1, 0);
                }
                function drawStuff(cvs, p0X, p1X) {
                    var ctx = cvs.getContext("2d");
                    ctx.clearRect(0, 0, cvs.width, cvs.height);
                    ctx.strokeStyle = cvs.style.color;
                    ctx.beginPath();
                    ctx.moveTo(p0X * cvs.width, 0);
                    ctx.lineTo(p1X * cvs.width, cvs.height);
                    ctx.stroke();
                }
            </script>
        </head>
        <body onload="doStuff();" style="border:solid;">
        <div style="position:relative;min-height:200px">
            <canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:absolute;top:0;width:300px;z-index:0;"></canvas>
            <canvas id="upperCanvas" style="color:blue;height:200px;left:0;position:absolute;top:0;width:300px;z-index:1;"></canvas>
        </body>
        </html>

    You need to close your canvas elements explicitly. Simply close it with:

    <canvas id="lowerCanvas" style="color:red;height:200px;left:0;position:inherit;top:0;width:300px;z-index:0;"></canvas>
    

    instead of the embedded close "/>"

    I also enclosed them in a div and used position:absolute so that they actually overlap...