0

I have reviewed many canvas z-index posts here, including:

HTML5 Canvas layer issue
Multi Layer Canvas HTML5
html5 - canvas element - Multiple layers

but I am not finding the answer to my issue.

I am trying to simply place one canvas directly behind another canvas. When a user clicks on the canvas, it will change the stacking order. But instead of the canvases being behind and in front of each other, they can both be seen, one on top, and one beneath it (not behind it) (see https://i.stack.imgur.com/ALWM7.jpg).

HTML and CSS:

<div id="preview" style="visibility:hidden;">
  <canvas id="cOriginal" width="2" height="1" onclick="clickCompare()" style="position:relative; z-index:2; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
  <canvas id="cPreview" width="2" height="1" onclick="clickCompare()" style="position:relative; z-index:1; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>    
  <canvas id="cSave" width="2" height="1" style="position:relative; z-index:0; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
</div>      

Thank you very much!

EDIT: Updating my question to show the current problem.

HTML:

<div id="preview" style="visibility:hidden; position:relative;">
  <canvas id="cOriginal" width="2" height="1" onclick="clickCompare()" style="position:absolute; z-index:2; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
  <canvas id="cPreview" width="2" height="1" onclick="clickCompare()" style="position:absolute; z-index:1; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>    
  <canvas id="cSave" width="2" height="1" style="position:absolute; z-index:0; border-style:solid; border-color: #C0C0C0 #C0C0C0 #606060 #606060;"></canvas>
</div>

CSS (centering code):

<style>
  #cOriginal, #cPreview, #cSave { max-width: 100%; display: block; margin: auto; left: 0; right: 0; margin-left: auto; margin-right: auto; }     
</style> 

The canvases are now layered and centered. But everything following the canvases has broken. See https://i.stack.imgur.com/UlD1E.jpg. Thank you!

TonyLuigiC
  • 185
  • 1
  • 2
  • 13
  • Why not just use one canvas and draw the images in the order you want. Its is quicker (no need to force a reflow, and uncontrolled compositing) and the code much simpler. – Blindman67 Feb 16 '18 at 01:33
  • Thank you for the comment, but that won't work efficiently here. The code will be used to display an original image vs an edited image. The editing code iterates through the image to read it, makes changes to the R, G. B, A arrays,, and then iterates again to redraw the image. On a large image this can be time consuming. There's no point in reproducing all that if the images can be drawn once followed by simply swapping z-index order. – TonyLuigiC Feb 16 '18 at 01:51
  • Just keep the edited image as a off screen canvas. Overall you will get a performance increase. You can draw a canvas to a canvas just like you draw an image. `ctx.drawImage(canvas2,0,0)` – Blindman67 Feb 16 '18 at 09:08
  • @Blindman67 That's interesting, thank you for pointing it out. What would be the preferred way to keep "canvas2" off screen? – TonyLuigiC Feb 17 '18 at 07:48

1 Answers1

1

First time answering on SO, but I believe I have the answer to your question.

I redid the HTML and JavaScript to be as simplistic as possible, since your question seems to be at the root of it all, asking for help on changing canvas layering, so I did it as simply as I could think of, here is the code, followed by a link to the codepen:

<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Canvas Layering</title>
</head>

<body>
    <div style="position: relative;">
        <canvas id="layer1" width="100" height="100" 
            style="position: absolute; left: 0; top: 0; z-index: 0; background-image: url(https://static.pexels.com/photos/158780/leaf-nature-green-spring-158780.jpeg);" onclick="ChangePicture(1)"></canvas>
        <canvas id="layer2" width="100" height="100" 
            style="position: absolute; left: 0; top: 0; z-index: 1; background-image: url(https://static.pexels.com/photos/54320/rose-roses-flowers-red-54320.jpeg);" onclick="ChangePicture(2)"></canvas>
        <canvas id="layer3" width="100" height="100" 
            style="position: absolute; left: 0; top: 0; z-index: 2; background-image: url(https://static.pexels.com/photos/5412/water-blue-ocean.jpg);" onclick="ChangePicture(3)"></canvas>
    </div>
</body>

<script>

    function ChangePicture(layerNumber) {
        if (layerNumber === 1) {
            document.getElementById("layer1").style.zIndex = "0";
            document.getElementById("layer2").style.zIndex = "2";
            document.getElementById("layer3").style.zIndex = "1";
        } else if (layerNumber === 2) {
            document.getElementById("layer1").style.zIndex = "1";
            document.getElementById("layer2").style.zIndex = "0";
            document.getElementById("layer3").style.zIndex = "2";
        } else if (layerNumber === 3) {
            document.getElementById("layer1").style.zIndex = "2";
            document.getElementById("layer2").style.zIndex = "1";
            document.getElementById("layer3").style.zIndex = "0";
        } else {
            console.log("Failed.");
        }
    }

</script>

</html>

https://codepen.io/levi_blodgett/pen/KQyWoR

If you want to change what picture starts as the default, simply change the z-index for the styling inside the html.

Levi Blodgett
  • 354
  • 1
  • 3
  • 16
  • That did successfully place the 3 canvases on top of each other. Unfortunately, they were on the far left side of the screen, instead of being centered. But, I think I may have that worked out. I'll let you know. Thanks! – TonyLuigiC Feb 16 '18 at 00:45
  • Okay, so that solved the layering issue, only problem was that everything was positioned on the left, I resolved that with CSS code. The only problem is, the page stops dead at the bottom of the canvases, the items that appear below the canvas are appearing BEHIND it. If you (or anyone) has a suggestion to resolve that issue, please let me know! – TonyLuigiC Feb 16 '18 at 01:44
  • Please take a look at https://imgur.com/AHG59zd that will explain it better than I can. In a nutshell, the controls under the image, and I suspect the footer as well, are now BEHIND the canvases. – TonyLuigiC Feb 16 '18 at 02:54
  • I figured out what you meant once I looked up at your update, what you want to do is give it a margin below, since it is an absolute position, that means it ignores other elements and their spacings, what you could do, however, is increase the margin surrounding it to space it properly, i.e: position: absolute; left: 50%; top: 500px; That would allow you to space everything properly. – Levi Blodgett Feb 16 '18 at 03:02
  • So there's nothing really wrong with my code, this is just the result of having to use "absolute" for the layers? Also, won't I now have to re-position **everything** below the canvases? – TonyLuigiC Feb 16 '18 at 03:22
  • i mean, it shouldn't terribly difficult, it is just the cost of wanting to layer z-indexes, unless you find another way perhaps with a relative div or something. – Levi Blodgett Feb 16 '18 at 03:57
  • When a user opens their own image, height will not be a constant, so that means having to read the height and then dynamically change the margin-top:(number of pixels) of every element that follows. A bit of a headache. I'm still hoping someone will have a solution that doesn't create a new problem. In any case, thank you very much for your time, I appreciate it. – TonyLuigiC Feb 16 '18 at 07:37
  • At the moment, I'm using visibility and display to hide and show the canvases, and it's working fine. So that part of the problem is solved. However, I have some plans for canvases which will **require** them to be layered, **so I'm still hoping someone will know a way of layering canvases _without_ throwing off formatting for the remainder of the page.** – TonyLuigiC Feb 17 '18 at 07:51