Performance improvements

This commit is contained in:
alonso.torres 2021-05-13 15:02:06 +02:00 committed by Andrey Antukh
parent 91fe0b0985
commit b2e01cd52b
7 changed files with 122 additions and 139 deletions

View file

@ -174,9 +174,17 @@
"Checks if the given rect overlaps with the path in any point" "Checks if the given rect overlaps with the path in any point"
[shape rect] [shape rect]
(let [rect-points (gpr/rect->points rect) (let [;; If paths are too complex the intersection is too expensive
;; we fallback to check its bounding box otherwise the performance penalty
;; is too big
;; TODO: Look for ways to optimize this operation
simple? (> (count (:content shape)) 100)
rect-points (gpr/rect->points rect)
rect-lines (points->lines rect-points) rect-lines (points->lines rect-points)
path-lines (gpp/path->lines shape) path-lines (if simple?
(points->lines (:points shape))
(gpp/path->lines shape))
start-point (-> shape :content (first) :params (gpt/point))] start-point (-> shape :content (first) :params (gpt/point))]
(or (is-point-inside-nonzero? (first rect-points) path-lines) (or (is-point-inside-nonzero? (first rect-points) path-lines)

View file

@ -46,7 +46,7 @@ http {
listen 3449 default_server; listen 3449 default_server;
server_name _; server_name _;
client_max_body_size 5M; client_max_body_size 20M;
charset utf-8; charset utf-8;
proxy_http_version 1.1; proxy_http_version 1.1;

View file

@ -1164,11 +1164,15 @@
(ptk/reify ::update-shape-flags (ptk/reify ::update-shape-flags
ptk/WatchEvent ptk/WatchEvent
(watch [it state stream] (watch [it state stream]
(letfn [(update-fn [obj] (let [update-fn
(cond-> obj (fn [obj]
(boolean? blocked) (assoc :blocked blocked) (cond-> obj
(boolean? hidden) (assoc :hidden hidden)))] (boolean? blocked) (assoc :blocked blocked)
(rx/of (dch/update-shapes-recursive [id] update-fn)))))) (boolean? hidden) (assoc :hidden hidden)))
objects (wsh/lookup-page-objects state)
ids (d/concat [id] (cp/get-children id objects))]
(rx/of (dch/update-shapes ids update-fn))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -11,6 +11,7 @@
[app.common.pages.spec :as spec] [app.common.pages.spec :as spec]
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.worker :as uw] [app.main.worker :as uw]
[app.main.store :as st] [app.main.store :as st]
[app.util.logging :as log] [app.util.logging :as log]
@ -31,127 +32,75 @@
(def commit-changes? (ptk/type? ::commit-changes)) (def commit-changes? (ptk/type? ::commit-changes))
(defn- generate-operations (defn- generate-operation
([ma mb] (generate-operations ma mb false)) "Given an object old and new versions and an attribute will append into changes
([ma mb undo?] the set and undo operations"
(let [ops (let [ma-keys (set (keys ma)) [changes attr old new]
mb-keys (set (keys mb)) (let [old-val (get old attr)
added (set/difference mb-keys ma-keys) new-val (get new attr)]
removed (set/difference ma-keys mb-keys) (if (= old-val new-val)
both (set/intersection ma-keys mb-keys)] changes
(d/concat (-> changes
(mapv #(array-map :type :set :attr % :val (get mb %)) added) (update :rops conj {:type :set :attr attr :val new-val})
(mapv #(array-map :type :set :attr % :val nil) removed) (update :uops conj {:type :set :attr attr :val old-val :ignore-touched true})))))
(loop [items (seq both)
result []] (defn- update-shape-changes
(if items "Calculate the changes and undos to be done when a function is applied to a
(let [k (first items) single object"
vma (get ma k) [changes page-id objects update-fn attrs id]
vmb (get mb k)] (let [old-obj (get objects id)
(if (= vma vmb) new-obj (update-fn old-obj)
(recur (next items) result)
(recur (next items) attrs (or attrs (d/concat #{} (keys old-obj) (keys new-obj)))
(conj result {:type :set
:attr k {rops :rops uops :uops}
:val vmb (reduce #(generate-operation %1 %2 old-obj new-obj)
:ignore-touched undo?})))) {:rops [] :uops []}
result))))] attrs)
(if undo?
(conj ops {:type :set-touched :touched (:touched mb)}) uops (cond-> uops
ops)))) (not (empty? uops))
(conj {:type :set-touched :touched (:touched old-obj)}))
change {:type :mod-obj :page-id page-id :id id}]
(cond-> changes
(not (empty? rops))
(update :rch conj (assoc change :operations rops))
(not (empty? uops))
(update :uch conj (assoc change :operations uops)))))
(defn update-shapes (defn update-shapes
([ids f] (update-shapes ids f nil)) ([ids f] (update-shapes ids f nil))
([ids f {:keys [reg-objects? save-undo?] ([ids f {:keys [reg-objects? save-undo? keys]
:or {reg-objects? false save-undo? true}}] :or {reg-objects? false save-undo? true attrs nil}}]
(us/assert ::coll-of-uuid ids) (us/assert ::coll-of-uuid ids)
(us/assert fn? f) (us/assert fn? f)
(ptk/reify ::update-shapes (ptk/reify ::update-shapes
ptk/WatchEvent ptk/WatchEvent
(watch [it state stream] (watch [it state stream]
(let [page-id (:current-page-id state) (let [page-id (:current-page-id state)
objects (get-in state [:workspace-data :pages-index page-id :objects]) objects (wsh/lookup-page-objects state)
reg-objects {:type :reg-objects :page-id page-id :shapes (vec ids)}] reg-objects {:type :reg-objects :page-id page-id :shapes (vec ids)}
(loop [ids (seq ids)
rch []
uch []]
(if (nil? ids)
(rx/of (let [has-rch? (not (empty? rch))
has-uch? (not (empty? uch))
rch (cond-> rch (and has-rch? reg-objects?) (conj reg-objects))
uch (cond-> uch (and has-rch? reg-objects?) (conj reg-objects))]
(when (and has-rch? has-uch?)
(commit-changes {:redo-changes rch
:undo-changes uch
:origin it
:save-undo? save-undo?}))))
(let [id (first ids) {redo-changes :rch undo-changes :uch}
obj1 (get objects id) (reduce #(update-shape-changes %1 page-id objects f keys %2)
obj2 (f obj1) {:rch [] :uch []} ids)]
rch-operations (generate-operations obj1 obj2)
uch-operations (generate-operations obj2 obj1 true)
rchg {:type :mod-obj
:page-id page-id
:operations rch-operations
:id id}
uchg {:type :mod-obj
:page-id page-id
:operations uch-operations
:id id}]
(recur (next ids)
(if (empty? rch-operations) rch (conj rch rchg))
(if (empty? uch-operations) uch (conj uch uchg)))))))))))
(defn update-shapes-recursive (when-not (empty? redo-changes)
[ids f] (let [redo-changes (cond-> redo-changes
(us/assert ::coll-of-uuid ids) reg-objects? (conj reg-objects))
(us/assert fn? f)
(letfn [(impl-get-children [objects id]
(cons id (cp/get-children id objects)))
(impl-gen-changes [objects page-id ids] undo-changes (cond-> undo-changes
(loop [sids (seq ids) reg-objects? (conj reg-objects))]
cids (seq (impl-get-children objects (first sids)))
rchanges []
uchanges []]
(cond
(nil? sids)
[rchanges uchanges]
(nil? cids) (rx/of (commit-changes {:redo-changes redo-changes
(recur (next sids) :undo-changes undo-changes
(seq (impl-get-children objects (first (next sids)))) :origin it
rchanges :save-undo? save-undo?})))))))))
uchanges)
:else
(let [id (first cids)
obj1 (get objects id)
obj2 (f obj1)
rops (generate-operations obj1 obj2)
uops (generate-operations obj2 obj1 true)
rchg {:type :mod-obj
:page-id page-id
:operations rops
:id id}
uchg {:type :mod-obj
:page-id page-id
:operations uops
:id id}]
(recur sids
(next cids)
(conj rchanges rchg)
(conj uchanges uchg))))))]
(ptk/reify ::update-shapes-recursive
ptk/WatchEvent
(watch [it state stream]
(let [page-id (:current-page-id state)
objects (get-in state [:workspace-data :pages-index page-id :objects])
[rchanges uchanges] (impl-gen-changes objects page-id (seq ids))]
(rx/of (commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it})))))))
(defn update-indices (defn update-indices
[page-id changes] [page-id changes]
@ -222,4 +171,4 @@
(when (and save-undo? (seq undo-changes)) (when (and save-undo? (seq undo-changes))
(let [entry {:undo-changes undo-changes (let [entry {:undo-changes undo-changes
:redo-changes redo-changes}] :redo-changes redo-changes}]
(rx/of (dwu/append-undo entry))))))))))) (rx/of (dwu/append-undo entry)))))))))))

View file

@ -320,8 +320,7 @@
(rx/map snap/correct-snap-point) (rx/map snap/correct-snap-point)
(rx/map start-local-displacement)) (rx/map start-local-displacement))
(rx/of (set-modifiers ids) (rx/of (apply-modifiers ids {:set-modifiers? true})
(apply-modifiers ids)
(calculate-frame-for-move ids) (calculate-frame-for-move ids)
(finish-transform))))))))) (finish-transform)))))))))
@ -390,8 +389,7 @@
(rx/map start-local-displacement)) (rx/map start-local-displacement))
(rx/of (move-selected direction shift?))) (rx/of (move-selected direction shift?)))
(rx/of (set-modifiers selected) (rx/of (apply-modifiers selected {:set-modifiers? true})
(apply-modifiers selected)
(finish-transform)))) (finish-transform))))
(rx/empty)))))) (rx/empty))))))
@ -469,22 +467,46 @@
(rx/of (apply-modifiers ids))))))) (rx/of (apply-modifiers ids)))))))
(defn apply-modifiers (defn apply-modifiers
[ids] ([ids]
(us/verify (s/coll-of uuid?) ids) (apply-modifiers ids nil))
(ptk/reify ::apply-modifiers
ptk/WatchEvent ([ids {:keys [set-modifiers?]
(watch [it state stream] :or {set-modifiers? false}}]
(let [objects (wsh/lookup-page-objects state) (us/verify (s/coll-of uuid?) ids)
children-ids (->> ids (mapcat #(cp/get-children % objects))) (ptk/reify ::apply-modifiers
ids-with-children (d/concat [] children-ids ids) ptk/WatchEvent
object-modifiers (get state :workspace-modifiers)] (watch [it state stream]
(rx/of (dwu/start-undo-transaction) (let [objects (wsh/lookup-page-objects state)
(dch/update-shapes ids-with-children (fn [shape] children-ids (->> ids (mapcat #(cp/get-children % objects)))
(-> shape ids-with-children (d/concat [] children-ids ids)
(merge (get object-modifiers (:id shape)))
(gsh/transform-shape))) {:reg-objects? true}) state (if set-modifiers?
(clear-local-transform) (ptk/update (set-modifiers ids) state)
(dwu/commit-undo-transaction)))))) state)
object-modifiers (get state :workspace-modifiers)]
(rx/of (dwu/start-undo-transaction)
(dch/update-shapes
ids-with-children
(fn [shape]
(-> shape
(merge (get object-modifiers (:id shape)))
(gsh/transform-shape)))
{:reg-objects? true
;; Attributes that can change in the transform. This way we don't have to check
;; all the attributes
:attrs [:selrect :points
:x :y
:width :height
:content
:transform
:transform-inverse
:rotation
:flip-x
:flip-y]
})
(clear-local-transform)
(dwu/commit-undo-transaction)))))))
;; --- Update Dimensions ;; --- Update Dimensions

View file

@ -24,7 +24,7 @@
(.-parentNode shape-node) (.-parentNode shape-node)
(and (some? thumb-node) (= :frame type)) (and (some? thumb-node) (= :frame type))
thumb-node (.-parentNode thumb-node)
:else :else
shape-node)] shape-node)]

View file

@ -122,9 +122,9 @@
(into [] (into []
(comp (map #(unchecked-get % "data")) (comp (map #(unchecked-get % "data"))
(filter match-criteria?) (filter match-criteria?)
(filter overlaps?)
(filter (comp overlaps? :frame)) (filter (comp overlaps? :frame))
(filter (comp overlaps-masks? :masks)) (filter (comp overlaps-masks? :masks))
(filter overlaps?)
(map add-z-index)) (map add-z-index))
result) result)