From b05908a760f64a7f6b1276396d11127d944c125c Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 29 Nov 2021 22:01:39 +0100 Subject: [PATCH] :zap: Improved performance for options and area selection --- .../app/main/data/workspace/selection.cljs | 54 +++++++++++-------- .../app/main/data/workspace/transforms.cljs | 2 +- .../app/main/ui/workspace/shapes/frame.cljs | 1 - .../app/main/ui/workspace/sidebar/layers.cljs | 9 +++- .../sidebar/options/shapes/multiple.cljs | 49 +++++++++++++---- 5 files changed, 77 insertions(+), 38 deletions(-) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 2fd5a2f3c..cc8331ffa 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -65,27 +65,33 @@ (watch [_ state stream] (let [zoom (get-in state [:workspace-local :zoom] 1) stop? (fn [event] (or (dwc/interrupt? event) (ms/mouse-up? event))) - stoper (->> stream (rx/filter stop?))] + stoper (->> stream (rx/filter stop?)) + + calculate-selrect + (fn [data pos] + (if data + (assoc data :stop pos) + {:start pos :stop pos})) + + selrect-stream + (->> ms/mouse-position + (rx/scan calculate-selrect nil) + (rx/map data->selrect) + (rx/filter #(or (> (:width %) (/ 10 zoom)) + (> (:height %) (/ 10 zoom)))) + (rx/take-until stoper))] (rx/concat - (when-not preserve? - (rx/of (deselect-all))) - (->> ms/mouse-position - (rx/scan (fn [data pos] - (if data - (assoc data :stop pos) - {:start pos :stop pos})) - nil) - (rx/map data->selrect) - (rx/filter #(or (> (:width %) (/ 10 zoom)) - (> (:height %) (/ 10 zoom)))) + (if preserve? + (rx/empty) + (rx/of (deselect-all))) - (rx/flat-map - (fn [selrect] - (rx/of (update-selrect selrect) - (select-shapes-by-current-selrect preserve?)))) + (rx/merge + (->> selrect-stream (rx/map update-selrect)) + (->> selrect-stream + (rx/debounce 50) + (rx/map #(select-shapes-by-current-selrect preserve?)))) - (rx/take-until stoper)) - (rx/of (update-selrect nil)))))))) + (rx/of (update-selrect nil)))))))) ;; --- Toggle shape's selection status (selected or deselected) @@ -221,11 +227,13 @@ selrect (get-in state [:workspace-local :selrect]) blocked? (fn [id] (get-in objects [id :blocked] false))] (when selrect - (->> (uw/ask! {:cmd :selection/query - :page-id page-id - :rect selrect - :include-frames? true - :full-frame? true}) + (rx/empty) + (->> (uw/ask-buffered! + {:cmd :selection/query + :page-id page-id + :rect selrect + :include-frames? true + :full-frame? true}) (rx/map #(cp/clean-loops objects %)) (rx/map #(into initial-set (filter (comp not blocked?)) %)) (rx/map select-shapes))))))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index cd2daa332..7dc694261 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -247,7 +247,7 @@ (gsh/calc-child-modifiers shape child modifiers ignore-constraints transformed-rect)] (cond-> modif-tree - (not (empty? (d/without-keys child-modifiers [:ignore-geometry?]))) + (d/not-empty? (d/without-keys child-modifiers [:ignore-geometry?])) (set-modifiers-recursive objects child child-modifiers diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index c43fd2c46..2637dbf90 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -59,7 +59,6 @@ [:& thumbnail {:shape shape}] [:rect {:x x :y y :width width :height height :style {:fill (or fill-color "white")}}]))) -;; used. (defn custom-deferred [component] (mf/fnc deferred diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 928a3e9d8..f23e7ab1f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -19,6 +19,7 @@ [app.util.keyboard :as kbd] [app.util.object :as obj] [app.util.timers :as ts] + [beicon.core :as rx] [cuerdas.core :as str] [okulary.core :as l] [rumext.alpha :as mf])) @@ -205,8 +206,12 @@ (mf/use-effect (mf/deps selected) (fn [] - (when (and (= (count selected) 1) selected?) - (.scrollIntoView (mf/ref-val dref) #js {:block "nearest", :behavior "smooth"})))) + (let [subid + (when (and (= (count selected) 1) selected?) + (ts/schedule-on-idle + #(.scrollIntoView (mf/ref-val dref) #js {:block "nearest", :behavior "smooth"})))] + #(when (some? subid) + (rx/dispose! subid))))) [:li {:on-context-menu on-context-menu :ref dref diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index e15e1b978..ff943abfa 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -9,6 +9,7 @@ [app.common.attrs :as attrs] [app.common.data :as d] [app.common.text :as txt] + [app.main.ui.hooks :as hooks] [app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu]] [app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]] [app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs fill-menu]] @@ -189,6 +190,14 @@ (def get-attrs (memoize get-attrs*)) +(defn basic-shape [_ shape] + (cond-> shape + :always + (dissoc :selrect :points :x :y :width :height :transform :transform-inverse :rotation :svg-transform :svg-viewbox :thumbnail) + + (= (:type shape) :path) + (dissoc :content))) + (mf/defc options {::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "shapes-with-children"]))] ::mf/wrap-props false} @@ -197,18 +206,36 @@ shapes-with-children (unchecked-get props "shapes-with-children") objects (->> shapes-with-children (group-by :id) (d/mapm (fn [_ v] (first v)))) - type :multiple - [measure-ids measure-values] (get-attrs shapes objects :measure) - [layer-ids layer-values] (get-attrs shapes objects :layer) - [constraint-ids constraint-values] (get-attrs shapes objects :constraint) - [fill-ids fill-values] (get-attrs shapes objects :fill) - [shadow-ids shadow-values] (get-attrs shapes objects :shadow) - [blur-ids blur-values] (get-attrs shapes objects :blur) - [stroke-ids stroke-values] (get-attrs shapes objects :stroke) + ;; Selrect/points only used for measures and it's the one that changes the most. We separate it + ;; so we can memoize it + objects-no-measures (->> objects (d/mapm basic-shape)) + objects-no-measures (hooks/use-equal-memo objects-no-measures) - ;; FIXME: Improve performance - [text-ids text-values] (get-attrs shapes objects :text) - ] + type :multiple + + [measure-ids measure-values] (get-attrs shapes objects :measure) + + [layer-ids layer-values + constraint-ids constraint-values + fill-ids fill-values + shadow-ids shadow-values + blur-ids blur-values + stroke-ids stroke-values + text-ids text-values] + + (mf/use-memo + (mf/deps objects-no-measures) + (fn [] + (into + [] + (mapcat identity) + [(get-attrs shapes objects-no-measures :layer) + (get-attrs shapes objects-no-measures :constraint) + (get-attrs shapes objects-no-measures :fill) + (get-attrs shapes objects-no-measures :shadow) + (get-attrs shapes objects-no-measures :shadow) + (get-attrs shapes objects-no-measures :stroke) + (get-attrs shapes objects-no-measures :text)])))] [:div.options (when-not (empty? measure-ids)