[javascript] How to resize html canvas element?

I have a canvas element defined statically in the html with a width and height. If I attempt to use JavaScript to resize it dynamically (setting a new width and height - either on the attributes of the canvas or via the style properties) I get the following error in Firefox:

uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///home/russh/Desktop/test.html :: onclick :: line 1" data: no]

Is it possible to resize this element or do I have to destroy it and create a new element on the fly?

This question is related to javascript html canvas dhtml

The answer is


<div id="canvasdiv" style="margin: 5px; height: 100%; width: 100%;">
    <canvas id="mycanvas" style="border: 1px solid red;"></canvas>
</div>
<script>
$(function(){
    InitContext();
});
function InitContext()
{
var $canvasDiv = $('#canvasdiv');

var canvas = document.getElementById("mycanvas");
canvas.height = $canvasDiv.innerHeight();
canvas.width = $canvasDiv.innerWidth();
}
</script>

You didn't publish your code, and I suspect you do something wrong. it is possible to change the size by assigning width and height attributes using numbers:

canvasNode.width  = 200; // in pixels
canvasNode.height = 100; // in pixels

At least it works for me. Make sure you don't assign strings (e.g., "2cm", "3in", or "2.5px"), and don't mess with styles.

Actually this is a publicly available knowledge — you can read all about it in the HTML canvas spec — it is very small and unusually informative. This is the whole DOM interface:

interface HTMLCanvasElement : HTMLElement {
           attribute unsigned long width;
           attribute unsigned long height;

  DOMString toDataURL();
  DOMString toDataURL(in DOMString type, [Variadic] in any args);

  DOMObject getContext(in DOMString contextId);
};

As you can see it defines 2 attributes width and height, and both of them are unsigned long.


I just had the same problem as you, but found out about the toDataURL method, which proved useful.

The gist of it is to turn your current canvas into a dataURL, change your canvas size, and then draw what you had back into your canvas from the dataURL you saved.

So here's my code:

var oldCanvas = canvas.toDataURL("image/png");
var img = new Image();
img.src = oldCanvas;
img.onload = function (){
    canvas.height += 100;
    ctx.drawImage(img, 0, 0);
}

This worked for me just now:

<canvas id="c" height="100" width="100" style="border:1px solid red"></canvas>
<script>
var c = document.getElementById('c');
alert(c.height + ' ' + c.width);
c.height = 200;
c.width = 200;
alert(c.height + ' ' + c.width);
</script>

<div id="canvasdiv" style="margin: 5px; height: 100%; width: 100%;">
    <canvas id="mycanvas" style="border: 1px solid red;"></canvas>
</div>
<script>
$(function(){
    InitContext();
});
function InitContext()
{
var $canvasDiv = $('#canvasdiv');

var canvas = document.getElementById("mycanvas");
canvas.height = $canvasDiv.innerHeight();
canvas.width = $canvasDiv.innerWidth();
}
</script>

Here's my effort to give a more complete answer (building on @john's answer).

The initial issue I encountered was changing the width and height of a canvas node (using styles), resulted in the contents just being "zoomed" or "shrunk." This was not the desired effect.

So, say you want to draw two rectangles of arbitrary size in a canvas that is 100px by 100px.

<canvas width="100" height="100"></canvas>

To ensure that the rectangles will not exceed the size of the canvas and therefore not be visible, you need to ensure that the canvas is big enough.

var $canvas = $('canvas'),
    oldCanvas,
    context = $canvas[0].getContext('2d');

function drawRects(x, y, width, height)
{
  if (($canvas.width() < x+width) || $canvas.height() < y+height)
  {
    oldCanvas = $canvas[0].toDataURL("image/png")
    $canvas[0].width = x+width;
    $canvas[0].height = y+height;

    var img = new Image();
    img.src = oldCanvas;
    img.onload = function (){
      context.drawImage(img, 0, 0);
    };
  }
  context.strokeRect(x, y, width, height);
}


drawRects(5,5, 10, 10);
drawRects(15,15, 20, 20);
drawRects(35,35, 40, 40);
drawRects(75, 75, 80, 80);

Finally, here's the jsfiddle for this: http://jsfiddle.net/Rka6D/4/ .


You didn't publish your code, and I suspect you do something wrong. it is possible to change the size by assigning width and height attributes using numbers:

canvasNode.width  = 200; // in pixels
canvasNode.height = 100; // in pixels

At least it works for me. Make sure you don't assign strings (e.g., "2cm", "3in", or "2.5px"), and don't mess with styles.

Actually this is a publicly available knowledge — you can read all about it in the HTML canvas spec — it is very small and unusually informative. This is the whole DOM interface:

interface HTMLCanvasElement : HTMLElement {
           attribute unsigned long width;
           attribute unsigned long height;

  DOMString toDataURL();
  DOMString toDataURL(in DOMString type, [Variadic] in any args);

  DOMObject getContext(in DOMString contextId);
};

As you can see it defines 2 attributes width and height, and both of them are unsigned long.


Prototypes can be a hassle to work with, and from the _PROTO part of the error it appears your error is caused by, say, HTMLCanvasElement.prototype.width, possibly as an attempt to resize all the canvases at once.

As a suggestion, if you are trying to resize a number of canvases at once, you could try:

<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<script type="text/javascript">
    ...
</script>

In the JavaScript, instead of invoking a prototype, try this:

$$ = function(){
    return document.querySelectorAll.apply(document,arguments);
}
for(var i in $$('canvas')){
    canvas = $$('canvas')[i];
    canvas.width = canvas.width+100;
    canvas.height = canvas.height+100;
}

This would resize all the canvases by adding 100 px to their size, as is demonstrated in this example


Hope this helped.


This worked for me just now:

<canvas id="c" height="100" width="100" style="border:1px solid red"></canvas>
<script>
var c = document.getElementById('c');
alert(c.height + ' ' + c.width);
c.height = 200;
c.width = 200;
alert(c.height + ' ' + c.width);
</script>

You didn't publish your code, and I suspect you do something wrong. it is possible to change the size by assigning width and height attributes using numbers:

canvasNode.width  = 200; // in pixels
canvasNode.height = 100; // in pixels

At least it works for me. Make sure you don't assign strings (e.g., "2cm", "3in", or "2.5px"), and don't mess with styles.

Actually this is a publicly available knowledge — you can read all about it in the HTML canvas spec — it is very small and unusually informative. This is the whole DOM interface:

interface HTMLCanvasElement : HTMLElement {
           attribute unsigned long width;
           attribute unsigned long height;

  DOMString toDataURL();
  DOMString toDataURL(in DOMString type, [Variadic] in any args);

  DOMObject getContext(in DOMString contextId);
};

As you can see it defines 2 attributes width and height, and both of them are unsigned long.


I just had the same problem as you, but found out about the toDataURL method, which proved useful.

The gist of it is to turn your current canvas into a dataURL, change your canvas size, and then draw what you had back into your canvas from the dataURL you saved.

So here's my code:

var oldCanvas = canvas.toDataURL("image/png");
var img = new Image();
img.src = oldCanvas;
img.onload = function (){
    canvas.height += 100;
    ctx.drawImage(img, 0, 0);
}

Here's my effort to give a more complete answer (building on @john's answer).

The initial issue I encountered was changing the width and height of a canvas node (using styles), resulted in the contents just being "zoomed" or "shrunk." This was not the desired effect.

So, say you want to draw two rectangles of arbitrary size in a canvas that is 100px by 100px.

<canvas width="100" height="100"></canvas>

To ensure that the rectangles will not exceed the size of the canvas and therefore not be visible, you need to ensure that the canvas is big enough.

var $canvas = $('canvas'),
    oldCanvas,
    context = $canvas[0].getContext('2d');

function drawRects(x, y, width, height)
{
  if (($canvas.width() < x+width) || $canvas.height() < y+height)
  {
    oldCanvas = $canvas[0].toDataURL("image/png")
    $canvas[0].width = x+width;
    $canvas[0].height = y+height;

    var img = new Image();
    img.src = oldCanvas;
    img.onload = function (){
      context.drawImage(img, 0, 0);
    };
  }
  context.strokeRect(x, y, width, height);
}


drawRects(5,5, 10, 10);
drawRects(15,15, 20, 20);
drawRects(35,35, 40, 40);
drawRects(75, 75, 80, 80);

Finally, here's the jsfiddle for this: http://jsfiddle.net/Rka6D/4/ .


Note that if your canvas is statically declared you should use the width and height attributes, not the style, eg. this will work:

<canvas id="c" height="100" width="100" style="border:1px"></canvas>
<script>
    document.getElementById('c').width = 200;
</script>

But this will not work:

<canvas id="c" style="width: 100px; height: 100px; border:1px"></canvas>
<script>
    document.getElementById('c').width = 200;
</script>

Prototypes can be a hassle to work with, and from the _PROTO part of the error it appears your error is caused by, say, HTMLCanvasElement.prototype.width, possibly as an attempt to resize all the canvases at once.

As a suggestion, if you are trying to resize a number of canvases at once, you could try:

<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<script type="text/javascript">
    ...
</script>

In the JavaScript, instead of invoking a prototype, try this:

$$ = function(){
    return document.querySelectorAll.apply(document,arguments);
}
for(var i in $$('canvas')){
    canvas = $$('canvas')[i];
    canvas.width = canvas.width+100;
    canvas.height = canvas.height+100;
}

This would resize all the canvases by adding 100 px to their size, as is demonstrated in this example


Hope this helped.


Note that if your canvas is statically declared you should use the width and height attributes, not the style, eg. this will work:

<canvas id="c" height="100" width="100" style="border:1px"></canvas>
<script>
    document.getElementById('c').width = 200;
</script>

But this will not work:

<canvas id="c" style="width: 100px; height: 100px; border:1px"></canvas>
<script>
    document.getElementById('c').width = 200;
</script>

This worked for me just now:

<canvas id="c" height="100" width="100" style="border:1px solid red"></canvas>
<script>
var c = document.getElementById('c');
alert(c.height + ' ' + c.width);
c.height = 200;
c.width = 200;
alert(c.height + ' ' + c.width);
</script>

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to canvas

How to make canvas responsive How to fill the whole canvas with specific color? Use HTML5 to resize an image before upload Convert canvas to PDF Scaling an image to fit on canvas Split string in JavaScript and detect line break Get distance between two points in canvas canvas.toDataURL() SecurityError Converting Chart.js canvas chart to image using .toDataUrl() results in blank image Chart.js canvas resize

Examples related to dhtml

Child element click event trigger the parent click event Change :hover CSS properties with JavaScript Modifying a query string without reloading the page Adding and removing style attribute from div with jquery Set content of HTML <span> with Javascript jQuery get the id/value of <li> element after click function Capture iframe load complete event How do I attach events to dynamic HTML elements with jQuery? How do I programmatically click on an element in JavaScript? Getting all selected checkboxes in an array