mirror of
https://github.com/penpot/penpot.git
synced 2025-07-20 15:07:11 +02:00
⚡ Performance improvements
This commit is contained in:
parent
91fe0b0985
commit
b2e01cd52b
7 changed files with 122 additions and 139 deletions
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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))))))
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
|
@ -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)))))))))))
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue