Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Would this be considered idiomatic ClojureScript?

I am experimenting/learning ClojureScript. Following code snippet interfaces with the excellent d3.js lib to display some circles. Find it to be bit verbose, without resorting to macros, is there a way to optimize/minimize it?

(def rdata (atom (array 3 10 12 16 19)))

(defn update []
(let [em (.selectAll (.select js/d3 "svg") "circle")
     data (.data em @rdata d3/String)
     enter (.append (.enter data) "circle")
     yscale (.linear (. js/d3 -scale))
     xscale (.linear (. js/d3 -scale))
     rscale (.linear (. js/d3 -scale))
     ]
(-> yscale 
  (.domain (array 0 20))
  (.range (array 100 200)))
(-> xscale
  (.domain (array 0 20))
  (.range (array 100 800)))
(-> rscale
  (.domain (array 0 20))
  (.range (array 50 100)))
(-> enter
  (.attr "cx" xscale)
  (.attr "cy" yscale)
  (.attr "r" rscale)
  (.style "fill" "steelblue")
  (.style "stroke" "black")
  (.style "stroke-width" "2")
  )
)
(.info js/console "rdata: " @rdata)
)

Thanks

like image 994
user922621 Avatar asked May 25 '12 21:05

user922621


1 Answers

To initialize the scales you can write (.linear (.-scale js/d3)), which is a bit more concise. Also, in this code snippet there is no reason to use an Atom for the data. If you want to update the visualization, you could pass new data as an argument to update rather than mutating the atom and calling a no-arg update fn.

The threading macro idiomatic for chaining, so you're good there.

Then again, you can't get more idiomatic than using a straight up Clojure library; check out C2, a Clojure(Script) implementation of D3. (Of course, as the primary author I'm a bit biased on that one.)

If you need to use D3 itself, you might also want to skim the source of the now-deprecated cljs-d3 wrapper.

Macros are one way to get a more concise interface (e.g., expanding map literals into multiple (.attr "key" value) calls), but the semantics of the chaining macro let you inject any fn into the chain, which is very different from the JavaScript case. You could, for instance, write a plain fn that takes the d3 selection and an attribute map and uses doseq to call (.attr d3 k v) for each map key/value.

Actually, there's a 40 minute talk on this exact subject (using D3 as the example) from Clojure Conj last year.

like image 171
Kevin L. Avatar answered Sep 29 '22 06:09

Kevin L.