103

i would like to make a rectangular canvas to simulate a progress bar but it seems when i set the width and height of a canvas to 100%, it doesn't really make it as high and as wide as parent

please see example below
http://jsfiddle.net/PQS3A/

Is it even possible to make non-squared canvas? I don't want to hardcode the height and width of canvas, because it should change dynamically when viewed in bigger or smaller screen, including mobile devices

Phrogz
  • 296,393
  • 112
  • 651
  • 745
user1118019
  • 3,819
  • 8
  • 40
  • 46

3 Answers3

179

Here's a working example fixing the problems:

http://jsfiddle.net/PQS3A/7/

You had several problems with your example:

  1. A <div> does not have height or width attributes. You need to set those through CSS.
  2. Even if the div were sized correctly, it was using the default position:static, which means that it is NOT the positioning parent of any children. If you want the canvas to be the same size as the div, you must set the div to position:relative (or absolute or fixed).
  3. The width and height attributes on a Canvas specify the number of pixels of data to draw to (like the actual pixels in an image), and are separate from the display size of the canvas. These attributes must be set to integers.

The example linked to above uses CSS to set the div size and make it a positioned parent. It creates a JS function (shown below) to both set a canvas to be the same display size as its positioned parent, and then adjusts the internal width and height properties so that is has the same number of pixels as it shows.

var canvas = document.querySelector('canvas');
fitToContainer(canvas);

function fitToContainer(canvas){
  // Make it visually fill the positioned parent
  canvas.style.width ='100%';
  canvas.style.height='100%';
  // ...then set the internal size to match
  canvas.width  = canvas.offsetWidth;
  canvas.height = canvas.offsetHeight;
}
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 1
    oh wow, i didn't chanage position to relative or absolute becuase i think div tag by default will stretch to contain the child element it has, so it is not the case? it will just let the child grow beyond its boundary if it is static position? i thought position has to do with literally just position, and what i wanted archive is to just make it as wide and high as parent. so i guess position also dictates what child element (within div tag) will reference for width and height?? – user1118019 Apr 18 '12 at 22:43
  • @user1118019 I didn't fully understand what you just wrote, but here are some salient details. Elements that are `display:block` and have no CSS `width` specified expand to be as wide as their container. Container elements without a CSS `height` specified are only as tall as their contents; contents that have a percentage height are equivalent to having `height:0` when it comes to the parent figuring out how tall it needs to be. Whenever you use absolute positioning or percentage dimensions they are calculated relative to the "offset parent"; by default, the body is the only offset parent. – Phrogz Apr 18 '12 at 22:54
  • @user1118019 Elements that are `position:static` (the default value and behavior of all elements) do not start a new positioning system, but `position:relative` does (without otherwise changing the display of the element). For example, see [this demo](http://jsfiddle.net/cAF2y/3/). Notice how `#a1` is positioned and sized relative to the body, ignoring its containing `
    `. Notice how `#b1` is instead positioned and sized relative to its container, with the only difference between the two being `#b { position:relative}`.
    – Phrogz Apr 18 '12 at 23:00
  • thanks Phrogz...i got it now, thank you for taking your time and explaining things to me,,really appreciate it – user1118019 Apr 19 '12 at 00:51
  • I'd like to point out that this solution worked for me as I was trying to position a string on the canvas in the bottom center. knowing text width and height I could do so but the canvas was positioning the text incorrectly. by using `canvas.offsetWidth` and `canvas.offsetHeight` for the values in my positioning code it suceeded. just here for future reference. – Richard Barker Apr 20 '15 at 19:02
  • 1
    "Even if the div were sized correctly, it was using the default position:static, which means that it is NOT the positioning parent of any children" smh... why tho, CSS? I've been only good to you. – CCJ Jul 04 '20 at 06:55
  • This only works if you WANT a static size to your canvas. Typically, canvas content is resized when the browser is resized. This will NOT work when this is executed on window resize. The canvas will perpetually grow. – E10 Jun 08 '22 at 17:52
  • Following the above approach makes output of Canvas.js disappear. Code: `var canvasMatch = document.querySelectorAll('canvas'); canvasMatch.forEach(canvas => fitToContainer(canvas) ); function fitToContainer(canvas){ canvas.style.width='100%'; canvas.style.height='100%'; canvas.width = 200; canvas.height = 400; }` – Osama Hussein Apr 22 '23 at 13:48
19

Use the width and height attributes of the canvas if you want it to actually be as big as the parent element. You can set them using JQuery.

$(document).ready(function() {
  var canvas = document.getElementById("theCanvas");
  canvas.width = $("#parent").width();
  canvas.height = $("#parent").height();
});

If you do not know JQuery, then use the following Javascript:

var canvas = document.getElementById("theCanvas");
var parent = document.getElementById("parent");
canvas.width = parent.offsetWidth;
canvas.height = parent.offsetHeight;

If you use the css height and width attributes, style="width:100%; height:100%;", then you are just stretching the canvas. This will cause everything you draw on the canvas to look stretched.

JSFiddle for JQuery solution.

JSFiddle for Javascript solution.

Brant Olsen
  • 5,628
  • 5
  • 36
  • 53
  • 3
    I notice the questioner did not refer to jquery and so perhaps does not know about it. They may need a pure Javascript method. – jing3142 Apr 18 '12 at 18:23
  • @jing3142 Good call. I have updated with both JQuery solution and non-JQuery solution. – Brant Olsen Apr 18 '12 at 18:31
  • 1
    Note that the non-jQuery solution will fail unless you place explicit `style=""` attribute on the parent, or use JS to set the style. You should use `getComputedStyle()` or, as I did in my answer, `offsetWidth`/`offsetHeight`. – Phrogz Apr 18 '12 at 18:36
  • thanks brant for answering, i would accept both your answer and first one if i could. but anyway i thumbs up ur answer as well. again thank you very much for explaining. – user1118019 Apr 18 '12 at 22:15
1

Use CSS properties instead of attributes on the tags:

<div style="background-color:blue;width:140px;height:20px">
    <canvas style="background-color: red;width:100%;height:100%">
    </canvas>
</div>​

That seems to work

Kristoffer Sall-Storgaard
  • 10,576
  • 5
  • 36
  • 46