In the last article, we covered the basics of Backbone Views and how to enable jQuery to seamlessly manipulate the same DOM that Backbone manipulates.

In this article, we will explore how we can make Backbone play nicely with d3.js. The concepts in this article should apply to situations where you intend to use Backbone with most other libraries that also manipulate the DOM.

Backbone + d3.js Working on the Same DOM

d3.js , written by Mike Bostock, is another widely used library that manipulates the Document Object Model, primarily to visualize data. In fact, you can get really creative with the way data can be visualized.

At the lowest level, d3.js interacts with HTML and/or SVG elements and manipulates their attributes by binding data to the Document Object Model.

Houston, We’ve Got a Problem!

Assuming that our goal is to preserve the existing p element and append the other p elements to DOM, when we execute the above code, we quickly run into a major problem.

The .render()inserts a p element with the text “I am not a number” into the DOM. But .renderVisualization() selects all existing p elements in the DOM and inserts content into those elements. This overwrites the text in the original p element, despite our appending to the DOM using d3.append() .

Solutions to Getting d3.js and Backbone to Play Nicely Together

In this simple example, at least two simple solutions exist.

Use a more specific CSS selector

Use a different tag altogether

Cordoning Off a Portion of the DOM

For more complicated examples, we may need alternative strategies. One potential solution is to cordon off a portion of the DOM that will be operated on by one of the libraries. For example:

In the above case, Backbone continues to manage the to-be-created view. However, let’s say that there is an element somewhere in the DOM (inside or outside of the DOM managed by the Backbone view) whose id is “visualization”. We can capitalize on this fact by scoping all of our d3-related DOM manipulations to this element. As a result, all d3 chained methods, including .selectAll("p") and .append("p") , are executed in the context of #visualization .

Encapsulate Differentiated DOM Manipulation With Sub-Views

Finally, another approach to managing third-party view functionality is to use subviews. Here is how that might look.

Another Shared-DOM Manipulation Approach for Backbone + d3.js

There are times when you need to make sure that your d3 DOM manipulation occurs in the same context as the Backbone view itself. For example, simply cordoning off a portion of the DOM with #visualization provides no guarantee that the element exists within or outside of the part of the DOM represented by the Backbone view.

One alternative is to ensure that your starting d3 selection references the same element as the one pointed to by this.$el . However, if you tend not to set el or any of its attributes directly, it would be difficult to sufficiently target the current view using CSS.

Luckily, in the d3.js library, there exists a method that enables direct node selection. Let me introduce you to d3.select(node) . According to the documentation, this method:

Selects the specified node. This is useful if you already have a reference to a node, such as d3.select(this) within an event listener, or a global such as document.body. This function does not traverse the DOM.

This method allows us to write the following code and ensure that d3 manipulations occur within the context of the Backbone view.