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?

3
  • 1
    To be clear, <canvas> elements "like" CSS width and height just fine; as with an HTML <img>, setting the display dimensions via CSS scales up/down a bitmap. The <canvas> 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. Commented May 3, 2012 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. Commented May 3, 2012 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. Commented May 9, 2012 at 10:58

6 Answers 6

33
+100

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
},
Sign up to request clarification or add additional context in comments.

1 Comment

While this answer does effectively set the styled height and width, the question is asking about the canvas height and width attributes. $('<canvas>').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.
31
var newCanvas = $('<canvas/>',{
                   'class':'radHuh',
                    id: 'myCanvas'                   
                }).prop({
                    width: 200,
                    height: 200
                });
$('#canvas').append(newCanvas);

Proof

1 Comment

This should be the accepted answer. .prop sets the width and height appropriately for canvas elements.
10

You can use like this

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

Change the case and try

3 Comments

That's interesting. Is this happening by design or is this taking advantage of some inconsistency?
i guess it is checking for known css attributes!
this behaviour could change in later version of jQuery so keep in mind linking to frozen version
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);​​​

Comments

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.

Comments

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.

4 Comments

Actually it seems to be a lot slower that way: jsperf.com/element-creation-vs-string-injection
@m90 Hm, interesting, I wonder what's the reason behind that then, it doesn't seem to be very logic.
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: james.padolsey.com/jquery/#v=1.7.2&fn=init for what's going on.
@m90 yeah, this is what I thought shortly after posting the comment, makes sense. Good to know either way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.