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")