
Replacing jQuery with D3 - chrtze
http://blog.webkid.io/replacing-jquery-with-d3/
======
athenot
We've been running with d3 instead of jQuery for almost 2 years. Some notes so
far:

\- d3.selectAll is more verbose than $() but in my opinion, that's not a bad
thing as I try to minimize DOM selections anyways;

\- transitions are another area where D3 really shines, for cases where you
don't/can't use CSS transitions, like displaying a discreet popup status
message.

\- d3 data binding is oh so convenient, and that's where the real magic
happens. Combined with a queueing system like postal.js, we pretty much have
the same thinking model as React. The DOM is now an expression of the data,
and D3's joins figure out what DOM elements need to be updated. It's slightly
lower level than React, in that you specify what happens on enter/update/exit,
but in terms of efficiency, it seems great (disclaimer: we haven't run
benchmarks);

\- if you happen to like CoffeeScript, D3 turns into a very elegant DSL that
is consistent for DOM editing, styling and event handling. Here's a simple
lightbox modal dialog:

    
    
        lightbox.shell = d3.select "body"
          .div "#shadebox"
          .style "opacity", 0
          .on "click", ->
            lightbox.removeLightbox()
            d3.event.stopPropagation()
    
        lightbox.body = lightbox.shell.append "div"
          .attr "id", "lightbox"
          .on "click", -> d3.event.stopPropagation()
    
        lightbox.showLightbox()
        return lightbox.body
    

\- we've added a `.div` function that's shorthand for d3.append and
automatically adds an id and/or class, to feel a bit more like Jade;

\- one downside we found with D3 is that we can't just grab any jquery plugin
and throw it in our app.

~~~
the8472
> \- d3 data binding is oh so convenient, and that's where the real magic
> happens

It's great, but it has limitations. It only ever binds to a single `__data__`
property on the DOM nodes (making it very very difficult to associate multiple
sets of data through a single DOM tree) and which needs to be carefully re-
bound to each sub-node if you wish to substitute the objects with new ones.
And acting on the data (basically two-way binding) and then updating the d3
selection has to be done very carefully too.

I've run into many subtle errors that stem from this fairly primitive method
of binding.

It probably could use some additional abstractions to make replaying updates
on object replacement/modification easier.

~~~
mgold
D3 has nested selections that let you handle cases like this. The data for a
single element can be an array, and if that element is a div (HTML) or g (SVG)
you can do another join and bind those data to its children. More info:
[http://bost.ocks.org/mike/nest/](http://bost.ocks.org/mike/nest/)

To "substitute the objects with new ones", do another join, pass a key
function as the second argument if necessary, and use the enter/update/exit
pattern.

~~~
the8472
You're not telling me anything new here. The point is that those data-binds
_only_ propagate if you perform all the same selections on your update as you
did during enter stage. I reported this issue and they essentially said it
can't be improved due to backwards-compatibility requirements[1]

And key functions are non-trivial to create if 1. you use d3.nest[2] (not to
be confused with nested selections) 2. you modify the data in a way that
changes the grouping 3. you try to match existing nodes back to the changed
groupings. Key-based computation is insufficient for dynamically matching DOM
nodes to changing sets.

Those two things aren't showstoppers. They just make the data-binding fairly
brittle.

The thing that it's bound to a non-namespaced __data__ property is more
problematic in my opinion since you always have to pay attention to not
overwrite the datum with a different selection on any DOMnode, otherwise you
will break callbacks that rely on the data. It basically requires a 1:1
correspondence for DOM to data on the whole subtree.

This makes decomposing the selections into separate steps difficult. I.e.
building a base tree and then populating the leaves with a separate data set
can easily end up overwriting the data bindings of the base tree. Again, it's
possible to avoid these pitfalls but if __data__ had been namespaced it would
be far less hazardous.

[1]
[https://github.com/mbostock/d3/issues/2034](https://github.com/mbostock/d3/issues/2034)
[2]
[https://github.com/mbostock/d3/wiki/Arrays#-nest](https://github.com/mbostock/d3/wiki/Arrays#-nest)

------
couchand
A great reference for someone starting out with D3 looking to replace some
basic jQuery incantations with D3 ones. I think this code sample is
particularly telling:

 _jQuery_

    
    
        $('.foo').find('.bar');
    

_D3_

    
    
        d3.selectAll('.foo').selectAll('.bar');
    

The D3 API consistency is so juicy and delicious.

~~~
talmand
For consistency like that you could always go with:

    
    
        $('.foo .bar');
    

But I would assume you could do the same in D3?

~~~
1wheel
Yes, d3 uses CSS3 selections

[https://github.com/mbostock/d3/wiki/Selections](https://github.com/mbostock/d3/wiki/Selections)

------
ww520
D3 is an amazing library. At first glance thought it's a charting library.
Upon further usage realized it's more of a DOM manipulation library just like
JQuery, with the additional support on SVG, which happens to do chart.

~~~
Tloewald
Jquery works quite well on SVG too. It's all Dom nodes.

~~~
slowhead
There are limits to what you can do with JQuery on SVG, hence the existence of
plugins such as this one : [http://keith-wood.name/svg.html](http://keith-
wood.name/svg.html)

------
gnud
The Ajax section is just not good enough.

The main reason I still use jQuery is that they unify their promise type with
their ajax. It's easy to create code that works with any promise, ajax or
otherwise.

~~~
acconrad
You should try reqwest if all you need jQuery for is AJAX

~~~
gnud
A good ajax library that's well integrated with a good promise library, that's
completely cross-browser, back to IE7.

------
frik
Instead of JQuery and D3. You can also use _vanilla JS5_ nowadays.

[http://vanilla-js.com/](http://vanilla-js.com/)

[SPOILER: it's not a framework, it's simply native JS5]

~~~
aikah
both jQuery and D3 are "vanilla js". Just that the person that owns that page
doesn't understand the difference between the DOM and Javascript.

~~~
frik
Usually people think of DOM as part of JS standard API, similar to Java's
standard platform API library. There are many JS books that usually cover DOM
but rarely books about DOM itself. As VBScript is dead, JS is the only
language that uses that API. So you are technically correct.

What is questionable is "both JQuery and D3 are vanilla js". JQuery is a JS
framework that is usually not considered "native". On modern browser it
nowadays calls newer DOM API functions like one can do with vanilla/standard
JS5. D3 is JS library that is mainly based around SVG, it's usually not
considered "native", it calls SVG and DOM APIs like one can do in JS5. Each
layer/framework on top means an additional overhead in combined JS file size.

"The Document Object Model (DOM) is a programming interface for HTML, XML and
SVG documents. [...] Though often accessed using JavaScript, the DOM itself is
not a part of the JavaScript language, and it can be accessed by other
languages, though this is much less common."

[https://developer.mozilla.org/en-
US/docs/Web/API/Document_Ob...](https://developer.mozilla.org/en-
US/docs/Web/API/Document_Object_Model)

------
potomak
About the topic of replacing jQuery I really enjoyed reading "Weaning yourself
off jQuery"[0] by James Halliday. It shows how to replace some of the jQuery
features with the DOM API and/or with npm libraries such hyperquest[1].

[0]
[http://substack.net/weaning_yourself_off_jquery](http://substack.net/weaning_yourself_off_jquery)

[1]
[https://www.npmjs.com/package/hyperquest](https://www.npmjs.com/package/hyperquest)

------
me_myself_and_I
I've come to dislike all-in-one solutions. If D3 focused only in rendering
there would be a few advantages like a smaller api and smaller file size.

It bothers me that I'm already using superagent for ajax stuff in a React
project, and if I want to use D3 I will need to live with that extra bloat.

D3 is really amazing, and I'll be integrating it anyway.

------
xiphias
It seems d3 would be easier to use if d3(...) would be an alias to
d3.selectAll(...)

~~~
Nemcue
Ease of use in the sense that you type less.

I think it would be harder to use from the perspective of a new developer
trying to learn D3. selectAll already has way too many responsibilities in my
opinion, making it totally opaque what d3(...) really does. OTOH I guess it's
kind of the same with jQuery(..), since it can do both selectors as well as
create new Elements.

D3 is one of those libraries that I really admire from a conceptual point of
view, but boy do I wish the API was more newbie-friendly.

It's rather indicative of an API that has room for improvement when you start
noticing just how many tutorials, videos and books that have to explain
D3.selectAll. "Well, you see — sometimes it doesn't really select anything,
instead it does this _other_ thing"

Not to mention the source code. Very sparsely commented.

~~~
couchand
I disagree that there's any problem with the API. I do agree that it can be
hard for a new developer trying to learn, but I believe that it's worth it. By
analogy, learning to code is hard for someone who has not yet done it, but
it's still worth the effort, and you would never expect designers of "real"
programming languages to dumb things down to make it easy for you the first
time.

Should we design our tools so that you can pick them up immediately or should
we design them so they give us as much power as possible? I, personally, would
prefer Englebart's violin.

~~~
Nemcue
"Should we design our tools so that you can pick them up immediately or should
we design them so they give us as much power as possible?"

A thoroughly false dichotomy.

It's not either or, it's varying degrees of both.

------
rip747
Honest question. if there so many similarities between the two, then why not
build the library as an jQuery plugin from the beginning?

~~~
chrtze
D3 implements many other features like scales and stuff. The two just have
some parts in common when it comes to DOM-manipulations and selections.

~~~
rip747
totally understand that. i'm just wondering why the authors would want to
write methods for DOM manipulation in the first place when they could
piggyback off jQuery for that and concentrate on the other stuff.

~~~
orthecreedence
I appreciate that they didn't. I don't like jQuery. I'm forced to use it for
work sometimes, but on side projects I won't touch it. However, I do like D3 a
lot for visualization work. If D3 piggybacked onto jQuery, I would find it a
lot less palatable.

That said, the way D3 does selections/grouping is much more complex than
jQuery. Sure, on the surface level they do the same thing (selecting DOM
nodes), but where D3 diverges is the ability to represent DOM nodes as data
you tie to it. So your array and your <circle> elements are 1:1, or perhaps
your array elements have sub-arrays...D3 can easily tie those sub-arrays into
sub-DOM-elements, all while letting you address different pieces of the tree
easily.

They are two different beasts. One is a DOM library, one is a visualization
library. There is really not a whole lot of intersection beyond some basic
operations.

------
lightblade
Just one feature missing: event delegation.

Event listeners in d3 are not delegated listeners. Implementing this feature
actually is not an easy matter as you need to preserve the d3 data binding
context and also attach to the nearest svg element because svg events don't
bubble through it.

------
based2
[http://alistapart.com/blog/post/choosing-vanilla-
javascript](http://alistapart.com/blog/post/choosing-vanilla-javascript)

------
dnprock
I use d3.select for data binding with DOM elements. For DOM manipulation, I
prefer jQuery. That's the distinction. I don't see advantage of d3.select over
jQuery DOM manipulation.

------
Pinatubo
What's the preferred nomenclature: d3 or D3? Even this article uses both.

~~~
mbostock
D3.

