Mainly cosmetic and performance improvements on shape render.

This commit is contained in:
Andrey Antukh 2020-12-21 13:42:10 +01:00 committed by Alonso Torres
parent a3c583af1d
commit c5f4ae2242
6 changed files with 80 additions and 67 deletions

View file

@ -31,6 +31,7 @@
[app.main.ui.workspace.shapes.path :as path] [app.main.ui.workspace.shapes.path :as path]
[app.main.ui.workspace.shapes.text :as text] [app.main.ui.workspace.shapes.text :as text]
[app.util.object :as obj] [app.util.object :as obj]
[app.util.debug :refer [debug?]]
[beicon.core :as rx] [beicon.core :as rx]
[okulary.core :as l] [okulary.core :as l]
[rumext.alpha :as mf])) [rumext.alpha :as mf]))
@ -44,15 +45,17 @@
(defn- shape-wrapper-memo-equals? (defn- shape-wrapper-memo-equals?
[np op] [np op]
(let [n-shape (obj/get np "shape") (let [n-shape (obj/get np "shape")]
o-shape (obj/get op "shape")
n-frame (obj/get np "frame")
o-frame (obj/get op "frame")]
;; (prn "shape-wrapper-memo-equals?" (identical? n-frame o-frame))
(if (= (:type n-shape) :group) (if (= (:type n-shape) :group)
false false
(and (identical? n-shape o-shape) (let [o-shape (obj/get op "shape")
(identical? n-frame o-frame))))) n-frame (obj/get np "frame")
o-frame (obj/get op "frame")
n-ghost (obj/get np "ghost?")
o-ghost (obj/get op "ghost?")]
(and (identical? n-shape o-shape)
(identical? n-frame o-frame)
(identical? n-ghost o-ghost))))))
(defn make-is-moving-ref (defn make-is-moving-ref
[id] [id]
@ -94,7 +97,9 @@
;; Only used when drawing a new frame. ;; Only used when drawing a new frame.
:frame [:> frame-wrapper {:shape shape}] :frame [:> frame-wrapper {:shape shape}]
nil) nil)
[:& bounding-box {:shape shape :frame frame}]])))
(when (debug? :bounding-boxes)
[:& bounding-box {:shape shape :frame frame}])])))
(def group-wrapper (group/group-wrapper-factory shape-wrapper)) (def group-wrapper (group/group-wrapper-factory shape-wrapper))
(def frame-wrapper (frame/frame-wrapper-factory shape-wrapper)) (def frame-wrapper (frame/frame-wrapper-factory shape-wrapper))

View file

@ -44,7 +44,7 @@
:fill "transparent" :fill "transparent"
:stroke-width "1px" :stroke-width "1px"
:stroke-opacity 0.5 :stroke-opacity 0.5
:stroke-dasharray 4 :stroke-dasharray 4
:pointer-events "none"}}]) :pointer-events "none"}}])
(mf/defc render-rect-points [{:keys [points color]}] (mf/defc render-rect-points [{:keys [points color]}]
@ -59,37 +59,36 @@
(mf/defc bounding-box (mf/defc bounding-box
{::mf/wrap-props false} {::mf/wrap-props false}
[props] [props]
(when (debug? :bounding-boxes) (let [shape (-> (unchecked-get props "shape"))
(let [shape (-> (unchecked-get props "shape")) frame (unchecked-get props "frame")
frame (unchecked-get props "frame") selrect (gsh/points->selrect (-> shape :points))
selrect (gsh/points->selrect (-> shape :points)) shape-center (gsh/center-shape shape)
shape-center (gsh/center-shape shape) line-color (rdcolor #js {:seed (str (:id shape))})
line-color (rdcolor #js {:seed (str (:id shape))}) zoom (mf/deref refs/selected-zoom)
zoom (mf/deref refs/selected-zoom) childs-ref (mf/use-memo (mf/deps shape) #(refs/objects-by-id (:shapes shape)))
childs-ref (mf/use-memo (mf/deps shape) #(refs/objects-by-id (:shapes shape))) childs (->> (mf/deref childs-ref)
childs (->> (mf/deref childs-ref) (map gsh/transform-shape))]
(map gsh/transform-shape))]
[:g.bounding-box [:g.bounding-box
[:text {:x (:x selrect) [:text {:x (:x selrect)
:y (- (:y selrect) 5) :y (- (:y selrect) 5)
:font-size 10 :font-size 10
:fill line-color :fill line-color
:stroke "white" :stroke "white"
:stroke-width 0.1} :stroke-width 0.1}
(str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x shape)) (fixed (:y shape)))] (str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x shape)) (fixed (:y shape)))]
[:& cross-point {:point shape-center [:& cross-point {:point shape-center
:zoom zoom
:color line-color}]
(for [point (:points shape)]
[:& cross-point {:point point
:zoom zoom :zoom zoom
:color line-color}] :color line-color}])
(for [point (:points shape)] [:& render-rect-points {:rect selrect
[:& cross-point {:point point :color line-color}]
:zoom zoom
:color line-color}])
[:& render-rect-points {:rect selrect [:& render-rect {:rect selrect
:color line-color}] :color line-color}]]))
[:& render-rect {:rect selrect
:color line-color}]])))

View file

@ -68,10 +68,10 @@
(mf/defc frame-title (mf/defc frame-title
[{:keys [frame]}] [{:keys [frame]}]
(let [zoom (mf/deref refs/selected-zoom) (let [{:keys [width x y]} frame
{:keys [width x y]} frame zoom (mf/deref refs/selected-zoom)
label-pos (gpt/point x (- y (/ 10 zoom))) label-pos (gpt/point x (- y (/ 10 zoom)))
handle-click (use-select-shape frame) handle-click (use-select-shape frame)
handle-pointer-enter (we/use-pointer-enter frame) handle-pointer-enter (we/use-pointer-enter frame)
handle-pointer-leave (we/use-pointer-leave frame)] handle-pointer-leave (we/use-pointer-leave frame)]
[:text {:x 0 [:text {:x 0
@ -92,33 +92,47 @@
(contains? (:selected local) id)))] (contains? (:selected local) id)))]
(l/derived check-moving refs/workspace-local))) (l/derived check-moving refs/workspace-local)))
;; This custom deffered don't deffer rendering when ghost rendering is
;; used.
(defn custom-deferred
[component]
(mf/fnc deferred
{::mf/wrap-props false}
[props]
(let [tmp (mf/useState false)
^boolean render? (aget tmp 0)
^js set-render (aget tmp 1)]
(mf/use-layout-effect (fn [] (ts/schedule-on-idle #(set-render true))))
(if (unchecked-get props "ghost?")
(mf/create-element component props)
(when render? (mf/create-element component props))))))
(defn frame-wrapper-factory (defn frame-wrapper-factory
[shape-wrapper] [shape-wrapper]
(let [frame-shape (frame/frame-shape shape-wrapper)] (let [frame-shape (frame/frame-shape shape-wrapper)]
(mf/fnc frame-wrapper (mf/fnc frame-wrapper
{::mf/wrap [#(mf/memo' % frame-wrapper-factory-equals?) {::mf/wrap [#(mf/memo' % frame-wrapper-factory-equals?) custom-deferred]
#(mf/deferred % ts/schedule-on-idle)]
::mf/wrap-props false} ::mf/wrap-props false}
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
objects (unchecked-get props "objects") objects (unchecked-get props "objects")
ghost? (unchecked-get props "ghost?") ghost? (unchecked-get props "ghost?")
moving-iref (mf/use-memo (mf/deps (:id shape)) moving-iref (mf/use-memo (mf/deps (:id shape))
#(make-is-moving-ref (:id shape))) #(make-is-moving-ref (:id shape)))
moving? (mf/deref moving-iref) moving? (mf/deref moving-iref)
selected-iref (mf/use-memo (mf/deps (:id shape)) selected-iref (mf/use-memo (mf/deps (:id shape))
#(refs/make-selected-ref (:id shape))) #(refs/make-selected-ref (:id shape)))
selected? (mf/deref selected-iref) selected? (mf/deref selected-iref)
shape (gsh/transform-shape shape) shape (gsh/transform-shape shape)
children (mapv #(get objects %) (:shapes shape)) children (mapv #(get objects %) (:shapes shape))
ds-modifier (get-in shape [:modifiers :displacement]) ds-modifier (get-in shape [:modifiers :displacement])
handle-context-menu (we/use-context-menu shape) handle-context-menu (we/use-context-menu shape)
handle-double-click (use-select-shape shape) handle-double-click (use-select-shape shape)
handle-mouse-down (we/use-mouse-down shape)] handle-mouse-down (we/use-mouse-down shape)]
(when (and shape (when (and shape
(or ghost? (not moving?)) (or ghost? (not moving?))

View file

@ -167,6 +167,7 @@
shapes (if ids shapes (if ids
(->> ids (map #(get objects %))) (->> ids (map #(get objects %)))
shapes)] shapes)]
[:* [:*
[:g.shapes [:g.shapes
(for [item shapes] (for [item shapes]

View file

@ -16,7 +16,11 @@
(defn debug! [option] (swap! *debug* conj option)) (defn debug! [option] (swap! *debug* conj option))
(defn -debug! [option] (swap! *debug* disj option)) (defn -debug! [option] (swap! *debug* disj option))
(defn ^:export debug? [option] (@*debug* option)) (defn ^:export ^boolean debug?
[option]
(if *assert*
(boolean (@*debug* option))
false))
(defn ^:export toggle-debug [name] (let [option (keyword name)] (defn ^:export toggle-debug [name] (let [option (keyword name)]
(if (debug? option) (if (debug? option)
@ -28,7 +32,7 @@
(defn ^:export tap (defn ^:export tap
"Transducer function that can execute a side-effect `effect-fn` per input" "Transducer function that can execute a side-effect `effect-fn` per input"
[effect-fn] [effect-fn]
(fn [rf] (fn [rf]
(fn (fn
([] (rf)) ([] (rf))

View file

@ -27,16 +27,6 @@
;; percentiles of render time measures. The log function is ;; percentiles of render time measures. The log function is
;; automatically debouced for avod excesive spam to the console. ;; automatically debouced for avod excesive spam to the console.
;; #?(:clj
;; (defmacro with-measure
;; [name & body]
;; `(let [start# (js/performance.now)
;; res# (do ~@body)
;; end# (js/performance.now)
;; time# (.toFixed (- end# start#) 2)]
;; (println (str "[perf|" ~name "] => " time#))
;; res#)))
(defn tdigest (defn tdigest
[] []
(specify! (td/TDigest.) (specify! (td/TDigest.)
@ -111,7 +101,7 @@
(mf/deps label) (mf/deps label)
#(on-render-factory label))] #(on-render-factory label))]
(if enabled? (if enabled?
[:> react/Profiler {:id label [:> react/Profiler #js {:id label
:on-render on-render} :onRender on-render}
children] children]
children))) children)))