32

I was just trying to do the following in jQuery:

var newCanvas = $('<canvas/>',{'width':100,'height':200,'class':'radHuh'});
$(body).append(newCanvas);

This is working (kind of) and generates the following markup:

<canvas style="width:100px; height:200px;" class="radHuh"></canvas>

As most of you might know canvas elements don't really like CSS dimensions but expect a width and height attribute, so this object creation failed for me.

I do know I could just do:

var newCanvas = $('<canvas/>',{'class':'radHuh'}).attr({'width':100,'height':200});

instead, but I was just wondering nonetheless if there is any way of telling jQuery that width and height should be treated as attributes when creating the element via $('element',{attributes}) and not as CSS?

m90
  • 11,434
  • 13
  • 62
  • 112
  • 1
    To be clear, `` elements "like" CSS width and height just fine; as with an HTML ``, setting the display dimensions via CSS scales up/down a bitmap. The `` height and width properties/attributes are like changing the size of an image in Photoshop, setting the actual number of pixels in the source image. – Phrogz May 03 '12 at 18:47
  • @Phrogz that's why I was writing "don't really like"... In any case I guess that 99% of canvas elements will need these attributes as they don't match the default ratio and so on. – m90 May 03 '12 at 18:54
  • 1
    @Phrogz , yes, ok but to be clear, you'll need a bit of simple math to scale it properly in plain css. Otherwise the `canvas` will act (as you said) like a normal `img` tag but it will **NOT scale proportionally** and most users (as they have) have problems in actually understanding - exactly this quasi/similarity. – Roko C. Buljan May 09 '12 at 10:58

6 Answers6

32

jQuery try to match each attribute name with a jQuery function name. Matched functions are called.

width and height are jQuery functions, so your original code is equivalent to this:

  var newCanvas = 
    $('<canvas/>',{'class':'radHuh'})
    .width(100)
    .height(100);

width(value) and height(value) functions set CSS width and height of an element.


Relevant jQuery source code line (https://github.com/jquery/jquery/blob/master/src/attributes.js#L308)

if ( pass && name in jQuery.attrFn ) {

attrFn object definition (https://github.com/jquery/jquery/blob/master/src/attributes.js#L288):

attrFn: {
    val: true,
    css: true,
    html: true,
    text: true,
    data: true,
    width: true,
    height: true,
    offset: true
},
Juan Mellado
  • 14,973
  • 5
  • 47
  • 54
  • 3
    While this answer does effectively set the styled height and width, the question is asking about the canvas height and width attributes. `$('').width(100).height(100)` actually sets the style of the canvas. The more appropriate answer is from @thecodeparadox. Using `.prop({width: 100, height: 100})` adds the direct height and width we're looking for. – Josh W Lewis Nov 26 '14 at 04:29
31
var newCanvas = $('<canvas/>',{
                   'class':'radHuh',
                    id: 'myCanvas'                   
                }).prop({
                    width: 200,
                    height: 200
                });
$('#canvas').append(newCanvas);

Proof

thecodeparadox
  • 86,271
  • 21
  • 138
  • 164
10

You can use like this

$('<canvas/>',{'class':'radHuh','Width':100,'Height':200});

Change the case and try

Ranganadh Paramkusam
  • 4,258
  • 2
  • 22
  • 33
8

It seem like changing the case of any letter will prevent jQuery from converting the attribute to a style, so ranganadh probably stumbled on to some unintended flaw in jQuery where it checks the attribute against styles, but not case-insensitive.

This for instance seems to work aswell ??

var newCanvas = $('<canvas/>', {heiGht: 200, widtH: 100});
$('body').append(newCanvas);​​​

The native JS attributes are not converted to styles, and I'd probably go with the below solution to make sure it's "future proof" ( setAttribute() seems to work fine aswell ) :

var newCanvas = $('<canvas/>');
    newCanvas[0].height = 200;
    newCanvas[0].width = 100;

$('body').append(newCanvas);​​​
Sam Axe
  • 33,313
  • 9
  • 55
  • 89
adeneo
  • 312,895
  • 29
  • 395
  • 388
1

I found that this worked the best:

$('<canvas height="50px" width="50px"/>')

You can also add id, class, or other attributes this way. Because it is not in the style="" attribute, it does not count as CSS and mess up your shapes.

elaid
  • 351
  • 1
  • 10
0

Edit: This is slower, see comments below.

This will likely be faster than any workaround posted here:

var attributes = {width: 100, height: 100, class: "whatever"};
$('<canvas width="'+attributes.width+'" height="'+attributes.height+'" class="'+attributes.class+'""></canvas>').appendTo(document.body);

Slightly less fancier, but it's esentially the same with less function calls.

Mahn
  • 16,261
  • 16
  • 62
  • 78
  • Actually it seems to be a lot slower that way: http://jsperf.com/element-creation-vs-string-injection – m90 Feb 10 '13 at 10:25
  • @m90 Hm, interesting, I wonder what's the reason behind that then, it doesn't seem to be very logic. – Mahn Feb 10 '13 at 15:42
  • jQuery won't just insert the String into the DOM but parse and handle it in many different ways. If you pass a plain HTML tag to the `$()` it can skip a call to `$.buildFragment` which seems to be pretty expensive and do the attribute handling via `.attr()` itself. See: http://james.padolsey.com/jquery/#v=1.7.2&fn=init for what's going on. – m90 Feb 10 '13 at 16:22
  • @m90 yeah, this is what I thought shortly after posting the comment, makes sense. Good to know either way. – Mahn Feb 10 '13 at 16:54