General performance improvements on workspace.

This commit is contained in:
Andrey Antukh 2020-05-01 18:05:13 +02:00
parent 00168d392b
commit 2ac42d15b6
10 changed files with 111 additions and 13 deletions

View file

@ -0,0 +1,47 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns uxbox.main.ui.components.defer
(:require
[rumext.alpha :as mf]
[uxbox.common.uuid :as uuid]
[uxbox.util.dom :as dom]
[uxbox.util.timers :as ts]
[goog.events :as events]
[goog.functions :as gf]
[goog.object :as gobj])
(:import goog.events.EventType
goog.events.KeyCodes))
(defn deferred
([component] (deferred component ts/raf))
([component schedule]
(mf/fnc deferred
{::mf/wrap-props false}
[props]
(let [[render? set-render!] (mf/useState false)]
(mf/use-effect
(fn [] (schedule #(set-render! true))))
(when render?
(mf/create-element component props))))))
(defn throttle
[component ms]
(mf/fnc throttle
{::mf/wrap-props false}
[props]
(let [[state set-state] (mf/useState props)
set-state* (mf/use-memo #(gf/throttle set-state ms))]
(mf/use-effect
nil
(fn []
(set-state* props)))
(mf/create-element component state))))

View file

@ -17,9 +17,11 @@
[uxbox.util.geom.shapes :as geom] [uxbox.util.geom.shapes :as geom]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.ui.components.defer :refer [deferred]]
[uxbox.main.ui.shapes.attrs :as attrs] [uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.ui.shapes.common :as common] [uxbox.main.ui.shapes.common :as common]
[uxbox.util.dom :as dom] [uxbox.util.dom :as dom]
[uxbox.util.timers :as ts]
[uxbox.util.interop :as itr] [uxbox.util.interop :as itr]
[uxbox.util.geom.matrix :as gmt] [uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt])) [uxbox.util.geom.point :as gpt]))
@ -53,7 +55,8 @@
[shape-wrapper] [shape-wrapper]
(let [frame-shape (frame-shape shape-wrapper)] (let [frame-shape (frame-shape shape-wrapper)]
(mf/fnc frame-wrapper (mf/fnc frame-wrapper
{::mf/wrap [#(mf/memo' % frame-wrapper-memo-equals?)] {::mf/wrap [#(deferred % ts/schedule-on-idle)
#(mf/memo' % frame-wrapper-memo-equals?)]
::mf/wrap-props false} ::mf/wrap-props false}
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")

View file

@ -10,21 +10,23 @@
(ns uxbox.main.ui.workspace.sidebar.layers (ns uxbox.main.ui.workspace.sidebar.layers
(:require (:require
[rumext.alpha :as mf]
[okulary.core :as l] [okulary.core :as l]
[uxbox.common.data :as d] [rumext.alpha :as mf]
[uxbox.builtins.icons :as i] [uxbox.builtins.icons :as i]
[uxbox.main.data.workspace :as dw] [uxbox.common.data :as d]
[uxbox.common.uuid :as uuid]
[uxbox.main.data.helpers :as dh] [uxbox.main.data.helpers :as dh]
[uxbox.main.data.workspace :as dw]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.ui.components.defer :refer [deferred]]
[uxbox.main.ui.hooks :as hooks] [uxbox.main.ui.hooks :as hooks]
[uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.shapes.icon :as icon] [uxbox.main.ui.shapes.icon :as icon]
[uxbox.util.dom :as dom] [uxbox.util.dom :as dom]
[uxbox.util.perf :as perf] [uxbox.util.timers :as ts]
[uxbox.common.uuid :as uuid] [uxbox.util.i18n :as i18n :refer [t]]
[uxbox.util.i18n :as i18n :refer [t]])) [uxbox.util.perf :as perf]))
;; --- Helpers ;; --- Helpers
@ -230,7 +232,8 @@
(mf/defc frame-wrapper (mf/defc frame-wrapper
{::mf/wrap-props false {::mf/wrap-props false
::mf/wrap [#(mf/memo' % frame-wrapper-memo-equals?)]} ::mf/wrap [#(deferred % ts/idle-then-raf)
#(mf/memo' % frame-wrapper-memo-equals?)]}
[props] [props]
[:> layer-item props]) [:> layer-item props])

View file

@ -15,6 +15,7 @@
[uxbox.main.data.workspace :as udw] [uxbox.main.data.workspace :as udw]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.refs :as refs] [uxbox.main.refs :as refs]
[uxbox.main.ui.components.defer :refer [throttle]]
[uxbox.main.ui.workspace.sidebar.align :refer [align-options]] [uxbox.main.ui.workspace.sidebar.align :refer [align-options]]
[uxbox.main.ui.workspace.sidebar.options.frame :as frame] [uxbox.main.ui.workspace.sidebar.options.frame :as frame]
[uxbox.main.ui.workspace.sidebar.options.group :as group] [uxbox.main.ui.workspace.sidebar.options.group :as group]
@ -30,6 +31,7 @@
;; --- Options ;; --- Options
(mf/defc shape-options (mf/defc shape-options
{::mf/wrap [#(throttle % 60)]}
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
[:div [:div
(case (:type shape) (case (:type shape)

View file

@ -17,10 +17,21 @@
[uxbox.main.ui.modal :as modal] [uxbox.main.ui.modal :as modal]
[uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]] [uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]]
[uxbox.util.dom :as dom] [uxbox.util.dom :as dom]
[uxbox.util.object :as obj]
[uxbox.util.math :as math] [uxbox.util.math :as math]
[uxbox.util.i18n :as i18n :refer [tr t]])) [uxbox.util.i18n :as i18n :refer [tr t]]))
(defn- fill-menu-memo-equals?
[np op]
(let [new-shape (obj/get np "shape")
old-shape (obj/get op "shape")]
(and (identical? (:fill-color new-shape)
(:fill-color old-shape))
(identical? (:fill-opacity new-shape)
(:fill-opacity old-shape)))))
(mf/defc fill-menu (mf/defc fill-menu
{::mf/wrap [#(mf/memo' % fill-menu-memo-equals?)]}
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [locale (i18n/use-locale) (let [locale (i18n/use-locale)

View file

@ -21,9 +21,10 @@
[uxbox.util.math :as math] [uxbox.util.math :as math]
[uxbox.util.i18n :refer [t] :as i18n])) [uxbox.util.i18n :refer [t] :as i18n]))
;; -- User/drawing coords ;; -- User/drawing coords
(defn user-coords-vector [shape]
(defn user-coords-vector
[shape]
(let [{sel-x :x sel-y :y :as selrect} (let [{sel-x :x sel-y :y :as selrect}
(-> shape (-> shape
gsh/shape->path gsh/shape->path
@ -35,11 +36,13 @@
dy (- rec-y sel-y)] dy (- rec-y sel-y)]
(gpt/point dx dy))) (gpt/point dx dy)))
(defn user->draw [{:keys [x y width height] :as shape}] (defn user->draw
[{:keys [x y width height] :as shape}]
(let [dv (user-coords-vector shape)] (let [dv (user-coords-vector shape)]
(-> shape (gsh/move dv)))) (-> shape (gsh/move dv))))
(defn draw->user [{:keys [x y width height] :as shape}] (defn draw->user
[{:keys [x y width height] :as shape}]
(let [dv (user-coords-vector shape)] (let [dv (user-coords-vector shape)]
(-> shape (gsh/move (gpt/negate dv))))) (-> shape (gsh/move (gpt/negate dv)))))

View file

@ -15,6 +15,7 @@
[uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]])) [uxbox.main.ui.workspace.sidebar.options.stroke :refer [stroke-menu]]))
(mf/defc options (mf/defc options
{::mf/wrap [mf/memo]}
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
[:div [:div
[:& measures-menu {:shape shape}] [:& measures-menu {:shape shape}]

View file

@ -17,10 +17,27 @@
[uxbox.main.ui.modal :as modal] [uxbox.main.ui.modal :as modal]
[uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]] [uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]]
[uxbox.util.dom :as dom] [uxbox.util.dom :as dom]
[uxbox.util.object :as obj]
[uxbox.util.i18n :as i18n :refer [tr t]] [uxbox.util.i18n :as i18n :refer [tr t]]
[uxbox.util.math :as math])) [uxbox.util.math :as math]))
(defn- stroke-menu-memo-equals?
[np op]
(let [new-shape (obj/get np "shape")
old-shape (obj/get op "shape")]
(and (identical? (:stroke-style new-shape)
(:stroke-style old-shape))
(identical? (:stroke-alignment new-shape)
(:stroke-alignment old-shape))
(identical? (:stroke-width new-shape)
(:stroke-width old-shape))
(identical? (:stroke-color new-shape)
(:stroke-color old-shape))
(identical? (:stroke-opacity new-shape)
(:stroke-opacity old-shape)))))
(mf/defc stroke-menu (mf/defc stroke-menu
{::mf/wrap [#(mf/memo' % stroke-menu-memo-equals?)]}
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [locale (i18n/use-locale) (let [locale (i18n/use-locale)
show-options (not= (:stroke-style shape) :none) show-options (not= (:stroke-style shape) :none)

View file

@ -23,6 +23,7 @@
[uxbox.main.streams :as ms] [uxbox.main.streams :as ms]
[uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.hooks :as hooks] [uxbox.main.ui.hooks :as hooks]
[uxbox.main.ui.components.defer :refer [deferred]]
[uxbox.main.ui.shapes :refer [shape-wrapper frame-wrapper]] [uxbox.main.ui.shapes :refer [shape-wrapper frame-wrapper]]
[uxbox.main.ui.workspace.drawarea :refer [draw-area start-drawing]] [uxbox.main.ui.workspace.drawarea :refer [draw-area start-drawing]]
[uxbox.main.ui.workspace.grid :refer [grid]] [uxbox.main.ui.workspace.grid :refer [grid]]
@ -102,6 +103,7 @@
(-> (rx/take-until stoper ms/mouse-position) (-> (rx/take-until stoper ms/mouse-position)
(rx/subscribe #(on-point dom reference %)))))))) (rx/subscribe #(on-point dom reference %))))))))
;; --- Viewport ;; --- Viewport
(declare remote-user-cursors) (declare remote-user-cursors)

View file

@ -32,3 +32,12 @@
(reify rx/IDisposable (reify rx/IDisposable
(-dispose [_] (-dispose [_]
(js/cancelIdleCallback sem))))) (js/cancelIdleCallback sem)))))
(defn raf
[f]
(js/window.requestAnimationFrame f))
(defn idle-then-raf
[f]
(schedule-on-idle #(raf f)))