It appears that disposal of reactive listeners is working properly now - my little performance test seems to demonstrate this.
This commit is contained in:
parent
3d959161b1
commit
d24ddf0125
4 changed files with 247 additions and 124 deletions
15
project.clj
15
project.clj
|
@ -7,9 +7,20 @@
|
|||
[org.clojure/clojurescript "0.0-2371"]]
|
||||
:profiles
|
||||
{:dev
|
||||
{:plugins [[com.cemerick/austin "0.1.5"]]
|
||||
{:plugins [[com.cemerick/austin "0.1.5"]
|
||||
[lein-cljsbuild "1.0.3"] ;; 1.0.3 is a requirement
|
||||
[lein-figwheel "0.1.5-SNAPSHOT"]]
|
||||
:dependencies
|
||||
[[com.cemerick/clojurescript.test "0.3.1"]]}}
|
||||
[[com.cemerick/clojurescript.test "0.3.1"]
|
||||
[figwheel "0.1.5-SNAPSHOT"]]
|
||||
:resource-paths ["example"]
|
||||
:cljsbuild {:builds [{:id "example"
|
||||
:source-paths ["src/clojure" "test"]
|
||||
:compiler {:output-to "resources/public/js/compiled/app.js"
|
||||
:output-dir "resources/public/js/compiled/out"
|
||||
:optimizations :none
|
||||
:source-map true}}]}
|
||||
}}
|
||||
:source-paths ["src/clojure"]
|
||||
:javac-options ["-Xlint:unchecked"]
|
||||
:java-source-paths ["src/java"])
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
(ns freactive.experimental.dom2)
|
||||
(ns freactive.experimental.dom2
|
||||
(:require [freactive.core :as r]
|
||||
[goog.object])
|
||||
(:require-macros [freactive.macros :refer [rx]]))
|
||||
|
||||
;; ## Core Defintions
|
||||
|
||||
(def ^:private element-spec-lookup #js {})
|
||||
(defonce ^:private element-state-lookup {})
|
||||
|
||||
(defprotocol IElementSpec
|
||||
(-get-virtual-dom [x]))
|
||||
|
@ -14,27 +17,42 @@
|
|||
(defn- dom-node? [x]
|
||||
(> (.-nodeType x) 0))
|
||||
|
||||
(defn- get-virtual-dom [x]
|
||||
(cond
|
||||
(dom-node? x)
|
||||
(get-virtual-dom (aget element-spec-lookup x))
|
||||
(string? x) x
|
||||
(vector? x) x
|
||||
:default (-get-virtual-dom x)))
|
||||
(defn- get-element-state [x]
|
||||
(get element-state-lookup x))
|
||||
|
||||
(defn- set-element-spec! [dom-node spec]
|
||||
(aset element-spec-lookup dom-node spec))
|
||||
(defn- get-virtual-dom [x]
|
||||
(when x
|
||||
(cond
|
||||
(dom-node? x)
|
||||
(when-let [state (get-element-state x)]
|
||||
(get-virtual-dom (.-element-spec state)))
|
||||
|
||||
(string? x) x
|
||||
|
||||
(vector? x) x
|
||||
|
||||
:default (-get-virtual-dom x))))
|
||||
|
||||
(defn- reset-element-spec! [dom-node spec]
|
||||
(set! (.-element-spec (get-element-state dom-node)) spec))
|
||||
|
||||
(defn- init-element-state! [dom-node element-spec]
|
||||
(let [state #js {:disposed false :element-spec element-spec :childstates {}}]
|
||||
(set! element-state-lookup (assoc element-state-lookup dom-node state))
|
||||
state))
|
||||
|
||||
(defn- register-with-parent-state [parent-state child state]
|
||||
(set! (.-childstates parent-state) (assoc (.-childstates parent-state) child state)))
|
||||
|
||||
(defn- unregister-from-parent-state [parent-state child]
|
||||
(set! (.-childstates parent-state) (dissoc (.-childstates parent-state) child)))
|
||||
|
||||
(defn- get-element-spec [x]
|
||||
(if (dom-node? x)
|
||||
(aget element-spec-lookup x)
|
||||
(when-let [state (aget element-state-lookup x)]
|
||||
(.-element-spec state))
|
||||
x))
|
||||
|
||||
(defn- get-transition [x transition-name]
|
||||
(let [spec (get-element-spec x)]
|
||||
(when-not (string? spec)
|
||||
(get (meta spec) transition-name))))
|
||||
|
||||
(defprotocol IHasDOMNode
|
||||
(-get-dom-node [x]))
|
||||
|
||||
|
@ -46,13 +64,68 @@
|
|||
(defprotocol IRemove
|
||||
(-remove! [x]))
|
||||
|
||||
(defn- remove-dom-node [x])
|
||||
(defn- dispose-node
|
||||
([dom-node]
|
||||
(dispose-node dom-node (get-element-state dom-node)))
|
||||
([dom-node state]
|
||||
;(println "diposing" dom-node state)
|
||||
(when state
|
||||
(set! (.-disposed state) true)
|
||||
(js-delete element-state-lookup dom-node)
|
||||
(doseq [[child state] (.-childstates state)]
|
||||
(dispose-node child state)))))
|
||||
|
||||
(defn- remove-dom-node [dom-node]
|
||||
(let [state (aget element-state-lookup dom-node)]
|
||||
(dispose-node dom-node state)
|
||||
(when-let [parent (.-parentNode dom-node)]
|
||||
(.removeChild parent dom-node)
|
||||
(when state
|
||||
(js-delete (.-parent-state state) state)))))
|
||||
|
||||
(defn remove! [x]
|
||||
(if (dom-node? x)
|
||||
(remove-dom-node x)
|
||||
(-remove! x)))
|
||||
|
||||
;; ## Defining Transitions
|
||||
|
||||
(defn- wrap-element-spec [elem-spec]
|
||||
(if (string? elem-spec)
|
||||
(ElementSpec. elem-spec)
|
||||
elem-spec))
|
||||
|
||||
(defn with-transitions [elem-spec transitions]
|
||||
(if (satisfies? IDeref elem-spec)
|
||||
(rx (with-transitions @elem-spec transitions))
|
||||
(vary-meta (wrap-element-spec elem-spec) merge transitions)))
|
||||
|
||||
(defn- get-transition [x transition-name]
|
||||
(let [spec (get-element-spec x)]
|
||||
(when-not (string? spec)
|
||||
(get (meta spec) transition-name))))
|
||||
|
||||
(defn- chain-transition [elem-spec transition-name transition-fn chain-fn]
|
||||
(if (satisfies? IDeref elem-spec)
|
||||
(rx (chain-transition @elem-spec transition-name transition-fn chain-fn))
|
||||
(let [cur-transition-fn (get-transition elem-spec transition-name)
|
||||
transition-fn (if cur-transition-fn
|
||||
(chain-fn cur-transition-fn transition-fn)
|
||||
transition-fn)]
|
||||
(with-transitions elem-spec {transition-name transition-fn}))))
|
||||
|
||||
(defn prepend-transition [elem-spec transition-name transition-fn]
|
||||
(chain-transition elem-spec transition-name transition-fn
|
||||
(fn [cur-tx new-tx]
|
||||
(fn [elem on-complete]
|
||||
(new-tx elem (fn [elem _] (cur-tx elem on-complete)))))) )
|
||||
|
||||
(defn append-transition [elem-spec transition-name transition-fn]
|
||||
(chain-transition elem-spec transition-name transition-fn
|
||||
(fn [cur-tx new-tx]
|
||||
(fn [elem on-complete]
|
||||
(cur-tx elem (fn [elem _] (new-tx elem on-complete)))))) )
|
||||
|
||||
;; ## Polyfills
|
||||
|
||||
(defn request-animation-frame [f]
|
||||
|
@ -68,7 +141,7 @@
|
|||
(let [attr-name (name attr-name)]
|
||||
(.setAttribute elem attr-name attr-value)))
|
||||
|
||||
(defn- on-value-ref-invalidated* [set-fn element attr-name ref]
|
||||
(defn- on-value-ref-invalidated* [set-fn element attr-name ref node-state]
|
||||
(when-let [[add-watch* remove-watch*] (r/get-add-remove-watch* ref)]
|
||||
(let [f (fn on-value-ref-invalidated
|
||||
([key ref _ _]
|
||||
|
@ -78,7 +151,7 @@
|
|||
(remove-watch* ref key)
|
||||
(request-animation-frame
|
||||
(fn [_]
|
||||
(when (.-parentNode element)
|
||||
(when-not (.-disposed node-state)
|
||||
(add-watch* ref key on-value-ref-invalidated)
|
||||
(set-fn element attr-name @ref))
|
||||
)
|
||||
|
@ -90,29 +163,29 @@
|
|||
(add-watch* ref [element attr-name] f)))
|
||||
(set-fn element attr-name @ref))
|
||||
|
||||
(defn bind-style-prop! [element attr-name attr-value]
|
||||
(defn bind-style-prop! [element attr-name attr-value node-state]
|
||||
(if (satisfies? cljs.core/IDeref attr-value)
|
||||
(on-value-ref-invalidated* set-style-prop! element attr-name attr-value)
|
||||
(on-value-ref-invalidated* set-style-prop! element attr-name attr-value node-state)
|
||||
(set-style-prop! element attr-name attr-value)))
|
||||
|
||||
(defn listen! [element evt-name handler]
|
||||
(.addEventListener element evt-name handler))
|
||||
|
||||
(defn bind-attr! [element attr-name attr-value]
|
||||
(defn bind-attr! [element attr-name attr-value node-state]
|
||||
(let [attr-name (name attr-name)]
|
||||
(cond
|
||||
(= "style" attr-name)
|
||||
(do
|
||||
(assert (map? attr-value))
|
||||
(doseq [[p v] attr-value]
|
||||
(bind-style-prop! element p v)))
|
||||
(bind-style-prop! element p v node-state)))
|
||||
|
||||
(= [\o \n \-] (take 3 attr-name))
|
||||
(listen! element (.substring attr-name 3) attr-value)
|
||||
|
||||
:default
|
||||
(if (satisfies? cljs.core/IDeref attr-value)
|
||||
(on-value-ref-invalidated* set-attr! element attr-name attr-value)
|
||||
(on-value-ref-invalidated* set-attr! element attr-name attr-value node-state)
|
||||
(set-attr! element attr-name attr-value)))))
|
||||
|
||||
;; From hiccup.compiler:
|
||||
|
@ -135,7 +208,6 @@
|
|||
|
||||
(declare build-element)
|
||||
|
||||
|
||||
(defn- replace-child [parent new-elem-spec cur-elem]
|
||||
(let [cur-dom-node (get-dom-node cur-elem)
|
||||
new-virtual-dom (get-virtual-dom new-elem-spec)]
|
||||
|
@ -144,23 +216,54 @@
|
|||
(= (.-nodeType cur-dom-node) 3))
|
||||
(do
|
||||
(set! (.-textContent cur-dom-node) new-virtual-dom)
|
||||
(set-element-spec! cur-dom-node new-elem-spec)
|
||||
(reset-element-spec! cur-dom-node new-elem-spec)
|
||||
cur-elem)
|
||||
(let [new-elem (build-element new-elem-spec)]
|
||||
(.replaceChild
|
||||
(get-dom-node parent)
|
||||
(get-dom-node new-elem)
|
||||
cur-dom-node)
|
||||
(dispose-node cur-dom-node)
|
||||
new-elem))))
|
||||
|
||||
(defn- append-child [parent new-elem]
|
||||
;;(println "appending" new-elem "to" parent)
|
||||
(let [new-elem (build-element new-elem)]
|
||||
(.appendChild
|
||||
(get-dom-node parent)
|
||||
(get-dom-node new-elem))
|
||||
new-elem)
|
||||
new-elem))
|
||||
|
||||
(defn- replace-or-append-child [parent new-elem cur-elem]
|
||||
(let [new-elem
|
||||
(if cur-elem
|
||||
(replace-child parent new-elem cur-elem)
|
||||
(append-child parent new-elem))]
|
||||
(when-let [parent-state (get-element-state parent)]
|
||||
;(println "parent-state" parent parent-state)
|
||||
(let [state (get-element-state new-elem)]
|
||||
(set! (.-parent-state state) parent-state)
|
||||
(register-with-parent-state parent-state new-elem state)))
|
||||
new-elem))
|
||||
|
||||
(defn- do-show-element [parent new-elem cur-elem]
|
||||
(when new-elem
|
||||
(let [show (get-transition new-elem :on-show)
|
||||
new-elem (replace-or-append-child parent new-elem cur-elem)]
|
||||
(when show
|
||||
(show new-elem nil)
|
||||
new-elem)
|
||||
new-elem)))
|
||||
|
||||
(defn- transition-element
|
||||
([parent new-elem cur-elem]
|
||||
;(println "transitioning" parent new-elem cur-elem)
|
||||
(if cur-elem
|
||||
(if-let [hide (get-transition cur-elem :on-hide)]
|
||||
(hide cur-elem
|
||||
(do-show-element parent new-elem cur-elem))
|
||||
(do-show-element parent new-elem cur-elem))
|
||||
(do-show-element parent new-elem cur-elem))))
|
||||
|
||||
(defn- clear-children! [parent]
|
||||
(let [dom-node (get-dom-node parent)]
|
||||
(loop []
|
||||
|
@ -169,84 +272,71 @@
|
|||
(.removeChild dom-node last-child)
|
||||
(recur))))))
|
||||
|
||||
(defn- replace-or-append-child [parent new-elem cur-elem]
|
||||
(if cur-elem
|
||||
(replace-child parent new-elem cur-elem)
|
||||
(append-child parent new-elem)))
|
||||
;; Reactive Element Handling
|
||||
|
||||
(defn- do-show-element [parent new-elem cur-elem]
|
||||
(let [show (get-transition new-elem :show)
|
||||
new-elem (replace-or-append-child parent new-elem cur-elem)]
|
||||
(when show
|
||||
(show new-elem nil))
|
||||
new-elem))
|
||||
(deftype ReactiveElement [parent cur-element dirty updating disposed invalidate]
|
||||
IRemove
|
||||
(-remove! [this]
|
||||
(set! (.-disposed this) true)
|
||||
(when-not updating
|
||||
(remove! @cur-element))
|
||||
(when-let [parent-state (get-element-state parent)]
|
||||
(unregister-from-parent-state parent-state this))))
|
||||
|
||||
(defn- transition-element
|
||||
([parent new-elem cur-elem]
|
||||
(if cur-elem
|
||||
(if-let [hide (get-transition cur-elem :hide)]
|
||||
(hide cur-elem
|
||||
(do-show-element parent new-elem cur-elem))
|
||||
(do-show-element parent new-elem cur-elem))
|
||||
(do-show-element parent new-elem cur-elem))))
|
||||
|
||||
;(defn remove-child! [parent child]
|
||||
; (if (instance? DerefElement child)
|
||||
; (cancel-and-remove-deref-element parent child)
|
||||
; (let [parent (as-dom-node parent)
|
||||
; child (as-dom-node child)]
|
||||
; (.removeChild parent child))))
|
||||
;
|
||||
(defn- append-deref-child [parent child-ref]
|
||||
(if-let [[add-watch* remove-watch*] (r/get-add-remove-watch* child-ref)]
|
||||
(let [cur-elem (atom nil)
|
||||
cancellation-token (atom false)
|
||||
f
|
||||
(let [state (ReactiveElement. parent nil false false false nil)
|
||||
|
||||
animate
|
||||
(fn animate [x]
|
||||
;(println "animating")
|
||||
(if (.-disposed state)
|
||||
(remove! (.-cur-element state))
|
||||
(do
|
||||
(set! (.-dirty state) false)
|
||||
(add-watch* child-ref state (.-invalidate state))
|
||||
(let [new-elem @child-ref
|
||||
cur (.-cur-element state)]
|
||||
;(println "cur" cur)
|
||||
(when (or (not cur)
|
||||
(not= (get-virtual-dom cur) (get-virtual-dom new-elem)))
|
||||
(set! (.-cur-element state)
|
||||
(transition-element
|
||||
parent
|
||||
(append-transition new-elem :on-show
|
||||
(fn [elem _]
|
||||
(set! (.-updating state) false)
|
||||
(if (.-disposed state)
|
||||
(remove! elem)
|
||||
(when
|
||||
(.-dirty state)
|
||||
(request-animation-frame animate)))))
|
||||
cur)))))))
|
||||
|
||||
invalidate
|
||||
(fn on-child-ref-invalidated
|
||||
([key child-ref _ _]
|
||||
(on-child-ref-invalidated key child-ref))
|
||||
([cur-elem child-ref]
|
||||
(remove-watch* child-ref cur-elem)
|
||||
(request-animation-frame
|
||||
(fn [x]
|
||||
(when (and ;;(.-parentNode parent)
|
||||
(not @cancellation-token)
|
||||
)
|
||||
(add-watch* child-ref cur-elem on-child-ref-invalidated)
|
||||
(let [new-elem (as-element-spec @child-ref)
|
||||
cur @cur-elem]
|
||||
(when (or (not cur)
|
||||
(not= (get-virtual-dom cur) (get-virtual-dom new-elem)))
|
||||
(reset! cur-elem
|
||||
(transition-element parent
|
||||
;new-elem
|
||||
(append-transition new-elem :show
|
||||
(fn [elem _]
|
||||
(when @cancellation-token
|
||||
(-remove elem))))
|
||||
cur)))))))))]
|
||||
(reset! cur-elem (transition-element parent [:span] nil))
|
||||
(f cur-elem child-ref)
|
||||
(ReactiveElement. child-ref cur-elem cancellation-token))
|
||||
(when-not (.-disposed state)
|
||||
;(println "invalidating")
|
||||
(set! (.-dirty state) true)
|
||||
(when-not (.-updating state)
|
||||
;(println "updating")
|
||||
(set! (.-updating state) true)
|
||||
(request-animation-frame animate)))))]
|
||||
(set! (.-invalidate state) invalidate)
|
||||
(set! (.-cur-element state) (transition-element parent (or @child-ref [:span]) nil))
|
||||
(when-let [parent-state (get-element-state parent)]
|
||||
(register-with-parent-state parent-state state state))
|
||||
(add-watch* child-ref state invalidate)
|
||||
state)
|
||||
(transition-element parent @child-ref nil)))
|
||||
|
||||
(deftype ReactiveElement [spec-ref cur-elem cancellation-token]
|
||||
IRemove
|
||||
(-remove [_]
|
||||
(reset! cancellation-token true)
|
||||
(-remove @cur-elem))
|
||||
;; Building Elements
|
||||
|
||||
IPrintWithWriter
|
||||
(-pr-writer [a writer opts]
|
||||
(-write writer "#<ReactiveElement: ")
|
||||
(pr-writer cur-elem writer opts)
|
||||
(-write writer " ")
|
||||
(pr-writer spec-ref writer opts)
|
||||
(-write writer " ")
|
||||
(pr-writer cancellation-token writer opts)
|
||||
(-write writer ">")))
|
||||
|
||||
(defn- append-child! [parent child]
|
||||
(defn append-child! [parent child]
|
||||
(cond
|
||||
(satisfies? IDeref child)
|
||||
(append-deref-child parent child)
|
||||
|
@ -266,15 +356,23 @@
|
|||
(let [virtual-dom (get-virtual-dom elem-spec)
|
||||
node
|
||||
(if (string? virtual-dom)
|
||||
(.createTextNode js/document virtual-dom)
|
||||
(let [node (.createTextNode js/document virtual-dom)]
|
||||
(init-element-state! node elem-spec)
|
||||
node)
|
||||
(let [node (create-dom-node (first virtual-dom))
|
||||
state (init-element-state! node elem-spec)
|
||||
attrs? (second virtual-dom)
|
||||
attrs (when (map? attrs?) attrs?)
|
||||
children (if attrs (nnext virtual-dom) (next virtual-dom))]
|
||||
(doseq [[k v] attrs]
|
||||
(bind-attr! node k v))
|
||||
(bind-attr! node k v state))
|
||||
(when children
|
||||
(append-children! node children))
|
||||
node))]
|
||||
(set-element-spec! node elem-spec)
|
||||
node))
|
||||
|
||||
(defn mount! [element child]
|
||||
;(println "mount!" element child)
|
||||
(when-let [last-child (.-lastChild (get-dom-node element))]
|
||||
(remove! last-child))
|
||||
(append-child! element child))
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
(defn bench [f]
|
||||
(time
|
||||
(dotimes [i 30000]
|
||||
(dotimes [i 100000]
|
||||
(f))))
|
||||
|
||||
(defprotocol ITest1
|
||||
|
@ -12,6 +12,10 @@
|
|||
ITest1
|
||||
(-do-something [this]))
|
||||
|
||||
(extend-protocol ITest1
|
||||
js/Object
|
||||
(-do-something [_]))
|
||||
|
||||
(defmulti test1 type)
|
||||
|
||||
(defn test1-string [x])
|
||||
|
@ -29,10 +33,14 @@
|
|||
|
||||
(def js0 #js {})
|
||||
|
||||
(def js1 #js [])
|
||||
|
||||
(def clj0 {})
|
||||
|
||||
(bench #(set! (.-x js0) 0))
|
||||
|
||||
(bench #(aset js1 0 0))
|
||||
|
||||
(bench #(assoc clj0 :x 0))
|
||||
|
||||
(def element-spec-lookup #js {})
|
||||
|
@ -108,3 +116,5 @@
|
|||
(remove-dom-node x)
|
||||
(-remove! x)))
|
||||
|
||||
|
||||
()
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
(ns freactive.dom-perf
|
||||
(:refer-clojure :exclude [atom])
|
||||
(:require
|
||||
[freactive.experimental.dom :as dom]
|
||||
[freactive.core :refer [atom cursor]])
|
||||
[freactive.experimental.dom2 :as dom]
|
||||
[freactive.core :refer [atom cursor]]
|
||||
[figwheel.client :as fw :include-macros true])
|
||||
(:require-macros
|
||||
[freactive.macros :refer [rx]]))
|
||||
|
||||
(defonce root (dom/append! (dom/get-body) [:div#root]))
|
||||
(enable-console-print!)
|
||||
|
||||
(defonce mouse-x (atom 0))
|
||||
|
||||
|
@ -31,7 +32,7 @@
|
|||
(defn circle [x y]
|
||||
[:svg/circle {:cx x :cy y :r 2 :stroke "black" :fill "black"}])
|
||||
|
||||
(defonce n (atom 7))
|
||||
(defonce n (atom 4))
|
||||
|
||||
(defn left-offset-x [i]
|
||||
(rx (* (inc i) (/ @mouse-x (inc @n)))))
|
||||
|
@ -49,35 +50,38 @@
|
|||
[:div
|
||||
|
||||
[:svg/svg
|
||||
{:width "100%" :height "100%"
|
||||
{:width "100%" :height "100%"
|
||||
:style {:position "absolute" :left 0 :top 0 }}
|
||||
(circle mouse-x mouse-y)
|
||||
(rx [:svg/g (for [i (range @n)] (circle (left-offset-x i) mouse-y))])
|
||||
(rx [:svg/g (for [i (range @n)] (circle (right-offset-x i) mouse-y))])
|
||||
(rx [:svg/g (for [j (range @n)] (circle mouse-x (top-offset-y j)))])
|
||||
(rx [:svg/g (for [j (range @n)] (circle mouse-x (bottom-offset-y j)))])
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(circle mouse-x mouse-y)
|
||||
(rx [:svg/g (for [i (range @n)] (circle (left-offset-x i) mouse-y))])
|
||||
(rx [:svg/g (for [i (range @n)] (circle (right-offset-x i) mouse-y))])
|
||||
(rx [:svg/g (for [j (range @n)] (circle mouse-x (top-offset-y j)))])
|
||||
(rx [:svg/g (for [j (range @n)] (circle mouse-x (bottom-offset-y j)))])
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(circle (left-offset-x i) (top-offset-y j)))])
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(circle (right-offset-x i) (top-offset-y j)))])
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(circle (left-offset-x i) (bottom-offset-y j)))])
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(rx [:svg/g (for [i (range @n) j (range @n)]
|
||||
(circle (right-offset-x i) (bottom-offset-y j)))])
|
||||
|
||||
[:svg/circle {:fill "red" :on-mousedown (fn [e] (swap! n dec))
|
||||
:r 8 :cx 8 :cy 8}]
|
||||
[:svg/circle {:fill "green" :on-mousedown (fn [e] (swap! n inc))
|
||||
:r 8 :cx 24 :cy 8}]
|
||||
]
|
||||
|
||||
[:span (rx (str @mouse-x ", " @mouse-y))
|
||||
". n = " (rx (str @n))
|
||||
". complexity = " (rx (str (let [n* @n n* (+ 1 (* 2 n*))]
|
||||
(* n* n*))))
|
||||
[:button {:on-click (fn [e]
|
||||
(println e)
|
||||
(swap! n dec))} "-"]
|
||||
|
||||
[:button {:on-click (fn [e]
|
||||
(println e)
|
||||
(swap! n inc))} "+"]
|
||||
]
|
||||
])
|
||||
]])
|
||||
|
||||
(dom/mount! root (view))
|
||||
(dom/mount! (.getElementById js/document "root") (view))
|
||||
|
||||
(fw/watch-and-reload
|
||||
;; :websocket-url "ws://localhost:3449/figwheel-ws" default
|
||||
;;:jsload-callback (fn [] (print "reloaded"))
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue