Quiescent and Highcharts
How to glue them together
I recently rewrote the front-end of a side-project from JavaScript and React to ClojureScript and Quiescent. In that effort I needed to chart some data. I could not find a ClojureScript charting library that I was happy with, so I decided to keep using HighCharts for the moment.
Add Highcharts to project
If you want to use a JavaScript library in a ClojureScript project, the easiest way is to go with CLJSJS. However, not every library is packaged up by CLJSJS. So in order to use Highcharts you have to put a little more effort into it.
Here is how you include it in your Leiningen project.clj
:compiler {
...
;; Highrise standalone-framework makes Highrise work without jQuery
:foreign-libs [{:file "lib/standalone-framework.src.js"
:provides ["Standalone"]}
{:file "lib/highcharts.src.js"
:provides ["Highcharts"]
:requires ["Standalone"]}]}}]}
Render a graph
To render a graph component with Quiescent, you have to use one of the React lifecycle hooks that Quiescent provides. In addition, you have to tell Highcharts which DOM-element to use for the graph. I banged my head against the wall trying to get the graph to render by passing a DOM element string id to Highcarts. The trick was passing an actual DOM element reference instead.
(q/defcomponent MyGraph
;; Quiescent will call the :on-render function every time the DOM is updated.
;; It is equivalent to 'componentDidMount' and 'componentDidUpdate' in React
:on-render (fn [dom-node component-value]
;; Instantiate a new chart by targeting the dom-node
(new js/Highcharts.Chart
;; Deep-convert the clojure data structure into a JavaScript
;; object that Highcharts.Chart takes as input
(clj->js
;; Need to pass the dom-node reference to :renderTo
{:chart {:type "column"
:renderTo dom-node}
;; Just some bogus data
:series [{:name "Monkey",
:data [1, 0, 4]},
{:name "Giraffe",
:data [5, 7, 3]}]})))
[props]
;; This div will be the target of the graphs :renderTo
(d/div {}))
You can find a complete example in my Cashflow repo.