srquinn
srquinn

Reputation: 10501

Dynamically created element used for Raphael canvas

I have created a Backbone.js/Require.js application that dynamically loads HTML templates to use as "pages" in the application. This means my main HTML page looks like so.

<head>
  // Necessary CSS and Javascripts here
</head>
<body>
  <div id="container"></div>
</body>

And then I used underscore templates to render new elements dynamically to the DOM. However, a new feature requires the use of a Raphael.js chart. I created a new element <div id='canvas'></div> and call Raphael('canvas') but since the canvas element wasn't there on DOM ready, Raphael can't see the newly created element.

I have attempted to use a jQuery selector in place of the id reference like so Raphael($('#canvas')) but this attaches the canvas to the body element and not my container element.

Any suggestions on how to bind a Raphael canvas to a dynamically created element?

Upvotes: 1

Views: 3165

Answers (4)

zmilan
zmilan

Reputation: 1152

I know that this is too old question, but anyway it can help to someone. Its important to be sure that your view is placed on page, so use something like onShow functionality, or render. But anyway Raphael will not show right because if your send to Raphael this.$el or anything similar it will not accept it like you expect. What You need to do is something like this.$el.first() or this.$el[0].

Upvotes: 0

srquinn
srquinn

Reputation: 10501

Raphael($('#canvas').first(), '100%', '100%')

Though I had errors else where, the main issue that caused Raphael not to fire was forgetting that a jQuery selector passes an array of Elements and Raphael's constructor want's a single element. Raphael was attaching itself to the body because it was the top level parent of the selector's result.

Mosselman was also correct in pointing out that you can build a view in Backbone entirely in memory and then append it to the DOM.

Upvotes: 4

Mosselman
Mosselman

Reputation: 1758

A way to overcome this issue is by creating an empty element in the view and binding everything onto that. I have never worked with Raphael, but I think this could work:

var someView = Backbone.View.extend({
    el: document.createElement('div'), // This creates a DOM element '<div></div>'

    initialize: function(){
        Raphael(this.el); // Attach Raphael, you could also go with jQuery
    },

    render: function(){
        jQuery('#container').append(this.el); // Add to DOM somehow
    }
})

Upvotes: 2

busticated
busticated

Reputation: 2187

seems like a good approach is to either throw an event after the template has been added to the DOM and have your call to Raphael('canvas') listen for that event or use a callback to trigger Raphael('canvas'). in both cases you are ensuring that you don't call Raphael('canvas') before the target element is in place.

very roughly, something like this:

//from your raphael module / code
$(document).on('canvasAdded', function(){
    var paper = Raphael('canvas');
    //stuff!
});

//after you are sure your template has rendered
$(document).trigger('canvasAdded');

you probably want to make some kind of .init() method and call that from the event handler (vs. what I show above) but hopefully this points you in the right direction.

Upvotes: 0

Related Questions