From 9cee38920367d4266d13d371ab6acdbf886c99dc Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Thu, 3 Dec 2020 13:21:00 -0500 Subject: [PATCH 01/11] Detect touch screens to enable alternate UI elements --- src/cljs/wish/db.cljs | 1 + src/cljs/wish/events.cljs | 6 ++++++ src/cljs/wish/subs.cljs | 1 + src/cljs/wish/views.cljs | 5 +++++ 4 files changed, 13 insertions(+) diff --git a/src/cljs/wish/db.cljs b/src/cljs/wish/db.cljs index 83240887..9adbae76 100644 --- a/src/cljs/wish/db.cljs +++ b/src/cljs/wish/db.cljs @@ -3,6 +3,7 @@ (def default-db {:page [:splash] :device-type :default + :touch? false ; true if there is a touch screen :updates {:latest nil :ignored :unknown} diff --git a/src/cljs/wish/events.cljs b/src/cljs/wish/events.cljs index 45ddd15c..8c3cd56a 100755 --- a/src/cljs/wish/events.cljs +++ b/src/cljs/wish/events.cljs @@ -41,6 +41,12 @@ (fn-traced [db [device-type]] (assoc db :device-type device-type))) +(reg-event-db + :set-touch + [trim-v] + (fn-traced [db [touch?]] + (assoc db :touch? touch?))) + (reg-event-fx ::update-keymap [trim-v (inject-cofx ::inject/sub [:meta/kind])] diff --git a/src/cljs/wish/subs.cljs b/src/cljs/wish/subs.cljs index 9f4b43ce..c34f173a 100644 --- a/src/cljs/wish/subs.cljs +++ b/src/cljs/wish/subs.cljs @@ -16,6 +16,7 @@ (def ^:private non-storable-providers #{:wish :demo}) (reg-sub :device-type :device-type) +(reg-sub :touch? :touch?) (reg-sub :showing-overlay :showing-overlay) (reg-sub diff --git a/src/cljs/wish/views.cljs b/src/cljs/wish/views.cljs index 8d7dc186..6f88a67a 100644 --- a/src/cljs/wish/views.cljs +++ b/src/cljs/wish/views.cljs @@ -58,6 +58,11 @@ "(max-width: 479px)" [:set-device :smartphone] [:set-device :default]] + [media-tracker + "(hover: none) and (pointer: coarse)" [:set-touch true] + "(hover: none) and (pointer: fine)" [:set-touch true] + [:set-touch false]] + [error-boundary [router pages]] From d360ba295ffc2c94c990969253a013d2cf4a698c Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Thu, 3 Dec 2020 15:00:45 -0500 Subject: [PATCH 02/11] WIP: scaffold out UI for "spinning" the health --- src/cljs/wish/sheets/dnd5e/overlays/hp.cljs | 53 ++++++++++++++----- .../wish/sheets/dnd5e/overlays/style.cljs | 3 ++ .../wish/views/widgets/spinning_modifier.cljs | 34 ++++++++++++ 3 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 src/cljs/wish/views/widgets/spinning_modifier.cljs diff --git a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs index 26eb2f02..f902affa 100644 --- a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs +++ b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs @@ -12,7 +12,9 @@ [wish.views.widgets :as widgets :refer-macros [icon] :refer [expandable formatted-text]] - [wish.views.widgets.fast-numeric])) + [wish.views.widgets.fast-numeric] + [wish.views.widgets.spinning-modifier + :refer [spinning-modifier]])) (defn- condition-widget [[id level] _on-delete] @@ -191,6 +193,31 @@ :save! #(>evt [::events/temp-max-hp! %2])}]]]) +(defn- non-touchable-ui [{:keys [state hp max-hp max-mod new-hp]}] + [:<> + [:h4 "Hit Points"] + [hp-form + :hp hp + :max-hp max-hp + :max-mod max-mod] + + [:h5.centered.section-header "Quick Adjust"] + [quick-adjust-form state + :hp hp + :max-hp max-hp + :new-hp new-hp] + ]) + +(defn- touchable-ui [{:keys [state]}] + [:<> + [:h4 "Hit Points"] + + [:div.touchable + [spinning-modifier + state + :path [:heal]]] + ]) + ; ======= public interface ================================ (defn overlay [] @@ -198,27 +225,27 @@ (let [[hp max-hp max-mod] (v [v] + (assoc-in @ratom path v))] + (r/with-let [initial ( Date: Sun, 6 Dec 2020 22:33:12 -0500 Subject: [PATCH 03/11] WIP: use touchmove + touch-action to handle the rotation --- .../wish/views/widgets/spinning_modifier.cljs | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index cb471608..c4342a4f 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -1,13 +1,15 @@ (ns wish.views.widgets.spinning-modifier (:require [reagent.core :as r] - [spade.core :refer [defattrs]] + [spade.core :refer [defclass]] [wish.views.widgets.circular-progress :refer [circular-progress]])) -(defattrs spinning-modifier-attrs [] +(defclass spinning-modifier-class [] {:display 'inline-block :position 'relative} + [:.spinner {:touch-action 'none}] + [:.value {:position 'absolute :left 0 :right 0 @@ -24,11 +26,17 @@ (r/with-let [initial ( " x y)))} + [:div.spinner + [circular-progress + delta 100 + :stroke-width 12 + :width 128]] [:div.value "42" current] ])))) From 9716722c23f1e863e898b54f82c5eab42e4bb459 Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Mon, 7 Dec 2020 09:08:40 -0500 Subject: [PATCH 04/11] WIP: add crappy rotation math I think what we really need to do is actually map the touches to points on the circle and compute the arc length between them --- .../wish/views/widgets/spinning_modifier.cljs | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index c4342a4f..82dc0cdd 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -18,25 +18,58 @@ :transform "translateY(-50%)" }]) +(defn compute-rotation [element last-touch this-touch] + (let [[_ _ diameter] element ; assumes a square + circumference (* js/Math.PI diameter) + [ox oy] last-touch + [nx ny] this-touch + ;; ox (- ox x) oy (- oy y) + ;; nx (- nx x) ny (- ny y) + dx (- ox nx) + dy (- oy ny) + distance (js/Math.sqrt (* dx dx) + (* dy dy)) + direction 1] + (doto (* direction 360 (/ distance circumference)) + println))) + +(defn on-touch-move [state-ref rotation-ref, ^js e] + (let [touch (first (.-touches e)) + state @state-ref + this-touch [(.-clientX touch) (.-clientY touch)]] + (when-let [last-touch (:last-touch state)] + (swap! rotation-ref + (compute-rotation + (:element state) + last-touch + this-touch))) + (swap! state-ref assoc :last-touch this-touch))) + (defn spinning-modifier [ratom {:keys [path]}] (letfn [(v [v] (assoc-in @ratom path v))] - (r/with-let [initial ( " x y)))} - [:div.spinner + :on-touch-move (partial on-touch-move state rotation)} + [:div.spinner {:ref #(when-let [el %] + (let [rect (.getBoundingClientRect el)] + (swap! state assoc :element + [(.-x rect) (.-y rect) + (.-width rect) + (.-height rect)]))) + :style {:transform (str "rotate(" + @rotation + "deg)")}} [circular-progress - delta 100 + 2 100 ;; TODO ? + ;; delta 100 :stroke-width 12 :width 128]] - [:div.value "42" current] + [:div.value "42" delta current] ])))) From bab7c101204eaf9eea5624312715a26f3798e8d8 Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Mon, 7 Dec 2020 09:47:53 -0500 Subject: [PATCH 05/11] Use real math to make the rotation work "correctly"! --- .../wish/views/widgets/spinning_modifier.cljs | 40 +++++++++++++------ .../views/widgets/spinning_modifier_test.cljs | 14 +++++++ 2 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 test/cljs/wish/views/widgets/spinning_modifier_test.cljs diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index 82dc0cdd..de079f45 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -18,20 +18,34 @@ :transform "translateY(-50%)" }]) +(defn- polar-angle + "Given a box circumscribing a circle and a point relative to that box, + compute the polar coordinate angle of that point. In other words, + project the point onto the circumference of the circle, and get the + angle of the equivalent polar coordinate. + + 0 degrees is 'east'; 90 is 'south', etc" + [element point] + (let [[x y w] element + [px py] point + + ; shift the point so the box has origin at 0 0 + ; with radius w/2 + radius (/ w 2) + px (- px x radius) + py (- py y radius)] + + ; from: https://math.stackexchange.com/a/1744369 + (-> (js/Math.atan2 py px) + + ; convert to degreese + (* 180) + (/ js/Math.PI)))) + (defn compute-rotation [element last-touch this-touch] - (let [[_ _ diameter] element ; assumes a square - circumference (* js/Math.PI diameter) - [ox oy] last-touch - [nx ny] this-touch - ;; ox (- ox x) oy (- oy y) - ;; nx (- nx x) ny (- ny y) - dx (- ox nx) - dy (- oy ny) - distance (js/Math.sqrt (* dx dx) - (* dy dy)) - direction 1] - (doto (* direction 360 (/ distance circumference)) - println))) + (let [last-angle (polar-angle element last-touch) + this-angle (polar-angle element this-touch)] + (- this-angle last-angle))) (defn on-touch-move [state-ref rotation-ref, ^js e] (let [touch (first (.-touches e)) diff --git a/test/cljs/wish/views/widgets/spinning_modifier_test.cljs b/test/cljs/wish/views/widgets/spinning_modifier_test.cljs new file mode 100644 index 00000000..900e34eb --- /dev/null +++ b/test/cljs/wish/views/widgets/spinning_modifier_test.cljs @@ -0,0 +1,14 @@ +(ns wish.views.widgets.spinning-modifier-test + (:require [cljs.test :refer-macros [deftest testing is]] + [wish.views.widgets.spinning-modifier + :refer [compute-rotation]])) + +(deftest compute-rotation-test + (testing "Rotate" + (is (= 90 + (compute-rotation + [0 0 10 10] + + ; 3 o'clock to 6 o'clock + [10 5] [5 10]))))) + From 3c9fd0afba23ed1509b6377c20603c712cad7289 Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Mon, 7 Dec 2020 18:39:14 -0500 Subject: [PATCH 06/11] Start tweaking the delta computation based on rotation This exposes an issue where the rotation amount changes quite drastically when going across the 9 o'clock angle... --- src/cljs/wish/sheets/dnd5e/overlays/hp.cljs | 7 +++++- .../wish/views/widgets/spinning_modifier.cljs | 25 +++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs index f902affa..b1931f19 100644 --- a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs +++ b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs @@ -208,13 +208,18 @@ :new-hp new-hp] ]) -(defn- touchable-ui [{:keys [state]}] +(defn- touchable-ui [{:keys [state hp max-hp]}] [:<> [:h4 "Hit Points"] [:div.touchable [spinning-modifier state + :initial hp + :maximum (condp > max-hp + 50 15 + 100 25 + 30) :path [:heal]]] ]) diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index de079f45..7764be1e 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -15,8 +15,7 @@ :right 0 :text-align 'center :top :50% - :transform "translateY(-50%)" - }]) + :transform "translateY(-50%)"}]) (defn- polar-angle "Given a box circumscribing a circle and a point relative to that box, @@ -58,32 +57,36 @@ this-touch))) (swap! state-ref assoc :last-touch this-touch))) -(defn spinning-modifier [ratom {:keys [path]}] +(defn spinning-modifier [ratom & {:keys [initial maximum path]}] (letfn [(v [v] (assoc-in @ratom path v))] - (r/with-let [initial ( Date: Mon, 7 Dec 2020 19:46:25 -0500 Subject: [PATCH 07/11] Fix compute-rotation when going through 180 degrees Algorithm with thanks to my Flight Controls project! --- .../wish/views/widgets/spinning_modifier.cljs | 19 +++++++++++++------ .../views/widgets/spinning_modifier_test.cljs | 13 ++++++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index 7764be1e..38d666d6 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -35,16 +35,23 @@ py (- py y radius)] ; from: https://math.stackexchange.com/a/1744369 - (-> (js/Math.atan2 py px) + (js/Math.atan2 py px))) - ; convert to degreese - (* 180) - (/ js/Math.PI)))) +(def ^:private two-pi (* js/Math.PI 2)) (defn compute-rotation [element last-touch this-touch] (let [last-angle (polar-angle element last-touch) - this-angle (polar-angle element this-touch)] - (- this-angle last-angle))) + this-angle (polar-angle element this-touch) + delta (- this-angle last-angle) + normalized (cond + (> delta js/Math.PI) (- two-pi delta) + (< delta (- js/Math.PI)) (+ two-pi delta) + :else delta)] + (-> normalized + + ; convert to degrees: + (* 180) + (/ js/Math.PI)))) (defn on-touch-move [state-ref rotation-ref, ^js e] (let [touch (first (.-touches e)) diff --git a/test/cljs/wish/views/widgets/spinning_modifier_test.cljs b/test/cljs/wish/views/widgets/spinning_modifier_test.cljs index 900e34eb..2a1c51b3 100644 --- a/test/cljs/wish/views/widgets/spinning_modifier_test.cljs +++ b/test/cljs/wish/views/widgets/spinning_modifier_test.cljs @@ -4,11 +4,18 @@ :refer [compute-rotation]])) (deftest compute-rotation-test - (testing "Rotate" + (testing "Rotate from 3 o'clock to 6 o'clock" (is (= 90 (compute-rotation [0 0 10 10] - ; 3 o'clock to 6 o'clock - [10 5] [5 10]))))) + ; touches: + [10 5] [5 10])))) + + (testing "Rotate through 9 o'clock" + (is (< 0 + (compute-rotation + [0 0 10 10] + + [0 6] [0 4]))))) From 064e50c4a8f4d949dade44887a0f2759b5eb7665 Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Mon, 7 Dec 2020 21:09:05 -0500 Subject: [PATCH 08/11] Improve circle rendering and UX --- src/cljs/wish/sheets/dnd5e/overlays/hp.cljs | 8 +++--- .../wish/views/widgets/circular_progress.cljs | 13 ++++++---- .../wish/views/widgets/spinning_modifier.cljs | 26 +++++++++---------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs index b1931f19..22cf1674 100644 --- a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs +++ b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs @@ -216,10 +216,10 @@ [spinning-modifier state :initial hp - :maximum (condp > max-hp - 50 15 - 100 25 - 30) + :maximum max-hp + :per-rotation (condp > max-hp + 100 20 + 40) :path [:heal]]] ]) diff --git a/src/cljs/wish/views/widgets/circular_progress.cljs b/src/cljs/wish/views/widgets/circular_progress.cljs index cfee2f08..e8b72d4b 100644 --- a/src/cljs/wish/views/widgets/circular_progress.cljs +++ b/src/cljs/wish/views/widgets/circular_progress.cljs @@ -5,7 +5,8 @@ [wish.style :as theme] [wish.style.media :as media])) -(defattrs circular-progress-attrs [width circumference stroke-width] +(defattrs circular-progress-attrs [width circumference stroke-width + transition-duration] {:height (px width) :width (px width)} @@ -18,21 +19,23 @@ :stroke-width stroke-width :stroke theme/text-primary-on-light - :transition [[:stroke-dashoffset "0.35s"]] + :transition [[:stroke-dashoffset transition-duration]] :transform "rotate(-90deg)" :transform-origin [[:50% :50%]]} (at-media media/dark-scheme {:stroke theme/text-primary-on-dark})]) (defn circular-progress - [current max & {:keys [stroke-width width] + [current max & {:keys [stroke-width width transition-duration] :or {stroke-width 4 + transition-duration "0.35s" width 32}}] (let [radius (* 0.5 width) - inner-radius (- (/ width 2) (* 2 stroke-width)) + inner-radius (- radius (/ stroke-width 2)) circumference (* 2 inner-radius js/Math.PI) perc (/ current max)] - [:svg (circular-progress-attrs width circumference stroke-width) + [:svg (circular-progress-attrs width circumference stroke-width + transition-duration) [:circle.slot {:fill 'transparent :cx radius :cy radius diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index 38d666d6..61e7597d 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -64,15 +64,17 @@ this-touch))) (swap! state-ref assoc :last-touch this-touch))) -(defn spinning-modifier [ratom & {:keys [initial maximum path]}] +(defn spinning-modifier [ratom & {:keys [initial maximum + per-rotation path]}] (letfn [(v [v] (assoc-in @ratom path v))] (r/with-let [state (atom nil) rotation (r/atom 0)] - (let [delta (int (* maximum (/ @rotation 360))) - current (+ initial delta)] + (let [delta (int (* per-rotation (/ @rotation 360))) + current (min (+ initial delta) + maximum)] [:div {:class (spinning-modifier-class) :on-touch-move (partial on-touch-move state rotation) :on-touch-end #(swap! state dissoc :last-touch)} @@ -81,19 +83,17 @@ (swap! state assoc :element [(.-x rect) (.-y rect) (.-width rect) - (.-height rect)]))) - #_:style #_{:transform (str "rotate(" - @rotation - "deg)")}} - [circular-progress - delta maximum - ;; delta 100 - :stroke-width 12 - :width 128]] + (.-height rect)])))} + [circular-progress delta per-rotation + :transition-duration "0.2s" + :stroke-width 16 + :width 112]] [:div.value [:div.result current] (when-not (= 0 delta) - [:div.mod delta])] + [:div.mod + (when (> delta 0) "+") + delta])] ])))) From 1deb3974b8a5fa83e4bb2eea2d95efb058bd3f17 Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Mon, 7 Dec 2020 21:29:36 -0500 Subject: [PATCH 09/11] Colorize the spinner --- src/cljs/wish/sheets/dnd5e/overlays/hp.cljs | 4 ++++ src/cljs/wish/views/widgets/circular_progress.cljs | 10 +++++----- src/cljs/wish/views/widgets/spinning_modifier.cljs | 14 ++++++++++---- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs index 22cf1674..dbc1a0be 100644 --- a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs +++ b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs @@ -217,6 +217,10 @@ state :initial hp :maximum max-hp + :delta->color (fn delta->color [delta] + (cond + (> delta 0) "#00cc00" + (< delta 0) "#cc0000")) :per-rotation (condp > max-hp 100 20 40) diff --git a/src/cljs/wish/views/widgets/circular_progress.cljs b/src/cljs/wish/views/widgets/circular_progress.cljs index e8b72d4b..fd8abee2 100644 --- a/src/cljs/wish/views/widgets/circular_progress.cljs +++ b/src/cljs/wish/views/widgets/circular_progress.cljs @@ -6,7 +6,7 @@ [wish.style.media :as media])) (defattrs circular-progress-attrs [width circumference stroke-width - transition-duration] + transition-duration color] {:height (px width) :width (px width)} @@ -17,16 +17,16 @@ [:.circle {:stroke-dasharray [[circumference circumference]] :stroke-width stroke-width - :stroke theme/text-primary-on-light + :stroke (or color theme/text-primary-on-light) :transition [[:stroke-dashoffset transition-duration]] :transform "rotate(-90deg)" :transform-origin [[:50% :50%]]} (at-media media/dark-scheme - {:stroke theme/text-primary-on-dark})]) + {:stroke (or color theme/text-primary-on-dark)})]) (defn circular-progress - [current max & {:keys [stroke-width width transition-duration] + [current max & {:keys [stroke-width width transition-duration color] :or {stroke-width 4 transition-duration "0.35s" width 32}}] @@ -35,7 +35,7 @@ circumference (* 2 inner-radius js/Math.PI) perc (/ current max)] [:svg (circular-progress-attrs width circumference stroke-width - transition-duration) + transition-duration color) [:circle.slot {:fill 'transparent :cx radius :cy radius diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index 61e7597d..74ef718b 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -15,7 +15,9 @@ :right 0 :text-align 'center :top :50% - :transform "translateY(-50%)"}]) + :transform "translateY(-50%)"} + [:.mod {:font-size "110%" + :font-weight 'bold}]]) (defn- polar-angle "Given a box circumscribing a circle and a point relative to that box, @@ -65,7 +67,9 @@ (swap! state-ref assoc :last-touch this-touch))) (defn spinning-modifier [ratom & {:keys [initial maximum - per-rotation path]}] + delta->color + per-rotation path] + :or {delta->color (constantly nil)}}] (letfn [(v [v] @@ -74,7 +78,8 @@ rotation (r/atom 0)] (let [delta (int (* per-rotation (/ @rotation 360))) current (min (+ initial delta) - maximum)] + maximum) + color (delta->color delta)] [:div {:class (spinning-modifier-class) :on-touch-move (partial on-touch-move state rotation) :on-touch-end #(swap! state dissoc :last-touch)} @@ -85,6 +90,7 @@ (.-width rect) (.-height rect)])))} [circular-progress delta per-rotation + :color color :transition-duration "0.2s" :stroke-width 16 :width 112]] @@ -93,7 +99,7 @@ [:div.result current] (when-not (= 0 delta) - [:div.mod + [:div.mod {:style {:color color}} (when (> delta 0) "+") delta])] ])))) From 5547b8f9a9079424652c373faefee6a637d0b31c Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Sat, 12 Dec 2020 09:16:03 -0500 Subject: [PATCH 10/11] Add some animation to the spinning modifier to give it "haptics" --- .../wish/views/widgets/spinning_modifier.cljs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index 74ef718b..54e6c3de 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -1,9 +1,17 @@ (ns wish.views.widgets.spinning-modifier (:require [reagent.core :as r] - [spade.core :refer [defclass]] + [spade.core :refer [defattrs defclass defkeyframes]] [wish.views.widgets.circular-progress :refer [circular-progress]])) +; by accepting the delta, we ensure that the animation has "changed" +; every time they rotate, so this animation will restart, giving a +; ratchet-like effect, like the numbers "clicking" into place. +(defkeyframes grow-in [delta] + ^{:key delta} + [:from {:transform "scale(0.8)"}] + [:to {:transform "scale(1.0)"}]) + (defclass spinning-modifier-class [] {:display 'inline-block :position 'relative} @@ -19,6 +27,11 @@ [:.mod {:font-size "110%" :font-weight 'bold}]]) +(defattrs modifier-attrs [color delta] + ^{:key ""} ; we don't need to create a new class every time + {:animation [[(grow-in delta) "175ms" "cubic-bezier(0, 0, 0.2, 1)"]] + :color color}) + (defn- polar-angle "Given a box circumscribing a circle and a point relative to that box, compute the polar coordinate angle of that point. In other words, @@ -99,7 +112,7 @@ [:div.result current] (when-not (= 0 delta) - [:div.mod {:style {:color color}} + [:div.mod (modifier-attrs color delta) (when (> delta 0) "+") delta])] ])))) From d4b6cd8c03af61af636e646aed69c5239933e326 Mon Sep 17 00:00:00 2001 From: Daniel Leong Date: Sat, 12 Dec 2020 09:28:21 -0500 Subject: [PATCH 11/11] Support applying HP changes from the touchable UI --- src/cljs/wish/sheets/dnd5e/overlays/hp.cljs | 19 ++++++++++++++++--- .../wish/sheets/dnd5e/overlays/style.cljs | 5 ++++- .../wish/views/widgets/spinning_modifier.cljs | 8 ++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs index dbc1a0be..0cc17846 100644 --- a/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs +++ b/src/cljs/wish/sheets/dnd5e/overlays/hp.cljs @@ -16,6 +16,10 @@ [wish.views.widgets.spinning-modifier :refer [spinning-modifier]])) +(defn- apply-hp-delta! [delta max-hp] + (>evt [::events/update-hp delta max-hp]) + (>evt [:toggle-overlay nil])) + (defn- condition-widget [[id level] _on-delete] (let [c (get data/conditions id)] @@ -120,8 +124,7 @@ {:on-submit (fn-click (let [{:keys [heal damage]} @state] (log "Update HP: heal +" heal " -" damage) - (>evt [::events/update-hp (- heal damage) max-hp]) - (>evt [:toggle-overlay nil])))} + (apply-hp-delta! (- heal damage) max-hp)))} [:div.sections [:div.quick-adjust @@ -224,7 +227,17 @@ :per-rotation (condp > max-hp 100 20 40) - :path [:heal]]] + :path [:heal]] + + (when (let [delta (:heal @state)] + (and delta (not= 0 delta))) + [:div.sections + [:input.apply {:type 'button + :value "Apply!" + :on-click (fn-click + (apply-hp-delta! (:heal @state) max-hp)) + }] ]) + ] ]) ; ======= public interface ================================ diff --git a/src/cljs/wish/sheets/dnd5e/overlays/style.cljs b/src/cljs/wish/sheets/dnd5e/overlays/style.cljs index 0bebce7d..80787049 100644 --- a/src/cljs/wish/sheets/dnd5e/overlays/style.cljs +++ b/src/cljs/wish/sheets/dnd5e/overlays/style.cljs @@ -86,7 +86,10 @@ [:.section-header {:margin-bottom "0px"}] [:.touchable (merge flex/vertical - flex/align-center)] + flex/align-center) + [:input.apply (merge + styles/button + {:margin-top "1em"})]] [:.new-hp (merge styles/text-center {:padding "12px" diff --git a/src/cljs/wish/views/widgets/spinning_modifier.cljs b/src/cljs/wish/views/widgets/spinning_modifier.cljs index 54e6c3de..451a4ece 100644 --- a/src/cljs/wish/views/widgets/spinning_modifier.cljs +++ b/src/cljs/wish/views/widgets/spinning_modifier.cljs @@ -85,14 +85,18 @@ :or {delta->color (constantly nil)}}] (letfn [(v [v] - (assoc-in @ratom path v))] + (v< [v] + (swap! ratom assoc-in path v))] (r/with-let [state (atom nil) rotation (r/atom 0)] (let [delta (int (* per-rotation (/ @rotation 360))) current (min (+ initial delta) maximum) color (delta->color delta)] + + (when-not (= (