Using 100% does not make my canvas fill the window [duplicate] - javascript

This question already has answers here:
Getting wrong canvas height
(2 answers)
Closed 7 years ago.
I'm trying to make my canvas fill up the entire window. Setting the width and height to 100% isn't working at all. Instead, it's making it 100px by 100px. Why would this be happening, and how can I achieve my effect?
Here's a fiddle that basically shows my problem. Thank you!
https://jsfiddle.net/t04n6q9y/1/
<body height="100%" width="100%">
<canvas id="myCanvas" width="100%" height="100%"></canvas>
</body>

The width and height are attributes and don't support % they need to be absolute. If you give 100% width and height in CSS, your canvas will not scale to 100% instead it will be zoomed to 100%. I would suggest the following way to achieve 100% width and height:
You need to calculate width in javascript and then apply it, Fiddle
js:
var height = window.innerHeight;
var width = window.innerWidth;
var canvas = document.getElementById('myCanvas');
canvas.height = height;
Snippet:
var height = window.innerHeight;
var width = window.innerWidth;
var canvas = document.getElementById('myCanvas');
canvas.height = height;
canvas.width = width;
var context = canvas.getContext('2d');
context.fillStyle = "#FFFF00";
context.fillRect(0, 0, canvas.width, canvas.height);
body {
margin: 0px;
padding: 0px;
background-color: #00000F
}
canvas {
padding: 0;
margin: auto;
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<body>
<canvas id="myCanvas"></canvas>
</body>

You should be doing this with CSS rather than HTML tag attributes. By declaring a CSS class, you will be able to apply this same style to anything else you may want to fullscreen. It also separates the DOM logic from the styling logic.
Here's how I would do it:
HTML:
<canvas class="fullscreen"></canvas>
CSS:
canvas.fullscreen {
width: 100vw;
height: 100vh;
}
The "vw" and "vh" units represent percentage of View Width and View Height, respectively. Using these units will ensure your canvas fills the entire viewport regardless of the size of its parent elements.

All that needed to be done was for the canvas to have an element to expand in.
HTML:
<body>
<div id="canback">
<canvas id="myCanvas"></canvas>
</div>
</body>
CSS:
body {
margin: 0px;
padding: 0px;
background-color: #00000F
}
#canback {
height: 100%;
width: 100%;
margin: 0 auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#myCanvas {
background:#f4f4f4;
height:100%;
width: 100%;
padding: 0;
margin: 0 auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
Here is a Fiddle
I hope this helped. :D

Related

How would I scale div content with its size using Javascript?

I have a div that is centered on the page and scales with viewport in a way that its aspect ratio (16:9) is maintained. The problem is, I want the font and content inside to scale with the div as it resizes, as well. Vmin works, for the most part, without issue. It would work perfectly if the aspect ratio of the div is 1:1 because vmin checks for the lesser value between height and width of the viewport directly, and you can't set a custom aspect ratio.
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color:white;
}
.wrapper {
width: 95vw;
height: calc(95vw * 9/16);
max-height: 95vh;
max-width: calc(95vh * 16/9);
background: center;
background-color: blue;
background-size:contain;
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#lorem {
color: aqua;
font-size:10vmin;
text-align:center;
position:absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
margin:auto;
}
</style>
</head>
<body>
<div class="wrapper">
<p id="lorem">
This text should scale with div only.
</p>
</div>
</body>
</html>
https://jsfiddle.net/Addictorator/70fq44sv/2/
Resize the window vertically to see what I'm talking about.
I don't believe there is a way in pure css (but if there is, that would be most preferred), but I think it is possible in javascript using an event listener onresize of the div and scaling each element down separately by a ratio comparing original (or previous - storing it as a var) div height/width to current div height/width. Or it could try and replicate vmin behavior but with height set to a ratio in a way 16:9 is considered instead of 1:1, like what was done on div using css above. I would prefer pure js and no jquery if at all possible. I've tried doing this myself, but I'm rather amateurish when it comes to javascript.
Thanks in advance!
Please see a working codepen here.
The solution is quite simple. On window resize we return the clientHeight of the parent. by dividing the returned value we achieve an integer that is usable as a font-size. We then assign this to the p element.
I hope this solves your problem.
//assigns font-size when document is ready
document.onreadystatechange = () => {
if (document.readyState === 'complete') {
var wrapperHeight = document.getElementById('wrapper').clientHeight;
var relativeFontSize = wrapperHeight / 10 + 'px'; //change 10 to any integer for desired font size
document.getElementById("lorem").style.fontSize = relativeFontSize;
}
};
//then on window resize
window.onresize = function(event) {
var wrapperHeight = document.getElementById('wrapper').clientHeight;
var relativeFontSize = wrapperHeight / 10 + 'px'; //change 10 to any integer for desired font size
document.getElementById("lorem").style.fontSize = relativeFontSize;
};
body {
background-color:white;
}
#wrapper {
width: 95vw;
height: calc(95vw * 9/16);
max-height: 95vh;
max-width: calc(95vh * 16/9);
background: center;
background-color: blue;
background-size:contain;
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
font-size:60px;
}
#lorem {
color: aqua;
text-align:center;
position:absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
margin:auto;
}
<div id="wrapper">
<p id="lorem">
This text should scale with div only.
</p>
</div>

to resize the window to keep the div in the center using javascript

How can I correct my code to keep the div in the center of the window when it is resized:
window.addEventListener("resize",handleResize,false);
function handleResize(){
var newwidth = window.innerWidth.value;
var newheight = window.innerHeight.value;
window.resizeTo(newwidth , newheight);
}
There is definitely no need for javascript coding for that: e.g. use auto margins with a parent container that has absolute or relative positioning instead.
You actually do not need to use JavaScript to achieve this. It can be done with pure CSS.
If you still want to use JS, you basically just have to get the window.innerWidth and window.innerHeight and divide them by 2. This will give you a point in the exact center of the window. Then just subtract half of the width from your element and half of the height to offset the left and top position of the element you want to center. This is necessary, because the positioning is relative to the upper left corner of the document.
When your using a CSS solution with an absolute positioned element make sure that the parent elements position is set to relative.
Here is an example with both, JS and CSS centering.
var centerDiv = document.querySelector('.center-js'),
showHideBtn = document.querySelector('.show-hide'),
winW = 0,
winH = 0;
// this is just the button click handler.
showHideBtn.addEventListener('click', function() {
if (centerDiv.style.opacity != 0) {
centerDiv.style.opacity = 0;
this.textContent = "Hide CSS centering";
} else {
centerDiv.style.opacity = 1;
this.textContent = "Show CSS centering";
}
}, false);
// here is the win resize handler;
function windowResize () {
winW = window.innerWidth;
winH = window.innerHeight;
centerDiv.style.top = (winH/2) - (centerDiv.clientHeight/2) + 'px';
centerDiv.style.left = (winW/2) - (centerDiv.clientWidth/2) + 'px';
}
window.addEventListener("resize", windowResize, false);
windowResize();
centerDiv.style.opacity = 1;
html {
position: relative;
min-height: 100%;
font-family: sans-serif;
color: white;
}
div {
text-align: center;
line-height: 200px;
vertical-align: middle;
}
.center-js {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
background: black;
opacity: 1;
transition: opacity .5s linear 0s;
z-index: 1020;
}
.center-css {
position: absolute;
top: 50%;
left: 50%;
margin-left: -100px;
margin-top: -100px;
width: 200px;
height: 200px;
background: red;
z-index: 1010;
}
<button class="show-hide">Show CSS centering</button>
<div class="center-js">JS centering</div>
<div class="center-css">CSS centering</div>

Inscribe and center an image within a frame

Given a div of arbitrary aspect ratio, what's the best way to place and style an image (also with an arbitrary aspect ratio) inside such that:
It is both inscribed and centered
Its dimensions and position are set using relative values so that the image will remain inscribed and centered automatically when the frame is uniformly scaled (javascript should only be required when the image is initially inserted, or if the frame's aspect ratio changes)
Extra markup is minimized
Here's the result we want:
Here's a fiddle template, which is just:
Markup
Should pillarbox
<div class="frame">
<img src="http://www.placekitten.com/200/300" />
</div>
Should letterbox
<div class="frame">
<img src="http://www.placekitten.com/300/200" />
</div>
CSS
.frame {
width: 200px;
height: 200px;
border: 2px solid black;
margin: 10px 0px 100px 0;
}
You can try something like this: updated fiddle
.frame {
width: 200px;
height: 200px;
border: 2px solid black;
margin: 10px 0px 100px 0;
position: relative; /* added */
}
img {
max-height: 100%;
max-width: 100%;
position: absolute;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
By combining Adrift's css
.frame {
width: 400px;
height: 400px;
border: 2px solid black;
margin: 10px 0px 100px 0;
position: relative; /* added */
}
img {
max-height: 100%;
max-width: 100%;
position: absolute;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
with javascript
var inscribe = function(img, frame) {
var imgRatio = img.width / img.height;
var frameRatio = frame.offsetWidth / frame.offsetHeight;
if (imgRatio > frameRatio) { // image is wider than frame; letterbox
img.style.width = '100%';
img.style.height = 'auto';
} else { // image is taller than frame; pillarbox
img.style.width = 'auto';
img.style.height = '100%';
}
}
all requirements can be satisfied.
http://jsfiddle.net/PBPkh/4/
Well you can achieve that with background-images too, if you can get rid of the <img /> elements.
There is a css property on background-size called contain, that does the job:
.background{
background-size: contain;
}
And if you wish to center the image just add this:
background-position: center center;

Preserving part of a canvas

When drawing on a HTML5 canvas element, is it possible to leave part of it untouched? Can you take part of the image, and then redraw that part if its not directly possible?
The only solution I have thought of is to draw to a seprate, smaller canvas and then copy that over to the main canvas. Is this a feasible approach?
I wish to draw a game scene while preserving the ui. Unfortunately, the draw order is not known in advance.
I guess you're looking for .clip: http://jsfiddle.net/eGjak/122/.
ctx.rect(100, 50, 200, 100); // make a region
ctx.clip(); // constrain to that region
ctx.drawImage($("img").get(0), 0, 0); // draw image
Draw the UI on another canvas. You can layer canvas elements if need be.
HTML
<div id="gameframe">
<canvas id="game-ui"></canvas>
<canvas id="game"></canvas>
</div>
CSS
#gameFrame { position: relative; width: 800px; height: 800px;}
#game-ui { position: absolute; z-index: 10; bottom: 0; left; 0; height: 50px; width: 100%;}
#game { position: absolute; z-index: 5; height: 100%; width: 100%;}
Yields
-------------------------------------------------------
- -
- -
- -
- <canvas id="game"> -
- -
- -
- -
- -
-------------------------------------------------------
- <canvas id="game-ui"> -
-------------------------------------------------------
When creating Canvas games i've always layered the GUI on top of the game canvas.
#ui{position: fixed; margin-left: auto; margin-right: auto; z-index: 1000; width: 500; height: 500}
#game{position: fixed; margin-left: auto; margin-right: auto; z-index: 999}
<div id="ui"><!--UI elements--></div>
<canvas id="game" width="500" height="500"></canvas>
Obviously you can layer another canvas on top, or build the UI using html elements.

Changing imsg src from one to another shows a 'flick'

I have an img elment with an image. For instance:
<img id='imageWord' src=images\Card.png onclick='changeImage();'>
When user clicks on it, I want to make a fadeOut, change its src to another image, and then fadeIn.
function changeImage()
{
$('#ImageWord').animate({opacity:0})
.queue(function(){
$(this).attr("src", '');
replaceImage('#ImageWord', 'images\newImage.png');
$(this).dequeue()
})
.animate({opacity:1});
}
var MAX_HEIGHT = 260;
var MAX_WIDTH = 260;
function keepAspectRatio(temp, target, url)
{
$(target).removeAttr('style');
// Get height and width once loaded
var realHeight = temp.height;
var realWidth = temp.width;
// Get how much to divide by (1 if image fits in dimensions)
// Get rid of ", 1" if you just want everything to be either
// MAX_HEIGHT tall or MAX_WIDTH wide
var factor = Math.max(realHeight/MAX_HEIGHT, realWidth/MAX_WIDTH, 1);
realHeight /= factor;
realWidth /= factor;
// Set the target image's source, height and width
$(target).attr("src", url).css({height: realHeight, width: realWidth});
if (realWidth != MAX_WIDTH)
{
var offsetX = (MAX_WIDTH - realWidth ) / 2;
var sum = parseFloat($(target).css("left").replace("px", "")) + offsetX;
$(target).css("left", sum);
}
if (realHeight != MAX_HEIGHT)
{
var offsetY = (MAX_HEIGHT - realHeight) / 2;
var sum = parseFloat($(target).css("top").replace("px", "")) + offsetY;
$(target).css("top", sum);
}
}
function replaceImage($target, url) {
$("<img>").load(function() {
keepAspectRatio(this, $target, url);
}).attr("src", url);
}
Sometimes I see the following:
Card.png fadeOut.
No image (0.1 seconds)
Card.png again (0.1 seconds).
newImage.png fadeIn.
I want to avoid step 3.
Any advice?
As this example shows, you could put all your images at start in display none. Than use jQuery fadeIn and fadeOut to show the right image. All you need is to put them in an position:relative div and define them as position:absolute :
<div class="slideshow" style="position: relative; ">
<img src="http://cloud.github.com/downloads/malsup/cycle/beach1.jpg" width="200" height="200" style="position: absolute; top: 0px; left: 0px; width: 200px; height: 200px; z-index: 5; opacity: 0; display: none; ">
<img src="http://cloud.github.com/downloads/malsup/cycle/beach2.jpg" width="200" height="200" style="position: absolute; top: 0px; left: 0px; width: 200px; height: 200px; z-index: 5; opacity: 0; display: none; ">
<img src="http://cloud.github.com/downloads/malsup/cycle/beach3.jpg" width="200" height="200" style="position: absolute; z-index: 6; top: 0px; left: 0px; display: block; width: 200px; height: 200px; opacity: 1; ">
<img src="http://cloud.github.com/downloads/malsup/cycle/beach4.jpg" width="200" height="200" style="position: absolute; top: 0px; left: 0px; width: 200px; height: 200px; z-index: 5; opacity: 0; display: none; ">
<img src="http://cloud.github.com/downloads/malsup/cycle/beach5.jpg" width="200" height="200" style="position: absolute; top: 0px; left: 0px; width: 200px; height: 200px; z-index: 5; opacity: 0; display: none; ">
</div>
http://jquery.malsup.com/cycle/basic.html
Supposing you have more that 2 pictures to show (as a slideshow) You could try using two images, one on top of the other. One is the image you are actually displaying, the other is the one you need to show when the first fades.
This way, you can fade the first, showing the bottom one. When the fade animation is ended you place it (callback) under the other one and change its src. There will be no flickering, as you load it in the background.
If you have only 2 images, then the fading is enough to cycle between the images.
Another solution that may solve your problem is to preload your images and store them in the cache. If i'm not wrong, it could solve the problem.
Sorry I provide no code, but I'm at work.... anyway if you need more details tell me.

Categories