This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 3 years ago.
I'm following a tutorial to learn about canvas, and I'm unstuck pretty early on.
Here is the code:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.lineWidth = 3;
context.strokeStyle = "blue";
context.lineJoin = "square";
context.strokeRect(10,10,200,200);
#canvas{
border: 1px solid black;
display: block;
width: 900px;
height: 600px;
margin: 0 auto;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML Canvas</title>
<link rel="stylesheet" href="stylesheet.css" type="text/css">
</head>
<body>
<canvas id="canvas"></canvas>
<script src="script.js" type="text/javascript"></script>
</body>
</html>
It seems like it should be pretty straight-forward, but it's not doing what I expect. Can anyone advise?
The height and width of the canvas should initially be set in HTML or via DOM properties, not CSS to avoid resizing.
From MDN:
Indeed, the element has only two attributes, width and
height. These are both optional and can also be set using DOM
properties. When no width and height attributes are specified, the
canvas will initially be 300 pixels wide and 150 pixels high. The
element can be sized arbitrarily by CSS, but during rendering the
image is scaled to fit its layout size: if the CSS sizing doesn't
respect the ratio of the initial canvas, it will appear distorted.
Because of this, your square was also being resized to the same size of the canvas and could no longer fit completely within it.
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.lineWidth = 3;
context.strokeStyle = "blue";
context.lineJoin = "square";
context.strokeRect(10,10,200,200);
#canvas{
border: 1px solid black;
display: block;
margin: 0 auto;
}
<canvas id="canvas" height="600" width="900"></canvas>
Related
I am practicing javascript and I am trying to make a game. I want the canvas element to be fullscreen, so I used percentages for the height and width attribute, but when I do, it doesn't behave like it normally does. When I run my debug code, it is supposed to make a box that is 50px by 50px, but the graphics look bigger than normal.
I've tried getting the canvas height and width in pixels, but that did not work. It does not report any error messages, but it is still too big.
<!DOCTYPE html>
<html>
<head></head>
<body>
<canvas id="canvas" style="height: 100%; width:100%;"></canvas>
</body>
<style>
html, body {width: 100%;
margin: 0;
height: 100%;
overflow: hidden;
position:fixed;}
</style>
<script>
var canvas = document.getElementById("canvas")
var c = canvas.getContext("2d")
c.fillStyle = "#FFFF00"
c.fillRect(50,50,50,50)
</script>
There are no error messages none appearing, but it is not sized correctly, and I can't figure out why it's not working.
It makes a difference if canvas size is set in CSS or using element attributes.
The canvas element size is set by its width and height attributes (as numbers). This sets the number of addressable pixels used to store the canvas drawing in memory. In the absence of width and height attributes, canvas element dimensions are set to 300 by 150 (pixels) by default.
CSS applied to the canvas can scale its dimensions using software interpolation of the canvas treated as an image. Just as a small image looks bigger when scaled to full screen, both the 300 by 150 pixel canvas and objects drawn within it (using canvas pixel coordinates) appear larger when blown up.
To make canvas coordinates match the screen size in pixels, set its width and height attributes to pixel number values. E.G.
var canvas = document.getElementById("canvas")
var c = canvas.getContext("2d")
c.fillStyle = "#FFFF00"
c.fillRect(50,50,50,50)
console.log( canvas.width, canvas.height);
alert( "fix?" )
canvas.style=""; // remove CSS scaling
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
c.fillStyle = "#FFFF00"
c.fillRect(50,50,50,50)
body {
width: 100%;
margin: 0;
height: 100%;
background-color: honeydew;
overflow: hidden;
position:fixed;
}
canvas {
background-color: silver;
}
<canvas id="canvas" style="height: 100%; width:100%;"></canvas>
I was testing html5 canvas element, and wish my canvas to be full screen in the display area. But I found if I set the canvas height to window.innerHeight, the scroll bar will be shown up. I tried and found need to set the height to 5 pixel less, the scroll bar will disappear, but unfortunately it left a white border below the canvas. If it's a div element, everything is fine.
The code I'm using to test is:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript">
function load() {
var o = document.getElementById('canvas');
if (o) {
o.width = window.innerWidth;
o.height = window.innerHeight - 5;
}
o = document.getElementById('div');
if (o) {
o.style.width = window.innerWidth + 'px';
o.style.height = window.innerHeight + 'px';
}
}
</script>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
body {
background-color: white;
}
#canvas {
background-color: blue;
}
#div {
background-color: green;
}
</style>
</head>
<body onload="load();">
<canvas id="canvas"></canvas>
<!--div id="div"></div-->
</body>
</html>
I've cleared the body margin and padding.
I test it on Chrome 8.0.552, and also it acts same on Firefox 3.6.13 but 4 pixel less is fine.
Anything I missed? Any suggestions will be really appreciated. Thanks a lot.
By default canvas, unlike div, is display: inline; so it gets set to vertical-align: baseline;. You can take either of the following approaches to make things naturally fill the window.innerHeight:
#canvas {
background-color: blue;
vertical-align: top;
}
Or:
#canvas {
background-color: blue;
display: block;
}
This question already has answers here:
Canvas is stretched when using CSS but normal with "width" / "height" properties
(10 answers)
Closed 5 years ago.
I have a canvas tag without width and height attributes. The canvas has inline width and height. Now when I apply linearGradient over it, it doesn't cover whole canvas. Demo:
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var gradient1 = ctx.createLinearGradient(0, 0, 150, 0);
gradient1.addColorStop(0, "#123456");
gradient1.addColorStop(1, "#654321");
ctx.fillStyle = gradient1;
ctx.fillRect(0, 0, 150, 100);
canvas {
border: 1px dotted red;
}
<canvas id="canvas" style="width: 150px; height: 100px;"></canvas>
Question1: Why doesn't whole 150px of canvas get covered? And if I add width="150" and height="100" attributes on canvas tag, why does it then fill whole canvas?
Question 2: In below script c.width returns 300px not 150px, why?
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
console.log(c.width);
console.log(c.height);
canvas {
border: 1px dotted red;
}
<canvas id="canvas" style="width: 150px; height: 100px;"></canvas>
Question3: Is this behavior due to something similar to svg viewBox?
I'm not sure why the inline styling isn't working, but if you change your canvas element to this:
<canvas id="canvas" width="150px" height= "100px;"></canvas>
Then the console logs the correct value and the gradient fills the canvas. :) I don't know why you can't use the other method, but I do know that everywhere I've seen I think everyone who uses the html canvas specifies the width and height in this way. (unless they specify it in the javascript)
Here's a pen of your working code: https://codepen.io/Awesomennjawarrior/pen/zwmmPY
Chrome and Firefox handle the following code fine when rendered at 100%.
<!DOCTYPE html>
<html>
<head>
<script type="application/x-javascript">
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(50,50,25,0,2*Math.PI);
ctx.stroke();
}
}
</script>
</head>
<body onload="draw();">
<canvas id="canvas" width="100" height="100">
<p>This example requires a browser that supports the
HTML5
<canvas> feature.</p>
</canvas>
</body>
</html>
But if someone magnifies my page a little, the canvas is sampled, not repainted. It's only a little ugly at 150%, but by the time the viewer reaches 300%, it will look very ugly:
How do I rewrite the code above so that the circle is repainted at the new magnification, not resampled?
This answer leads me to believe that it can be easily done. My attempt
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
</style>
<script type="application/x-javascript">
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.beginPath();
ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
ctx.canvas.height/4,0,2*Math.PI);
ctx.stroke();
}
}
</script>
</head>
<body onload="draw();">
<canvas id="canvas">
<p>This example requires a browser that supports the
HTML5
<canvas> feature.</p>
</canvas>
</body>
</html>
is no good. The circle is still resampled when the user magnifies. Can you do better?
(Chrome and Firefox behave differently when one magnifies. The effect I'm aiming for is for the circle to stay put with its center in the middle of the canvas and its radius a quarter of the window's height.)
Try doing the onload combined with the window resize event to redraw the canvas (zooming triggers the resize event):
window.addEventListener('resize', draw);
CANVAS REDRAWING
Example: http://jsfiddle.net/ksvyndwp/
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.beginPath();
ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
ctx.canvas.height/4,0,2*Math.PI);
ctx.stroke();
}
}
draw();
window.addEventListener('resize', draw);
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
<canvas id="canvas">
<p>This example requires a browser that supports the
HTML5
<canvas> feature.</p>
</canvas>
If you're still worried about pixelization at higher zoom levels, I'm afraid there's nothing you can do about it directly on the canvas, because canvas' pixels scale with the window, and although you enter the sub-pixel rendering stage, there's nothing you can do to make it look better.
CSS SCALING
However, if you don't want to do it purely inside the canvas, you can do a simple CSS transformation that will make your circle look correctly on all zoom levels. Setting the width and the height to 100% will keep the canvas (as in canvas, the DOM element; not the actual canvas.width and canvas.height) the size of the window, so it's basically "immune" to zooming.
See it here (actually works much better when zooming the jsfiddle: http://jsfiddle.net/406h7xm0/ than the Stack Overflow iframe):
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.beginPath();
ctx.arc(ctx.canvas.width/2, ctx.canvas.height/2,
ctx.canvas.height/4,0,2*Math.PI);
ctx.stroke();
}
console.log(window.innerWidth);
}
draw();
html, body {
width: 100%;
height: 100%;
margin: 0px;
}
canvas {
width: 100%;
height: 100%;
}
<canvas id="canvas"></canvas>
The final solution of what you're trying to do probably lies somewhere between the two approaches I've shown you.
I am trying to put an HTML5 canvas as the background of my web page. I can't get it to work no matter what I do. Does anyone know how? This is my current attempt:
<!DOCTYPE html>
<html>
<head> <title> Test </title> </head>
<style>
#bgcanvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index = -1;
}
</style>
<script type="text/javascript">
function fillCanvas(){
var bg = document.getElementById("bgcanvas");
var ctx = bg.getContext("2d");
ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 50, 50);
ctx = document.getElementById("screen").getContext("2d");
ctx.fillStyle = "#0000FF";
ctx.fillRect(0, 0, 500, 400);
}
</script>
<body onload="fillCanvas();">
<center>
<h1>Test Page</h1>
<canvas id="screen" width=720 height=480 style="background: black;">
Your browser sucks. Please upgrade.
</canvas>
</center>
</body>
<canvas id="bgcanvas" width=100 height=100> </canvas>
</html>
Thanks!
There are a few simple errors here you can adjust to make it work as pointed out in the various comments:
#bgcanvas {
/* ... rest not shown ... */
/* remove these unless you want the content to scale like an image:
width: 100%;
height: 100%;
*/
z-index: -1; /* change = to :. = is not supported in CSS for properties */
}
Move the canvas element inside the body tags:
...
<canvas id="bgcanvas" width=100 height=100> </canvas>
</body>
Tip: Increase the size to get better quality (you would currently scaling an "image" of 100x100 pixels to about the size of the window which will can give a poor result).
You can alternatively drop the CSS sizing and set the canvas size this way in your script before you draw anything to it:
var bg = document.getElementById("bgcanvas");
bg.width = window.innerWidth;
bg.height = window.innerHeight;