Revert some memoizes on page/helpers.

And improves base performance of get-children and
remove duplicated code. Also optimize the use
of get-children on react components with corresponding
use-memo hook.
This commit is contained in:
Andrey Antukh 2022-01-18 23:12:41 +01:00 committed by Andrés Moya
parent 1b3b3b0ee6
commit 072e4a4f98
5 changed files with 111 additions and 107 deletions

View file

@ -6,7 +6,9 @@
(ns app.common.geom.align (ns app.common.geom.align
(:require (:require
[app.common.data :as d]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages.helpers :refer [get-children]]
[clojure.spec.alpha :as s])) [clojure.spec.alpha :as s]))
;; --- Alignment ;; --- Alignment
@ -15,23 +17,13 @@
(declare calc-align-pos) (declare calc-align-pos)
;; TODO: revisit on how to reuse code and dont have this function
;; duplicated because the implementation right now differs from the
;; original function.
;; Duplicated from pages/helpers to remove cyclic dependencies
(defn- get-children [id objects]
(let [shapes (vec (get-in objects [id :shapes]))]
(if shapes
(into shapes (mapcat #(get-children % objects)) shapes)
[])))
(defn- recursive-move (defn- recursive-move
"Move the shape and all its recursive children." "Move the shape and all its recursive children."
[shape dpoint objects] [shape dpoint objects]
(let [children-ids (get-children (:id shape) objects) (->> (get-children (:id shape) objects)
children (map #(get objects %) children-ids)] (map (d/getf objects))
(map #(gsh/move % dpoint) (cons shape children)))) (cons shape)
(map #(gsh/move % dpoint))))
(defn align-to-rect (defn align-to-rect
"Move the shape so that it is aligned with the given rectangle "Move the shape so that it is aligned with the given rectangle

View file

@ -412,7 +412,7 @@
{:rotation angle {:rotation angle
:displacement displacement})) :displacement displacement}))
(defn merge-modifiers* (defn merge-modifiers
[objects modifiers] [objects modifiers]
(let [set-modifier (let [set-modifier
@ -422,8 +422,6 @@
(->> modifiers (->> modifiers
(reduce set-modifier objects)))) (reduce set-modifier objects))))
(def merge-modifiers (memoize merge-modifiers*))
(defn modifiers->transform (defn modifiers->transform
([modifiers] ([modifiers]
(modifiers->transform nil modifiers)) (modifiers->transform nil modifiers))

View file

@ -99,37 +99,10 @@
[component] [component]
(get-in component [:objects (:id component)])) (get-in component [:objects (:id component)]))
;; Implemented with transient for performance (defn get-children [id objects]
(defn get-children* (if-let [shapes (-> (get objects id) :shapes (some-> vec))]
"Retrieve all children ids recursively for a given object. The (into shapes (mapcat #(get-children % objects)) shapes)
children's order will be breadth first." []))
[id objects]
(loop [result (transient [])
pending (transient [])
next id]
(let [children (get-in objects [next :shapes] [])
[result pending]
;; Iterate through children and add them to the result
;; also add them in pending to check for their children
(loop [result result
pending pending
current (first children)
children (rest children)]
(if current
(recur (conj! result current)
(conj! pending current)
(first children)
(rest children))
[result pending]))
;; If we have still pending, advance the iterator
length (count pending)]
(if (pos? length)
(let [next (get pending (dec length))]
(recur result (pop! pending) next))
(persistent! result)))))
(def get-children (memoize get-children*))
(defn get-children-objects (defn get-children-objects
"Retrieve all children objects recursively for a given object" "Retrieve all children objects recursively for a given object"
@ -175,7 +148,7 @@
shape shape
(get objects (:frame-id shape)))) (get objects (:frame-id shape))))
(defn clean-loops* (defn clean-loops
"Clean a list of ids from circular references." "Clean a list of ids from circular references."
[objects ids] [objects ids]
@ -192,8 +165,6 @@
(reduce add-element (d/ordered-set) ids))) (reduce add-element (d/ordered-set) ids)))
(def clean-loops (memoize clean-loops*))
(defn calculate-invalid-targets (defn calculate-invalid-targets
[shape-id objects] [shape-id objects]
(let [result #{shape-id} (let [result #{shape-id}

View file

@ -101,10 +101,12 @@
bool-shape (bool/bool-shape shape-wrapper)] bool-shape (bool/bool-shape shape-wrapper)]
(mf/fnc bool-wrapper (mf/fnc bool-wrapper
[{:keys [shape] :as props}] [{:keys [shape] :as props}]
(let [childs (->> (cp/get-children (:id shape) objects) (let [childs (mf/use-memo
(select-keys objects))] (mf/deps (:id shape) objects)
[:& bool-shape {:shape shape (fn []
:childs childs}])))) (->> (cp/get-children (:id shape) objects)
(select-keys objects))))]
[:& bool-shape {:shape shape :childs childs}]))))
(defn svg-raw-wrapper-factory (defn svg-raw-wrapper-factory
[objects] [objects]
@ -221,26 +223,39 @@
(mf/defc frame-svg (mf/defc frame-svg
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [objects frame zoom] :or {zoom 1} :as props}] [{:keys [objects frame zoom] :or {zoom 1} :as props}]
(let [modifier (-> (gpt/point (:x frame) (:y frame)) (let [frame-id (:id frame)
(gpt/negate)
(gmt/translate-matrix))
frame-id (:id frame)
include-metadata? (mf/use-ctx export/include-metadata-ctx) include-metadata? (mf/use-ctx export/include-metadata-ctx)
modifier-ids (concat [frame-id] (cp/get-children frame-id objects)) modifier
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier) (mf/use-memo
objects (reduce update-fn objects modifier-ids) (mf/deps (:x frame) (:y frame))
frame (assoc-in frame [:modifiers :displacement] modifier) (fn []
(-> (gpt/point (:x frame) (:y frame))
(gpt/negate)
(gmt/translate-matrix))))
objects
(mf/use-memo
(mf/deps frame-id objects modifier)
(fn []
(let [update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)]
(->> (cp/get-children frame-id objects)
(into [frame-id])
(reduce update-fn objects)))))
frame
(mf/use-memo
(mf/deps modifier)
(fn [] (assoc-in frame [:modifiers :displacement] modifier)))
wrapper
(mf/use-memo
(mf/deps objects)
(fn [] (frame-wrapper-factory objects)))
width (* (:width frame) zoom) width (* (:width frame) zoom)
height (* (:height frame) zoom) height (* (:height frame) zoom)
vbox (format-viewbox {:width (:width frame 0) :height (:height frame 0)}) vbox (format-viewbox {:width (:width frame 0) :height (:height frame 0)})]
wrapper (mf/use-memo
(mf/deps objects)
#(frame-wrapper-factory objects))]
[:svg {:view-box vbox [:svg {:view-box vbox
:width (ust/format-precision width viewbox-decimal-precision) :width (ust/format-precision width viewbox-decimal-precision)
@ -254,19 +269,25 @@
(mf/defc component-svg (mf/defc component-svg
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]} {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
[{:keys [objects group zoom] :or {zoom 1} :as props}] [{:keys [objects group zoom] :or {zoom 1} :as props}]
(let [modifier (-> (gpt/point (:x group) (:y group)) (let [group-id (:id group)
(gpt/negate)
(gmt/translate-matrix))
group-id (:id group)
include-metadata? (mf/use-ctx export/include-metadata-ctx) include-metadata? (mf/use-ctx export/include-metadata-ctx)
modifier-ids (concat [group-id] (cp/get-children group-id objects)) modifier
(mf/use-memo
(mf/deps (:x group) (:y group))
(fn []
(-> (gpt/point (:x group) (:y group))
(gpt/negate)
(gmt/translate-matrix))))
objects
(mf/use-memo
(mf/deps modifier objects group-id)
(fn []
(let [modifier-ids (concat [group-id] (cp/get-children group-id objects))
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier) update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
modifiers (reduce update-fn {} modifier-ids) modifiers (reduce update-fn {} modifier-ids)]
objects (gsh/merge-modifiers objects modifiers) (gsh/merge-modifiers objects modifiers))))
group (get objects group-id) group (get objects group-id)
width (* (:width group) zoom) width (* (:width group) zoom)
@ -276,7 +297,7 @@
group-wrapper group-wrapper
(mf/use-memo (mf/use-memo
(mf/deps objects) (mf/deps objects)
#(group-wrapper-factory objects))] (fn [] (group-wrapper-factory objects)))]
[:svg {:view-box vbox [:svg {:view-box vbox
:width (ust/format-precision width viewbox-decimal-precision) :width (ust/format-precision width viewbox-decimal-precision)
@ -285,31 +306,51 @@
:xmlns "http://www.w3.org/2000/svg" :xmlns "http://www.w3.org/2000/svg"
:xmlnsXlink "http://www.w3.org/1999/xlink" :xmlnsXlink "http://www.w3.org/1999/xlink"
:xmlns:penpot (when include-metadata? "https://penpot.app/xmlns")} :xmlns:penpot (when include-metadata? "https://penpot.app/xmlns")}
[:> shape-container {:shape group} [:> shape-container {:shape group}
[:& group-wrapper {:shape group :view-box vbox}]]])) [:& group-wrapper {:shape group :view-box vbox}]]]))
(mf/defc component-symbol (mf/defc component-symbol
[{:keys [id data] :as props}] {::mf/wrap-props false}
[props]
(let [{:keys [name path objects]} data (let [id (obj/get props "id")
data (obj/get props "data")
name (:name data)
path (:path data)
objects (:objects data)
root (get objects id) root (get objects id)
selrect (:selrect root)
{:keys [width height]} (:selrect root) vbox
vbox (format-viewbox {:width width :height height}) (format-viewbox
{:width (:width selrect)
:height (:height selrect)})
modifier (-> (gpt/point (:x root) (:y root)) modifier
(mf/use-memo
(mf/deps (:x root) (:y root))
(fn []
(-> (gpt/point (:x root) (:y root))
(gpt/negate) (gpt/negate)
(gmt/translate-matrix)) (gmt/translate-matrix))))
modifier-ids (concat [id] (cp/get-children id objects)) objects
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier) (mf/use-memo
objects (reduce update-fn objects modifier-ids) (mf/deps modifier id objects)
root (assoc-in root [:modifiers :displacement] modifier) (fn []
(let [modifier-ids (concat [id] (cp/get-children id objects))
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)]
(reduce update-fn objects modifier-ids))))
root
(mf/use-memo
(mf/deps modifier root)
(fn [] (assoc-in root [:modifiers :displacement] modifier)))
group-wrapper group-wrapper
(mf/use-memo (mf/use-memo
(mf/deps objects) (mf/deps objects)
#(group-wrapper-factory objects))] (fn [] (group-wrapper-factory objects)))]
[:> "symbol" #js {:id (str id) [:> "symbol" #js {:id (str id)
:viewBox vbox :viewBox vbox
@ -321,7 +362,6 @@
(mf/defc components-sprite-svg (mf/defc components-sprite-svg
{::mf/wrap-props false} {::mf/wrap-props false}
[props] [props]
(let [data (obj/get props "data") (let [data (obj/get props "data")
children (obj/get props "children") children (obj/get props "children")
embed? (obj/get props "embed?") embed? (obj/get props "embed?")

View file

@ -96,18 +96,21 @@
::mf/wrap-props false} ::mf/wrap-props false}
[props] [props]
(let [shape (unchecked-get props "shape") (when-let [shape (unchecked-get props "shape")]
objects (unchecked-get props "objects") (let [objects (unchecked-get props "objects")
thumbnail? (unchecked-get props "thumbnail?") thumbnail? (unchecked-get props "thumbnail?")
children (-> (mapv (d/getf objects) (:shapes shape)) children
(hooks/use-equal-memo)) (-> (mapv (d/getf objects) (:shapes shape))
all-children (-> (cp/get-children-objects (:id shape) objects)
(hooks/use-equal-memo)) (hooks/use-equal-memo))
show-thumbnail? (and thumbnail? (some? (:thumbnail shape)))] all-children
(-> (cp/get-children-objects (:id shape) objects)
(hooks/use-equal-memo))
show-thumbnail?
(and thumbnail? (some? (:thumbnail shape)))]
(when (some? shape)
[:g.frame-wrapper {:display (when (:hidden shape) "none")} [:g.frame-wrapper {:display (when (:hidden shape) "none")}
[:> shape-container {:shape shape} [:> shape-container {:shape shape}
[:& ff/fontfaces-style {:shapes all-children}] [:& ff/fontfaces-style {:shapes all-children}]