Created
April 9, 2017 14:40
-
-
Save rgm/7f2771a605956c17e5fb8c7409a7098a to your computer and use it in GitHub Desktop.
hooking up D3 and React via om.next
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns skeleton.fourth.charts | |
(:require | |
[om.next :as om :refer-macros [defui]] | |
[om.dom :as dom] | |
[sablono.core :as sab :refer-macros [html]] | |
[devcards.core :as dc :refer-macros [defcard]] | |
[cljsjs.d3 :as d3])) | |
(def canvas-size 200) | |
(def num-points 5) | |
(defn create-d3-chart | |
[props-data dom-node] | |
(let [radius 5 | |
x-transform (fn [d i] (+ 10 (* i (/ canvas-size (+ num-points 1))))) | |
y-transform (fn [d i] (- canvas-size (* d 20) 10))] | |
(.. js/d3 | |
(select dom-node) | |
(selectAll "circle") | |
(data (clj->js props-data)) | |
(attr "r" radius) | |
(attr "cx" x-transform) | |
(attr "cy" y-transform) | |
enter | |
(append "circle") | |
(attr "r" radius) | |
(attr "cx" x-transform) | |
(attr "cy" y-transform)))) | |
(defn create-d3-list | |
[props-data dom-node] | |
(.. js/d3 | |
(select dom-node) | |
(selectAll "li") | |
(data (clj->js props-data)) | |
(html identity) | |
enter | |
(append "li") | |
(html identity))) | |
(defn refresh-charts [c] | |
(let [data (:sample-data (om/props c))] | |
(create-d3-chart data (dom/node c "the-svg")) | |
(create-d3-list data (dom/node c "the-ul")))) | |
(defui ^:once D3IsInCharge | |
Object | |
(componentDidMount [this] (refresh-charts this)) | |
(componentDidUpdate [this _ _] (refresh-charts this)) | |
(render | |
[this] | |
(let [props (om/props this)] | |
(html [:div | |
[:h2 "d3-generated HTML"] [:ul#the-ul {:ref "the-ul"}] | |
[:h2 "d3-generated SVG"] [:svg#the-svg {:ref "the-svg" | |
:width canvas-size | |
:height canvas-size}]])))) | |
(def d3-in-charge (om/factory D3IsInCharge)) | |
(defonce chart-state (atom {:sample-data (vec (range num-points))})) | |
(defn mutate-state! [_] | |
(swap! chart-state update-in [:sample-data] #(->> % (map inc) vec))) | |
(defcard "Tests of getting React and D3.js to play nice (from Ch. 9 of *D3.js In Action*).") | |
(defcard :d3-is-in-charge | |
"Test of letting D3 drive the DOM (aka. 'approach one' from the book). React | |
generates *only* the `<svg>` or `<ul>` container and we set a `ref` with | |
`[:svg {:ref \"the-ref\"} ,,,]`. We use that `ref` from `componentDidMount` and | |
`componentDidUpdate` using `(om.dom/node component \"the-ref\")` to get a | |
handle to the DOM node, and that forms the root D3 selection. Component's | |
`render` method only gets called once and we're relying on D3's | |
select/enter/exit." | |
(fn [props owner] | |
(html [:div | |
[:p [:label "Trigger a re-render: " | |
[:button {:on-click mutate-state!} "mutate-state!"]]] | |
(d3-in-charge @props)])) | |
chart-state | |
{:inspect-data true}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment