How to Stack Two Same-Sized Canvas on Top of Each Other

How can I stack two same-sized canvas on top of each other?

Use CSS's position: absolute. Add the following CSS to your page:

canvas {
position: absolute;
top: 0;
left: 0;
}

This will put both canvases at the same spot: the topleft-most part.

You might want to put them in a wrapper element, which will need to be position: relative in order for its child elements to be. For example, your HTML will look something like this:

<div class="wrapper">
<canvas id="canvas1" width="400" height="300"></canvas>
<canvas id="canvas2" width="400" height="300"></canvas>
</div>

And your CSS will look like this:

.wrapper {
position: relative;
width: 400px;
height: 300px;
}

.wrapper canvas {
position: absolute;
top: 0;
left: 0;
}

Then position the wrapper div however you'd position the other stuff.

Placing two canvas elements on top of each other

Actually I am not sure why your version does not work (it should as-is!), but here's a version that uses your code and a bit of CSS to check the overlap. Read the comments in the CSS. When done, remove the extra code and enable .wrapper canvas { top: 0 } again.

Without the Javascript, I might add, I don't use Django.

However, it seems your JS new Image() has no size parameters and ctx.drawimage only has a location (0,0) but no (height,width) to work with.

So, height=0, width=0 yields nothing to overlap...

Forgot to mention: give both canvas a z-index so you can control which is on top.

UPDATE

Added Javascript and a third canvas to prove the code works as expected. Also inserted z-index per canvas as suggested before. Retrieving a few random pics from 'Lorem Picsum' to fill the canvas.

NOTICE that I use proper width/height parameters in my Javascript....

var canvas1 = document.getElementById("dorsal")          , ctx1 = canvas1.getContext("2d");var canvas2 = document.getElementById("dorsal-duplicate"), ctx2 = canvas2.getContext("2d");var canvas3 = document.getElementById("extra-img")       , ctx3 = canvas3.getContext("2d");
var background1 = new Image(512,256);var to_draw_on = new Image(512,256);var extra_img = new Image(512,256);
background1.src = "https://picsum.photos/512/512?random=0";to_draw_on.src = "https://picsum.photos/512/512?random=1";extra_img.src = "https://picsum.photos/512/512?random=2";
background1.onload = function(){ctx1.drawImage(background1,0,0);}to_draw_on.onload = function(){ctx2.drawImage(to_draw_on,0,0);}extra_img.onload = function(){ctx3.drawImage(extra_img,0,0);}
/* code to draw on the second canvas */
.wrapper {position: relative;width : 512px;height: 512px;}
.wrapper canvas {position: absolute;left: 0;/* top : 0; /* temporary disabled */
/*ADDED*/width: 100%; height: 100%; /* fill-parent */border: 2px dotted black;}
/* To check the overlap: - make #dorsal fill the top half of 512px - make #dorsal-duplicate fill the bottom half of 512px*/#dorsal { top : 0; height: 50%; background-color: green; z-index: 1;}#dorsal-duplicate { background-color: red; bottom: 0; height: 50%;
z-index: 2;}#extra-img { background-color: blue; left: 64px; bottom: 128px; height: 50%; width: 75%;
z-index: 3;}
<div class="wrapper">    <div class="pb-2 justify-content-center">        <h2>            <strong>Drawing test</strong>        </h2>        <p>removed width/height values from <canvas>, redundant.        <div class="justify-content-center">            <form enctype="multipart/form-data" method="post" action="">{% csrf_token %}                <div class="wrapper">                    <canvas id="dorsal"          ></canvas>                    <canvas id="dorsal-duplicate"></canvas>                    <canvas id="extra-img"       ></canvas>                </div>            </form>        </div>    </div></div>

How can I stack two same-sized canvas on top of each other, next to another canvas?

Use a container div that is positioned relative that will contain the canvas elements positioned absolute.

<div style="width: 810px; margin-left: auto; margin-right: auto;">
<canvas width="350" height="350" id="imageCanvas" style="float: left; border: 1px solid black;"></canvas>
<div class="container">
<canvas width="350" height="350" id="plotCanvas" style="margin-left: 6px; border: 1px solid black;"></canvas>
<canvas width="350" height="350" id="plotCanvas_BG" style="margin-left: 6px; border: 1px solid black;"></canvas>
</div>
</div>

CSS

.container {
display: inline-block;
position: relative;
float: left;
}

#plotCanvas,
#plotCanvas_BG {
position: absolute;
top: 0;
left: 0;
background-color: transparent;
}

#plotCanvas {
background-color: #fff;
}

JSFiddle Demo: https://jsfiddle.net/8c8csnzk/1/

How do I center two canvases on top of one another?

Make an outer container with text-align:center and position:relative, make an inner container with position:relative, put the canvases inside the inner container, remove left:0;top:0; on both canvases, and remove the position:absolute on the lower of the canvases. And make sure in the html that the lower canvas comes before the upper canvas, like you have.

#container {
text-align:center;
position:relative;
}

#inner_container{
position:relative;
}
#upper {
z-index: 1;
}
#lower {
position:absolute; z-index: 0;
}

http://jsfiddle.net/NW6Fx/

Edit: I believe the z-index property isn't needed if you do it this way. The order is just a matter of which canvas comes first in the html and which is position:relative.

Two html canvases on top of each other centered horizontally on browser window

The following works, and I'm including a snippet implementation below.

canvas#front, canvas#back {
position: absolute;
/* Use calc to make sure that browser without transform support
* (that therefore also dont support calc) don't
* actually move your elements. */
left: calc(50%);
top: calc(50%);
/* Don't forget to prefix. */
transform: translate(-50%,-50%);
z-index: 1;
}
canvas#back { z-index: 0; }

document.documentElement.style.overflow = 'hidden';window.addEventListener('resize', function(){resizeCanvas();}, true);
var sscale = 1.0;canvas_back = document.getElementById("canvas_back");stage2 = new createjs.Stage(canvas_back); stage2.autoClear = true;my_ticker2 = createjs.Ticker.on("tick",stage2); this.back = new createjs.Bitmap("http://i.imgur.com/VcDqpBW.png"); stage2.addChild(this.back); canvas_front = document.getElementById("canvas_front");stage = new createjs.Stage(canvas_front); stage.autoClear = true;createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED; createjs.Ticker.framerate = 120;my_ticker = createjs.Ticker.on("tick",stage); this.ob1 = new createjs.Bitmap("http://i.imgur.com/3toyiJo.png"); this.ob1.x=Math.floor(canvas_front.width/2); this.ob1.y = Math.floor(canvas_front.height/2);stage.addChild(this.ob1);resizeCanvas();
function resizeCanvas(){ var SCREEN_WIDTH = window.innerWidth; var SCREEN_HEIGHT = window.innerHeight;//window.screen.availHeight; console.log("SCREEN_WIDTH, SCREEN_HEIGHT, canvas_back.height", SCREEN_WIDTH, SCREEN_HEIGHT, canvas_back.height); ratio = (SCREEN_HEIGHT/canvas_back.height);
sscale = (sscale*ratio); console.log("ratio,sscale : ", ratio,sscale); stage.scaleX = sscale; stage.scaleY = sscale; canvas_back.width = Math.min(canvas_back.width*ratio); canvas_back.height = Math.min(canvas_back.height*ratio); console.log("canvas width/height : " , canvas_back.width, canvas_back.height); stage2.scaleX = sscale; stage2.scaleY = sscale; canvas_front.width = Math.min(canvas_front.width*ratio); canvas_front.height = Math.min(canvas_front.height*ratio); /*if(canvas_back.width > SCREEN_WIDTH) { */ console.log("canvas width bigger than screen width"); document.documentElement.scrollLeft = ((document.body.scrollWidth - document.body.clientWidth) / 2); document.body.scrollLeft = ((document.body.scrollWidth - document.body.clientWidth) / 2); /*}*/}
*{ margin: 0; padding: 0;}
html, body { height: 100%;}
#canvas_back, #canvas_front { position: absolute; left: 50%; top: 50%; -webkit-transform: translate(-50%, -50%); -moz-transform: translate(-50%, -50%); -ms-transform: translate(-50%, -50%); transform: translate(-50%, -50%);}
<!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>JS Bin</title>  <script type="text/javascript" src="https://code.createjs.com/createjs-2015.05.21.min.js"></script></head><body>  <canvas id="canvas_back" height="256" width="512"> asdf </canvas>  <canvas id="canvas_front" height="256" width="384"> asdf </canvas></body></html>

Stacking multiple canvases in HTML5

First step is to wrap your canvases into a container:

<div id="stack">
<canvas id="bg" width="500" height="500"></canvas>
<canvas id="lc" width="500" height="500"></canvas>
<canvas id="rc" width="500" height="500"></canvas>
<canvas id="ch" width="500" height="500"></canvas>
<div>

then properly apply CSS rules:

#stack {
position:relative;
}
#stack > canvas {
position:absolute;
left:0;
top:0;
}

z-index is not necessary here as the first canvas will be at the bottom etc.

Next is to implement a image loader handler as image loading is asynchronous. This is the reason why your image doesn't show as the image hasn't finished loading before calling drawImage() (at the time the code gets to the "fourth" element the image may be loaded depending on various factors such as cache, system performance etc - but this is in the category "random result":

var bg = document.getElementById('bg').getContext('2d'),
lc = document.getElementById('lc').getContext('2d'),
rc = document.getElementById('rc').getContext('2d'),
ch = document.getElementById('ch').getContext('2d'),
img = new Image();

img.onload = drawImgs; /// set handler
img.src = "image.png"; /// set url

function drawImgs() {
/// 'this' is the loaded image
bg.drawImage(this, 0,0);
lc.drawImage(this, 64,64);
rc.drawImage(this, 128,128);
ch.drawImage(this, 192,192);

/// continue rest of code here...
}

If you put your script at the bottom of your page then that's it. If in the header wrap your script in:

window.onload = function() {

... code above here...
}

Other considerations is that your image gets loaded properly. For that you can use the onerror and onabort handlers on the image object:

img.onerror = functionToHandleError;
img.onabort = functionToHandleAbort;

also these defined before setting the src property.



Related Topics



Leave a reply



Submit