Coffeescript helpers for d3.js

fp.js is a tiny library to help keep d3.js dom manipulation code clean.

Update (December 29, 2013) #

Upgraded to support the format at the bottom. Check out this rewrite of the d3.js Grouped Bar Chart Example using fp.js.

I write a lot of d3.js code and most dom manipulation code got complicated and hard to maintain. With fp.js attributes, styles and events can be set easily. But the most important fact is that FP.js lets you maintain indentation in coffescript code that matches the dom structure.

numbers = [5, 3, 23, 6, 7, 0, 1, 25, 11, 19, 20]
chartHeight = 300

chart = d3.select("body")
 .append("svg")
 .attr("width", "100%")
 .attr("height", "100%")

bars = chart.selectAll("g.bar").data(numbers).enter()
 .append("g")
 .attr("class", "bar")

bars.append("rect")
 .attr("y", (d) -> chartHeight - d * 10)
 .attr("x", (d, i) -> i * 20)
 .attr("width", 20)
 .attr("height", (d) -> d * 10)

bars.append("line")
 .attr("class", "budget")
 .attr("y1", (d) -> chartHeight - d * 9)
 .attr("y2", (d) -> chartHeight - d * 9)
 .attr("x1", (d, i) -> i * 20)
 .attr("x2", (d, i) -> i * 20 + 20)
 .attr("stroke", (d) -> if d < 20 then "white" else "#aaa")

Above is plain code to draw a simple bar chart with d3.js, and below is the code with FP.js.

numbers = [5, 3, 23, 6, 7, 0, 1, 25, 11, 19, 20]
chartHeight = 300

FP d3, 'select', 'body', ->
 FP @, 'svg', width: "100%", height: "100%", ->
   FP @, 'selectAll', 'g.bar', ->
    FP @, 'data', numbers, ->
     FP @, 'enter', ->
      FP @, 'g.bar', ->
       FP @, 'rect',
        y: ((d) -> chartHeight - d * 10)
        x: ((d, i) -> i * 20)
        width: 20, height: ((d) -> d * 10)
       FP @, 'line.budget',
        y1: ((d) -> chartHeight - d * 9)
        y2: ((d) -> chartHeight - d * 9)
        x1: ((d, i) -> i * 20)
        x2: ((d, i) -> i * 20 + 20)
        stroke: ((d) -> if d < 20 then "white" else "#aaa")

I am planning to remove the clutter of FP @, so that it’ll look like the following; but for that I will have to either use with keyword or create functions for select, rect, line, etc, in a local context similar to coffeekup.

FP d3, ->
 select 'body', ->
  svg width: "100%", height: "100%", ->
    selectAll 'g.bar', ->
     data numbers, ->
      enter ->
       g '.bar', ->
        rect
         y: ((d) -> chartHeight - d * 10)
         x: ((d, i) -> i * 20)
         width: 20, height: ((d) -> d * 10)
        line '.budget',
         y1: ((d) -> chartHeight - d * 9)
         y2: ((d) -> chartHeight - d * 9)
         x1: ((d, i) -> i * 20)
         x2: ((d, i) -> i * 20 + 20)
         stroke: ((d) -> if d < 20 then "white" else "#aaa")

Another option is to use @, which cleaner and not that messy, but code readers might get confused whether @ is referring to the object you are making the call from. Also, using a one letter name such as $ or _ for fp.js will give a similar code - $.rect, $.line, etc.

FP d3, ->
 @select 'body', ->
  @svg width: "100%", height: "100%", ->
    @selectAll 'g.bar', ->
     @data numbers, ->
      @enter ->
       @g '.bar', ->
        @rect
         y: ((d) -> chartHeight - d * 10)
         x: ((d, i) -> i * 20)
         width: 20, height: ((d) -> d * 10)
        @line '.budget',
         y1: ((d) -> chartHeight - d * 9)
         y2: ((d) -> chartHeight - d * 9)
         x1: ((d, i) -> i * 20)
         x2: ((d, i) -> i * 20 + 20)
         stroke: ((d) -> if d < 20 then "white" else "#aaa")
 
102
Kudos
 
102
Kudos

Now read this

Benford’s Law Analysis and Sparklines

[Benford’s Law Analysis with Sparklines](//vpj.github.io/images/posts/benford-sparkline.png) The image shows first-two-digit distribution compared with the expected values based on Benford’s Law. What is new here are the sparklines on... Continue →