From 6b8b961d130a442d4cd46def733a32348c137882 Mon Sep 17 00:00:00 2001 From: Daniel Compton Date: Tue, 15 Nov 2016 15:06:10 +1300 Subject: [PATCH] Commit changes --- src/day8/re_frame/trace.cljs | 15 +- src/day8/re_frame/trace/d3.cljs | 113 +---- src/day8/re_frame/trace/graph.cljc | 86 ++++ src/day8/re_frame/trace/subvis.cljs | 564 ++++-------------------- test/day8/re_frame/trace/graph_test.clj | 53 +++ 5 files changed, 259 insertions(+), 572 deletions(-) create mode 100644 src/day8/re_frame/trace/graph.cljc create mode 100644 test/day8/re_frame/trace/graph_test.clj diff --git a/src/day8/re_frame/trace.cljs b/src/day8/re_frame/trace.cljs index 7429e15..b805aae 100644 --- a/src/day8/re_frame/trace.cljs +++ b/src/day8/re_frame/trace.cljs @@ -11,7 +11,10 @@ [reagent.ratom :as ratom] [re-frame.utils :as rutils] [goog.object :as gob] - [re-frame.interop :as interop])) + [re-frame.interop :as interop] + + [devtools.formatters.core :as devtools] + )) (defn comp-name [c] (let [n (or (component/component-path c) @@ -72,7 +75,8 @@ (fn [] (this-as c (trace/with-trace {:op-type key :operation (last (str/split (comp-name c) #" > ")) - :tags {:component-path (reagent.impl.component/component-path c)}}) + :tags {:component-path (reagent.impl.component/component-path c) + :reaction (rutils/reagent-id ($ c :cljsRatom))}}) (.call (real-custom-wrapper key f) c c))) (real-custom-wrapper key f)))) @@ -151,7 +155,9 @@ [:tbody (doall (for [{:keys [type id operation tags duration] :as trace} showing-traces] - (let [row-style (merge padding {:border-top (case type :event "1px solid lightgrey" nil)})] + (let [row-style (merge padding {:border-top (case type :event "1px solid lightgrey" nil)}) + _ (js/console.log (devtools/header-api-call tags)) + ] (list [:tr {:key id :style {:color (case type :sub/create "green" @@ -169,7 +175,8 @@ (.toFixed duration 1) " ms"]] (when true [:tr {:key (str id "-details")} - [:td {:col-span 3} (with-out-str (pprint/pprint (dissoc tags :query-v :event :duration)))]])))))]]])))) + [:td {:col-span 3} (with-out-str (pprint/pprint (dissoc tags :query-v :event :duration)))]]) + ))))]]])))) (defn resizer-style [draggable-area] {:position "absolute" :z-index 2 :opacity 0 diff --git a/src/day8/re_frame/trace/d3.cljs b/src/day8/re_frame/trace/d3.cljs index f0d95ab..95b7061 100644 --- a/src/day8/re_frame/trace/d3.cljs +++ b/src/day8/re_frame/trace/d3.cljs @@ -1,110 +1,37 @@ (ns day8.re-frame.trace.d3 (:require [reagent.core :as r])) -(defn component-did-update [{:keys [d3-enter d3-update d3-exit]} ratoms] - (apply d3-enter ratoms) - (apply d3-update ratoms) - (apply d3-exit ratoms)) - -(defn component-did-mount [{:keys [d3-did-mount] :as lifecycle-fns} ratoms] - (apply d3-did-mount ratoms) - (component-did-update lifecycle-fns ratoms)) - (defn no-op [desc] - (fn [& args] - (println "No-op" desc))) + (fn [& args] nil)) + +(defn component-did-update [{:keys [d3-update]} ratoms] + (apply d3-update ratoms)) + +(defn component-did-mount [{:keys [d3-once] :as lifecycle-fns} ratoms] + (apply d3-once ratoms) + (component-did-update lifecycle-fns ratoms)) (defn create-d3 "Creates a bridging component from Reagent to D3. Takes a map of lifecycle functions, and reactive data sources. :render-component - Render the outer Reagent component, and a place for your D3 component to mount to (probably an SVG element) - :d3-did-mount - Function called after the component has been rendered, for you to setup anything you need in D3 (e.g. adding or classes) - :d3-enter, :d3-update, :d3-exit - correspond to functions in the D3 general update pattern: https://bl.ocks.org/mbostock/3808218 + :d3-once - Function called after the component has been rendered, for you to setup anything you need in D3 (e.g. adding or classes) + :d3-update - Run the D3 general update pattern: https://bl.ocks.org/mbostock/3808218 " - [{:keys [render-component d3-did-mount d3-enter d3-update d3-exit] - :or {render-component no-op - d3-did-mount (no-op :d3-did-mount) - d3-enter (no-op :d3-enter) - d3-update (no-op :d3-update) - d3-exit (no-op :d3-exit)}} + [{:keys [render-component d3-once d3-update] + :or {render-component (no-op :render) + d3-once (no-op :d3-did-mount) + d3-update (no-op :d3-update)}} & ratoms] (let [lifecycle-fns {:render-component render-component - :d3-did-mount d3-did-mount - :d3-enter d3-enter - :d3-update d3-update - :d3-exit d3-exit}] + :d3-once d3-once + :d3-update d3-update}] (r/create-class {:reagent-render (fn [] (doseq [r ratoms] (deref r)) (apply render-component ratoms)) - :component-did-mount (fn [this] (component-did-mount lifecycle-fns ratoms)) - :component-did-update (fn [this old-argv] (component-did-update lifecycle-fns ratoms))})) - ) - - -;;;; -;;;; -;;; app -; -; -;(def data (r/atom {})) -; -;(defn my-render [ratom] -; (let [width 100 -; height 100] -; [:div -; {:id "barchart"} -; [:svg -; {:width width -; :height height}]])) -; -;(defn bars-did-mount [ratom] -; (-> (js/d3.select "#barchart svg") -; (.append "g") -; (.attr "class" "container") -; (.append "g") -; (.attr "class" "bars"))) -; -;(defn bars-enter [ratom] -; (let [data (get-data ratom)] -; (-> (js/d3.select "#barchart svg .container .bars") -; (.selectAll "rect") -; (.data (clj->js data)) -; .enter -; (.append "rect")))) -; -;(defn bars-update [ratom] -; (let [width (get-width ratom) -; height (get-height ratom) -; data (get-data ratom) -; data-n (count data) -; rect-height (/ height data-n) -; x-scale (-> js/d3 -; .scaleLinear -; (.domain #js [0 5]) -; (.range #js [0 width]))] -; (-> (js/d3.select "#barchart svg .container .bars") -; (.selectAll "rect") -; (.data (clj->js data)) -; (.attr "fill" "green") -; (.attr "x" (x-scale 0)) -; (.attr "y" (fn [_ i] -; (* i rect-height))) -; (.attr "height" (- rect-height 1)) -; (.attr "width" (fn [d] -; (x-scale (aget d "x"))))))) -; -;(defn bars-exit [ratom] -; (let [data (get-data ratom)] -; (-> (js/d3.select "#barchart svg .container .bars") -; (.selectAll "rect") -; (.data (clj->js data)) -; .exit -; .remove))) -; -;(create-d3 data {:reagent-render my-render -; :d3-did-mount bars-did-mount -; :d3-enter bars-enter -; :d3-update bars-update -; :d3-exit bars-exit}) + :component-did-mount (fn [this] + (component-did-mount lifecycle-fns ratoms)) + :component-did-update (fn [this old-argv] + (component-did-update lifecycle-fns ratoms))}))) diff --git a/src/day8/re_frame/trace/graph.cljc b/src/day8/re_frame/trace/graph.cljc new file mode 100644 index 0000000..e5a8680 --- /dev/null +++ b/src/day8/re_frame/trace/graph.cljc @@ -0,0 +1,86 @@ +(ns day8.re-frame.trace.graph + (:require [clojure.set :as set])) + +(defn select-type [type traces] + (filter #(= type (:type %)) traces)) + +(defn get-reaction [trace] + (get-in trace [:tags :reaction])) + +(defn distinct-k + "Returns a lazy sequence of the elements of coll with duplicates removed." + ([key-fn coll] + (let [step (fn step [xs seen] + (lazy-seq + ((fn [[f :as xs] seen] + (when-let [s (seq xs)] + (let [f-fn (key-fn f)] + (if (contains? seen f-fn) + (recur (rest s) seen) + (cons f (step (rest s) (conj seen f-fn))))))) + xs seen)))] + (step coll #{})))) + +(defn select-links [traces type disposed-ids link-val] + (->> traces + (select-type type) + (remove #(contains? disposed-ids (get-reaction %))) + (mapcat (fn [trace] + (for [input-signal (get-in trace [:tags :input-signals]) + :let [reaction (get-reaction trace)] + :when (every? some? [input-signal reaction])] + {:source input-signal :target reaction :value link-val + :id (str input-signal "|" reaction)}))) + (into {} (map (fn [trace] [(:id trace) trace]))) + (vals))) + +(defn select-sub-nodes [traces type disposed-ids r] + (->> traces + (select-type type) + (remove #(contains? disposed-ids (get-reaction %))) + (remove #(get-in % [:tags :cached?])) + (map (fn [trace] + {:id (get-reaction trace) + :title (str (:operation trace)) + :group 2 + :r r + :data trace})) + (into {} (map (fn [trace] [(:id trace) trace]))) + (vals))) + +(defn select-view-nodes [traces type unmounted-components r] + (->> traces + (select-type type) + (remove #(contains? unmounted-components (:id %))) + (map (fn [trace] + {:id (get-reaction trace) + :title (str (get-reaction trace) " " (:operation trace)) + :group 3 + :r r + :data trace + :fx 250})) + (remove #(nil? (:id %))) ;; remove reactions that are null (mostly from input fields???) + (into {} (map (fn [trace] [(:id trace) trace]))) + (vals) + )) + +(defn trace->sub-graph [traces extra-nodes] + (let [disposed-ids (->> (select-type :sub/dispose traces) + (map get-reaction) + set) + unmounted-components (->> (select-type :componentWillUnmount traces) + (map get-reaction) + set) + sub-nodes (select-sub-nodes traces :sub/create disposed-ids 10) + view-nodes (select-view-nodes traces :render unmounted-components 5) + sub-links (select-links traces :sub/run disposed-ids 1) + view-links (select-links traces :render unmounted-components 0.5) + all-nodes (concat extra-nodes sub-nodes view-nodes) + node-ids (set (map :id all-nodes)) + nodes-links (->> (mapcat (fn [{:keys [source target]}] [source target]) view-links) set) + missing-nodes (set/difference nodes-links node-ids) ;; These are local ratoms + view-links (->> view-links + (remove #(get missing-nodes (:source %)))) + all-links (concat sub-links view-links)] + {:nodes all-nodes + :links all-links})) diff --git a/src/day8/re_frame/trace/subvis.cljs b/src/day8/re_frame/trace/subvis.cljs index 770a375..efe911e 100644 --- a/src/day8/re_frame/trace/subvis.cljs +++ b/src/day8/re_frame/trace/subvis.cljs @@ -1,6 +1,7 @@ (ns day8.re-frame.trace.subvis (:require cljsjs.d3 [day8.re-frame.trace.d3 :as d3t] + [day8.re-frame.trace.graph :as graph] [reagent.core :as r] [re-frame.utils :as rutils] [re-frame.db :as db] @@ -8,80 +9,20 @@ [clojure.set :as set])) (def width 400) -(def height 200) +(def height 400) (def mygraph (r/atom {:nodes [{:id 1 :group 1} {:id 2 :group 1} {:id 3 :group 2}] :links [{:source 1 :target 2 :value 1}]})) -(defn trace->sub-graph [traces] - (let [disposed (->> traces - (filter #(#{:sub/dispose} (:type %))) - (map #(get-in % [:tags :reaction])) - set) - sub-nodes (->> traces - (filter #(#{:sub/create} (:type %))) - (remove #(contains? disposed (get-in % [:tags :reaction]))) - (remove #(get-in % [:tags :cached?])) - (map (fn [trace] - {:id (get-in trace [:tags :reaction]) - :title (str (:operation trace)) - :group (mod (:id trace) 20) - :r 10 - :data trace}))) +(def app-db-node {:id (rutils/reagent-id db/app-db) + :title "app-db" + :group 1 + :r 20 + :fx 15 + :fy (/ height 2)}) - unmounted-components #{} - view-nodes (->> traces - (filter #(#{:render} (:type %))) - (remove #(contains? unmounted-components (:id %))) ;; todo - (map (fn [trace] - {:id (get-in trace [:tags :reaction]) - :title (:operation trace) - :group (mod (:id trace) 20) - :r 5 - :data trace})) - - ) - - sub-links (->> traces - (filter #(#{:sub/run} (:type %))) - (remove #(contains? disposed (get-in % [:tags :reaction]))) - (mapcat (fn [trace] - (for [input-signal (get-in trace [:tags :input-signals]) - :let [reaction (get-in trace [:tags :reaction])] - :when (every? some? [input-signal reaction])] - {:source input-signal :target reaction :value 1})))) - - view-links (->> traces - (filter #(#{:render} (:type %))) - (remove #(contains? unmounted-components (get-in % [:tags :reaction]))) - (mapcat (fn [trace] - (for [input-signal (get-in trace [:tags :input-signals]) - :let [reaction (get-in trace [:tags :reaction])] - :when (every? some? [input-signal reaction])] - {:source input-signal :target reaction :value 0.5})))) - - app-db {:id (rutils/reagent-id db/app-db) - :title "app-db" - :group 1 - :r 20 - :fx (/ width 2) - :fy 30} - - - all-nodes (concat sub-nodes [app-db] view-nodes) - node-ids (set (map :id all-nodes)) - nodes-links (->> (mapcat (fn [{:keys [source target]}] [source target]) view-links) - set) - missing-nodes (set/difference nodes-links node-ids) ;; These are local ratoms - - view-links (->> view-links - (remove #(get missing-nodes (:source %)))) - ] - - {:nodes all-nodes - :links (concat sub-links view-links)})) (defn min-max "Returns x if it is within min-val and max-val @@ -93,267 +34,76 @@ (assert (<= min-val max-val)) (cljs.core/max min-val (cljs.core/min x max-val))) -(defn force-inner [graph] - (r/create-class - {:reagent-render (fn [] [:div [:svg {:width width :height height}]]) - :component-did-mount (fn [] - (let [nodes (clj->js (:nodes graph)) - links (clj->js (:links graph)) - color (.scaleOrdinal js/d3 (.-schemeCategory20 js/d3)) - svg (. js/d3 select "svg") - simulation (.. js/d3 - (forceSimulation) - (force "link" (.. js/d3 (forceLink) - (id #(.-id %)) - (distance (constantly 100)))) - (force "charge" (.. js/d3 (forceManyBody) - (strength (constantly -100)))) - (force "center" (. js/d3 forceCenter (/ width 2) (/ height 2)))) - - dragstarted (fn [d] - (when (zero? (.. js/d3 -event -active)) - (.. simulation - (alphaTarget 0.3) - (restart))) - - (set! (.-fx d) (.-x d)) - (set! (.-fy d) (.-y d))) - - dragged (fn [d] - (set! (.-fx d) (.. js/d3 -event -x)) - (set! (.-fy d) (.. js/d3 -event -y))) - - dragended (fn [d] - (when (zero? (.. js/d3 -event -active)) - (.. simulation - (alphaTarget 0.0))) - (set! (.-fx d) nil) - (set! (.-fy d) nil)) - - link (.. (. svg append "g") - (attr "class" "links") - (selectAll "line") - (data links) - (enter) - (append "line") - (attr "stroke-width" (fn [d] (Math/sqrt (.-value d))))) - - node (.. (. svg append "g") - (attr "class" "nodes") - (selectAll "circle") - (data nodes) - (enter) - (append "g") - (attr "class" "node")) - - circle (.. node - (append "circle") - (attr "r" #(or (gob/get % "r" 10))) - (attr "fill" (fn [d] (color (.-group d)))) - (call (.. (. js/d3 drag) - (on "start" dragstarted) - (on "drag" dragged) - (on "end" dragended)))) - - label (.. node - (append "text") - (attr "dy" ".35em") - (text #(gob/get % "title" ""))) - - ticked (fn [] - (.. link - (attr "x1" (fn [d] (.. d -source -x))) - (attr "y1" (fn [d] (.. d -source -y))) - (attr "x2" (fn [d] (.. d -target -x))) - (attr "y2" (fn [d] (.. d -target -y)))) - (.. circle - (attr "cx" (fn [d] (min-max (.. d -r) (.. d -x) (- width (.. d -r))))) - (attr "cy" (fn [d] (min-max (.. d -r) (.. d -y) (- height (.. d -r)))))) - (.. label - (attr "x" #(+ (.-x %) 2 (.-r %))) - (attr "y" #(+ (.-y %)))) - nil) - ] - - (.. simulation - (nodes nodes) - (on "tick" ticked)) - - (.. simulation - (force "link") - (links links)))) - - :component-did-update (fn [this] - #_(let [[_ data] (r/argv this) - d3data (clj->js data) - circles (.. js/d3 - (select "svg") - (selectAll "circle") - (data d3data (fn [d i] (when d (.-name d)))))] - (.. circles - ;(attr "cx" (fn [d] (.-x d))) - ;(attr "cy" (fn [d] (.-y d))) - ;(attr "r" (fn [d] (.-r d))) - enter - (append "circle") - (attr "cx" 200) - (attr "cy" 200) - (attr "r" 500) - (transition) - (attr "cx" (fn [d] (.-x d))) - (attr "cy" (fn [d] (.-y d))) - (attr "r" (fn [d] (.-r d))) - (attr "fill" (fn [d] (.-color d)))) - (.. circles - exit - remove)))})) - - -(defn force-outer [traces-ratom] +(defn ticked [selector] (fn [] - (let [trace-graph (trace->sub-graph @traces-ratom)] - [force-inner trace-graph]))) - -(defonce desc (r/atom 1)) + ;(println "ticked") + (let [link-sel (.. selector + (selectAll "g.links > line")) + circle-sel (.. selector + (selectAll "g.node > circle")) + label-sel (.. selector + (selectAll "g.node > text"))] + (.. link-sel + (attr "x1" (fn [d] (.. d -source -x))) + (attr "y1" (fn [d] (.. d -source -y))) + (attr "x2" (fn [d] (.. d -target -x))) + (attr "y2" (fn [d] (.. d -target -y)))) + (.. circle-sel + (attr "cx" (fn [d] (set! (.-x d) (min-max (.. d -r) (.. d -x) (- width (.. d -r)))))) + (attr "cy" (fn [d] (set! (.-y d) (min-max (.. d -r) (.. d -y) (- height (.. d -r))))))) + (.. label-sel + (attr "x" (fn [d] (+ 2 (.-x d) (.-r d)))) + (attr "y" #(+ (.-y %))))))) (defn render-subvis [traces-ratom] (let [color-a (atom nil) svg-a (atom nil) - simulation-a (atom nil)] + simulation-a (atom nil) + run? (atom false)] (fn [] + (println "Render subvis") [:div {:style {:padding "10px"}} [:h1 "SUBVIS"] - [force-outer traces-ratom] - [:hr] - [:h2 {:on-click #(swap! desc inc)} "Click"] - [(d3t/create-d3 - {:render-component (fn [ratom] - [:div - [:h1 (str "SVG")] - [:svg#d3cmp {:width width :height height}]]) - :d3-did-mount (fn [ratom] - (let [graph (trace->sub-graph @ratom) + [d3t/create-d3 + {:render-component (fn [ratom] + [:svg#d3cmp {:width width :height height}]) + :d3-once (fn [ratom] + (let [color (reset! color-a (.scaleOrdinal js/d3 (.-schemeCategory20 js/d3))) + svg (reset! svg-a (. js/d3 select "#d3cmp")) + simulation (reset! simulation-a + (.. js/d3 + (forceSimulation) + (force "link" (.. js/d3 (forceLink) + (id #(.-id %)) + (distance (constantly 100)))) + (force "charge" (.. js/d3 (forceManyBody) + (strength (constantly -100)))) + (force "center" (. js/d3 forceCenter (/ width 2) (/ height 2))))) + + link (.. (. svg append "g") + (attr "class" "links")) + + node (.. (. svg append "g") + (attr "class" "nodes"))])) + :d3-update (fn [ratom] + (when-not false #_@run? + #_(reset! run? true) + (let [graph (graph/trace->sub-graph @ratom [app-db-node]) nodes (clj->js (:nodes graph)) links (clj->js (:links graph)) - color (reset! color-a (.scaleOrdinal js/d3 (.-schemeCategory20 js/d3))) - svg (reset! svg-a (. js/d3 select "#d3cmp")) - simulation (reset! simulation-a - (.. js/d3 - (forceSimulation) - (force "link" (.. js/d3 (forceLink) - (id #(.-id %)) - (distance (constantly 100)))) - (force "charge" (.. js/d3 (forceManyBody) - (strength (constantly -100)))) - (force "center" (. js/d3 forceCenter (/ width 2) (/ height 2))))) - - dragstarted (fn [d] - (when (zero? (.. js/d3 -event -active)) - (.. simulation - (alphaTarget 0.3) - (restart))) - - (set! (.-fx d) (.-x d)) - (set! (.-fy d) (.-y d))) - - dragged (fn [d] - (set! (.-fx d) (.. js/d3 -event -x)) - (set! (.-fy d) (.. js/d3 -event -y))) - - dragended (fn [d] - (when (zero? (.. js/d3 -event -active)) - (.. simulation - (alphaTarget 0.0))) - (set! (.-fx d) nil) - (set! (.-fy d) nil)) - - link (.. (. svg append "g") - (attr "class" "links") - (selectAll "line") - (data links) - (enter) - (append "line") - (attr "stroke-width" (fn [d] (Math/sqrt (.-value d)))) - ) - - - node (.. (. svg append "g") - (attr "class" "nodes") - (selectAll "circle") - (data nodes) - (enter) - (append "g") - (attr "class" "node")) - - circle (.. node - (append "circle") - (attr "r" #(or (gob/get % "r" 10))) - (attr "fill" (fn [d] (color (.-group d)))) - (call (.. (. js/d3 drag) - (on "start" dragstarted) - (on "drag" dragged) - (on "end" dragended)))) - - - - label (.. node - (append "text") - (attr "dy" ".35em") - (text #(gob/get % "title" ""))) - - - - ticked (fn [] - (let [link-sel (.. svg - (selectAll ".links > line")) - circle-sel (.. svg - (selectAll ".node > circle")) - label-sel (.. svg - (selectAll ".node > text"))] - (.. link-sel - (attr "x1" (fn [d] (.. d -source -x))) - (attr "y1" (fn [d] (.. d -source -y))) - (attr "x2" (fn [d] (.. d -target -x))) - (attr "y2" (fn [d] (.. d -target -y)))) - (.. circle-sel - (attr "cx" (fn [d] (min-max (.. d -r) (.. d -x) (- width (.. d -r))))) - (attr "cy" (fn [d] (min-max (.. d -r) (.. d -y) (- height (.. d -r)))))) - (.. label-sel - (attr "x" #(+ (.-x %) 2 (.-r %))) - (attr "y" #(+ (.-y %))))) - nil) - ] - (.. simulation - (nodes nodes) - (on "tick" ticked)) - - (.. simulation - (force "link") - (links links)) - )) - :d3-enter (fn [ratom] - - (let [graph (trace->sub-graph @ratom) - nodes (clj->js (:nodes graph)) - links (clj->js (:links graph)) - svg @svg-a color @color-a simulation @simulation-a - _ (js/console.log "d3ent" (.. svg - (selectAll ".links > line") - size)) - dragstarted (fn [d] (when (zero? (.. js/d3 -event -active)) (.. simulation (alphaTarget 0.3) (restart))) - (set! (.-fx d) (.-x d)) - (set! (.-fy d) (.-y d))) + #_(set! (.-fx d) (.. js/d3 -event -x)) ; (.-x d) + #_(set! (.-fy d) (.. js/d3 -event -y))) dragged (fn [d] (set! (.-fx d) (.. js/d3 -event -x)) @@ -366,23 +116,27 @@ (set! (.-fx d) nil) (set! (.-fy d) nil)) - link (.. (. svg append "g") - (attr "class" "links") + link (.. svg + (select ".links") (selectAll "line") - (data links) + (data links (fn [d] (.-id d)))) + + new-link (.. link (enter) (append "line") (attr "stroke-width" (fn [d] (Math/sqrt (.-value d))))) - node (.. (. svg append "g") - (attr "class" "nodes") + node (.. svg + (select ".nodes") (selectAll "circle") - (data nodes) + (data nodes)) + + new-node (.. node (enter) (append "g") (attr "class" "node")) - circle (.. node + circle (.. new-node (append "circle") (attr "r" #(or (gob/get % "r" 10))) (attr "fill" (fn [d] (color (.-group d)))) @@ -391,174 +145,34 @@ (on "drag" dragged) (on "end" dragended)))) - - label (.. node + label (.. new-node (append "text") (attr "dy" ".35em") (text #(gob/get % "title" ""))) - ] + exit-node (.. node + (exit) + (remove "g")) + exit-link (.. link + (exit) + (remove "line")) + + ] + (println "Nodes count" (count nodes)) + (println "Links count" (count links)) + + (.. simulation + (nodes nodes) + (on "tick" (ticked svg))) (.. simulation (force "link") (links links)) - (println "D3 did enter") - (js/console.log "d3 ent done" (.. svg - (selectAll ".links > line") - size))))} - traces-ratom)] + (.. simulation + (alphaTarget 0.3) + (restart)) + + )))} + traces-ratom] [:hr]]))) - - - - -;;;;;;;;;;;;;;;;;;;;;;;;;; - - - - - - - - - - - -;(ns todomvc.subvis2 -; (:require [reagent.core :as r])) -; -;(defn prep-parent [parent] -; (-> parent -; (.selectAll "*") -; .remove) -; (.append parent "g")) -; -;(defn draw-circle [parent] -; (let [OUTER_WIDTH 208 -; OUTER_HEIGHT 208 -; parent (-> (js/d3.select parent) -; (.select "svg") -; (.attr "width" OUTER_WIDTH) -; (.attr "height" OUTER_HEIGHT))] -; -; ; Clear everything under the parent node so we can re-render it. -; (prep-parent parent) -; -; (let [top-node (.select parent "g") -; COLOR_CIRCLE "#fdb74a"] -; (.attr top-node -; "transform" -; (str "translate(" -; (/ OUTER_WIDTH 2.0) -; "," -; (/ OUTER_HEIGHT 2.0) -; ")")) -; -; (-> top-node -; (.append "circle") -; (.attr "cx" 0) -; (.attr "cy" 0) -; (.attr "r" 100) -; (.style "stroke" COLOR_CIRCLE))))) -; -;(defn d3-gauge [args] -; (let [dom-node (r/atom nil)] -; (r/create-class -; {:component-did-update -; (fn [this old-argv] -; (let [[_ args] (r/argv this)] -; ;; This is where we get to actually draw the D3 gauge. -; (draw-circle @dom-node))) -; -; :component-did-mount -; (fn [this] -; (let [node (r/dom-node this)] -; ;; This will trigger a re-render of the component. -; (reset! dom-node node))) -; -; :reagent-render -; (fn [args] -; ;; Necessary for Reagent to see that we depend on the dom-node r/atom. -; ;; Note: we don't actually use any of the args here. This is because -; ;; we cannot render D3 at this point. We have to wait for the update. -; @dom-node -; [:div.gauge [:svg]])}))) -; -; -;(def circles (r/atom [{:name "circle 1" -; :x 10 -; :y 10 -; :r 20 -; :color "black"} -; {:name "circle 2" -; :x 35 -; :y 35 -; :r 15 -; :color "red"} -; {:name "circle 3" -; :x 100 -; :y 100 -; :r 30 -; :color "blue"} -; {:name "circle 4" :x 55 :y 55 :r 10 :color "red"}])) -; -;(defn new-circle [] -; {:name (str (gensym "circle")) -; :x (rand-int 400) -; :y (rand-int 400) -; :r (+ 10 (rand-int 20)) -; :color (str "hsl(" (rand-int 360) ", 100%, 50%)")}) -; -;(defn add-new [n] -; (swap! circles conj (new-circle))) -; -;(defn d3-inner [data] -; (r/create-class -; {:reagent-render (fn [] [:div [:svg {:width 400 :height 800}]]) -; -; :component-did-mount (fn [] -; (let [d3data (clj->js data)] -; (.interval js/d3 add-new 1000) -; (.. js/d3 -; (select "svg") -; (selectAll "circle") -; (data d3data (fn [d i] (.-name d))) -; enter -; (append "circle") -; (attr "cx" (fn [d] (.-x d))) -; (attr "cy" (fn [d] (.-y d))) -; (attr "r" (fn [d] (.-r d))) -; (attr "fill" (fn [d] (.-color d)))))) -; -; :component-did-update (fn [this] -; (let [[_ data] (r/argv this) -; d3data (clj->js data) -; circles (.. js/d3 -; (select "svg") -; (selectAll "circle") -; (data d3data (fn [d i] (when d (.-name d)))))] -; (.. circles -; ;(attr "cx" (fn [d] (.-x d))) -; ;(attr "cy" (fn [d] (.-y d))) -; ;(attr "r" (fn [d] (.-r d))) -; enter -; (append "circle") -; (attr "cx" 200) -; (attr "cy" 200) -; (attr "r" 500) -; (transition) -; (attr "cx" (fn [d] (.-x d))) -; (attr "cy" (fn [d] (.-y d))) -; (attr "r" (fn [d] (.-r d))) -; (attr "fill" (fn [d] (.-color d)))) -; (.. circles -; exit -; remove)))})) -; -;(defn outer [] -; (let [data circles #_(subscribe [:circles])] -; (fn [] -; [d3-inner @data]))) -; -; diff --git a/test/day8/re_frame/trace/graph_test.clj b/test/day8/re_frame/trace/graph_test.clj new file mode 100644 index 0000000..00d78be --- /dev/null +++ b/test/day8/re_frame/trace/graph_test.clj @@ -0,0 +1,53 @@ +(ns day8.re-frame.trace.graph-test + (:require [day8.re-frame.trace.graph :as graph] + [clojure.test :refer :all])) + +(def t1 + '({:id 1, :operation :initialise-db, :type :event, :tags {:event [:initialise-db]}, :child-of nil} + {:id 2, :operation "todomvc.core.wrapper", :type :render, :tags {:component-path "todomvc.core.wrapper", :reaction "rx2", :input-signals ("ra18")}, :child-of nil} + {:id 5, :operation :sorted-todos, :type :sub/create, :tags {:query-v [:sorted-todos], :cached? false, :reaction "rx3"}, :child-of 4} + {:id 4, :operation :todos, :type :sub/create, :tags {:query-v [:todos], :cached? false, :reaction "rx4"}, :child-of 3} + {:id 7, :operation :sorted-todos, :type :sub/run, :tags {:query-v [:sorted-todos], :reaction "rx3", :input-signals ["ra5"]}, :child-of 6} + {:id 6, :operation :todos, :type :sub/run, :tags {:query-v [:todos], :reaction "rx4", :input-signals ["rx3"]}, :child-of 3} + {:id 3, :operation "todomvc.views.todo_app", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app", :reaction "rx6", :input-signals ("rx4")}, :child-of nil} + {:id 8, :operation "todomvc.views.task_entry", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.task_entry", :reaction nil, :input-signals nil}, :child-of nil} + {:id 9, :operation "todomvc.views.todo_input", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.task_entry > todomvc.views.todo_input", :reaction "rx7", :input-signals ("ra19")}, :child-of nil} + {:id 10, :operation "ReagentInput", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.task_entry > todomvc.views.todo_input > ReagentInput", :reaction nil, :input-signals nil}, :child-of nil} + {:id 13, :operation :todos, :type :sub/create, :tags {:query-v [:todos], :cached? true, :reaction "rx4"}, :child-of 12} + {:id 14, :operation :showing, :type :sub/create, :tags {:query-v [:showing], :cached? false, :reaction "rx8"}, :child-of 12} + {:id 12, :operation :visible-todos, :type :sub/create, :tags {:query-v [:visible-todos], :cached? false, :reaction "rx9"}, :child-of 11} + {:id 16, :operation :todos, :type :sub/create, :tags {:query-v [:todos], :cached? true, :reaction "rx4"}, :child-of 15} + {:id 15, :operation :all-complete?, :type :sub/create, :tags {:query-v [:all-complete?], :cached? false, :reaction "rx10"}, :child-of 11} + {:id 17, :operation :all-complete?, :type :sub/run, :tags {:query-v [:all-complete?], :reaction "rx10", :input-signals ["rx4"]}, :child-of 11} + {:id 19, :operation :showing, :type :sub/run, :tags {:query-v [:showing], :reaction "rx8", :input-signals ["ra5"]}, :child-of 18} + {:id 18, :operation :visible-todos, :type :sub/run, :tags {:query-v [:visible-todos], :reaction "rx9", :input-signals ("rx4" "rx8")}, :child-of 11} + {:id 11, :operation "todomvc.views.task_list", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.task_list", :reaction "rx11", :input-signals ("rx10" "rx9")}, :child-of nil} + {:id 20, :operation "ReagentInput", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.task_list > ReagentInput", :reaction nil, :input-signals nil}, :child-of nil} + {:id 21, :operation "todomvc.views.todo_item", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.task_list > todomvc.views.todo_item", :reaction "rx12", :input-signals ("ra20" "ra20")}, :child-of nil} + {:id 22, :operation "ReagentInput", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.task_list > todomvc.views.todo_item > ReagentInput", :reaction nil, :input-signals nil}, :child-of nil} + {:id 24, :operation :footer-counts, :type :sub/create, :tags {:query-v [:footer-counts], :cached? false, :reaction "rx13"}, :child-of 23} + {:id 25, :operation :showing, :type :sub/create, :tags {:query-v [:showing], :cached? true, :reaction "rx8"}, :child-of 23} + {:id 27, :operation :todos, :type :sub/create, :tags {:query-v [:todos], :cached? true, :reaction "rx4"}, :child-of 26} + {:id 29, :operation :todos, :type :sub/create, :tags {:query-v [:todos], :cached? true, :reaction "rx4"}, :child-of 28} + {:id 28, :operation :completed-count, :type :sub/create, :tags {:query-v [:completed-count], :cached? false, :reaction "rx14"}, :child-of 26} + {:id 30, :operation :completed-count, :type :sub/run, :tags {:query-v [:completed-count], :reaction "rx14", :input-signals ["rx4"]}, :child-of 26} + {:id 26, :operation :footer-counts, :type :sub/run, :tags {:query-v [:footer-counts], :reaction "rx13", :input-signals ("rx4" "rx14")}, :child-of 23} + {:id 23, :operation "todomvc.views.footer_controls", :type :render, :tags {:component-path "todomvc.core.wrapper > todomvc.views.todo_app > todomvc.views.footer_controls", :reaction "rx15", :input-signals ("rx13" "rx8" "rx8" "rx8")}, :child-of nil})) + +(deftest sub-graph-test + (is (= {:links [] + :nodes [{:id "rx4" + :r 10 + :title "" + :group 2 + :data {:id 1 + :tags {:cached? false + :reaction "rx4"} + :type :sub/create}}]} + (graph/trace->sub-graph [{:id 1 :type :sub/create :tags {:cached? false :reaction "rx4"}}] [])))) + +(deftest dispose-view-test + (is (= {:links [] + :nodes []} + (graph/trace->sub-graph [{:id 1 :type :render :tags {:cached? false :reaction "rx4"}} + {:id 2 :type :componentWillUnmount :tags {:reaction "rx4"}}] []))))