mirror of
https://github.com/penpot/penpot.git
synced 2025-03-11 23:31:21 -05:00
⚡ Improve performance of z-index update
This commit is contained in:
parent
285a0d5f47
commit
32b623e82b
4 changed files with 94 additions and 54 deletions
|
@ -67,6 +67,7 @@
|
|||
|
||||
;; Indices
|
||||
(d/export indices/calculate-z-index)
|
||||
(d/export indices/update-z-index)
|
||||
(d/export indices/generate-child-all-parents-index)
|
||||
(d/export indices/generate-child-parent-index)
|
||||
(d/export indices/create-mask-index)
|
||||
|
|
|
@ -9,43 +9,70 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as helpers]
|
||||
[app.common.uuid :as uuid]))
|
||||
[app.common.uuid :as uuid]
|
||||
[clojure.set :as set]))
|
||||
|
||||
(defn calculate-frame-z-index [z-index frame-id objects]
|
||||
(let [is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
||||
frame-shapes (->> objects (vals) (filterv #(= (:frame-id %) frame-id)))
|
||||
children (or (get-in objects [frame-id :shapes]) [])]
|
||||
|
||||
(if (empty? children)
|
||||
z-index
|
||||
|
||||
(loop [current (peek children)
|
||||
pending (pop children)
|
||||
current-idx (count frame-shapes)
|
||||
z-index z-index]
|
||||
|
||||
(let [children (get-in objects [current :shapes])
|
||||
is-frame? (is-frame? current)
|
||||
pending (if (not is-frame?)
|
||||
(d/concat pending children)
|
||||
pending)]
|
||||
|
||||
(if (empty? pending)
|
||||
(-> z-index
|
||||
(assoc current current-idx))
|
||||
|
||||
(recur (peek pending)
|
||||
(pop pending)
|
||||
(dec current-idx)
|
||||
(assoc z-index current current-idx))))))))
|
||||
|
||||
;; The z-index is really calculated per-frame. Every frame will have its own
|
||||
;; internal z-index. To calculate the "final" z-index we add the shape z-index with
|
||||
;; the z-index of its frame. This way we can update the z-index per frame without
|
||||
;; the need of recalculate all the frames
|
||||
(defn calculate-z-index
|
||||
"Given a collection of shapes calculates their z-index. Greater index
|
||||
means is displayed over other shapes with less index."
|
||||
[objects]
|
||||
(let [is-frame? (fn [id] (= :frame (get-in objects [id :type])))
|
||||
root-children (or (get-in objects [uuid/zero :shapes]) [])
|
||||
num-frames (->> root-children (filterv is-frame?) count)]
|
||||
|
||||
(when-not (empty? root-children)
|
||||
(loop [current (peek root-children)
|
||||
pending (pop root-children)
|
||||
current-idx (+ (count objects) num-frames -1)
|
||||
z-index (transient {})]
|
||||
(let [frames (helpers/select-frames objects)
|
||||
z-index (calculate-frame-z-index {} uuid/zero objects)]
|
||||
(->> frames
|
||||
(map :id)
|
||||
(reduce #(calculate-frame-z-index %1 %2 objects) z-index))))
|
||||
|
||||
(let [children (get-in objects [current :shapes])
|
||||
assigned? (contains? z-index current)
|
||||
is-frame? (is-frame? current)
|
||||
(defn update-z-index
|
||||
"Updates the z-index given a set of ids to change and the old and new objects
|
||||
representations"
|
||||
[z-index changed-ids old-objects new-objects]
|
||||
|
||||
pending (cond
|
||||
(not is-frame?)
|
||||
(d/concat pending children)
|
||||
(let [old-frames (into #{} (map #(get-in old-objects [% :frame-id])) changed-ids)
|
||||
new-frames (into #{} (map #(get-in new-objects [% :frame-id])) changed-ids)
|
||||
|
||||
(not assigned?)
|
||||
(d/concat pending [current] children)
|
||||
changed-frames (set/union old-frames new-frames)
|
||||
|
||||
:else
|
||||
pending)]
|
||||
frames (->> (helpers/select-frames new-objects)
|
||||
(map :id)
|
||||
(filter #(contains? changed-frames %)))
|
||||
|
||||
(if (empty? pending)
|
||||
(-> (assoc! z-index current current-idx)
|
||||
(persistent!))
|
||||
(recur (peek pending)
|
||||
(pop pending)
|
||||
(dec current-idx)
|
||||
(assoc! z-index current current-idx))))))))
|
||||
z-index (calculate-frame-z-index z-index uuid/zero new-objects)]
|
||||
|
||||
(->> frames
|
||||
(reduce #(calculate-frame-z-index %1 %2 new-objects) z-index))))
|
||||
|
||||
(defn generate-child-parent-index
|
||||
[objects]
|
||||
|
|
|
@ -111,7 +111,7 @@ goog.scope(function() {
|
|||
// Tree implementation functions
|
||||
|
||||
function isRed(branch) {
|
||||
return branch !== null && branch.color === Color.RED;
|
||||
return branch && branch.color === Color.RED;
|
||||
}
|
||||
|
||||
// Insert recursively in the tree
|
||||
|
|
|
@ -20,41 +20,44 @@
|
|||
|
||||
(defonce state (l/atom {}))
|
||||
|
||||
(defn- index-object
|
||||
[objects z-index parents-index masks-index index obj]
|
||||
(let [{:keys [x y width height]} (:selrect obj)
|
||||
shape-bound #js {:x x :y y :width width :height height}
|
||||
(defn index-shape
|
||||
[objects parents-index masks-index]
|
||||
(fn [index shape]
|
||||
(let [{:keys [x y width height]} (:selrect shape)
|
||||
shape-bound #js {:x x :y y :width width :height height}
|
||||
|
||||
parents (get parents-index (:id obj))
|
||||
masks (get masks-index (:id obj))
|
||||
z (get z-index (:id obj))
|
||||
parents (get parents-index (:id shape))
|
||||
masks (get masks-index (:id shape))
|
||||
|
||||
frame (when (and (not= :frame (:type obj))
|
||||
(not= (:frame-id obj) uuid/zero))
|
||||
(get objects (:frame-id obj)))]
|
||||
(qdt/insert index
|
||||
(:id obj)
|
||||
shape-bound
|
||||
(assoc obj :frame frame :masks masks :parents parents :z z))))
|
||||
frame (when (and (not= :frame (:type shape))
|
||||
(not= (:frame-id shape) uuid/zero))
|
||||
(get objects (:frame-id shape)))]
|
||||
(qdt/insert index
|
||||
(:id shape)
|
||||
shape-bound
|
||||
(assoc shape :frame frame :masks masks :parents parents)))))
|
||||
|
||||
(defn- create-index
|
||||
[objects]
|
||||
(let [shapes (-> objects (dissoc uuid/zero) (vals))
|
||||
z-index (cp/calculate-z-index objects)
|
||||
parents-index (cp/generate-child-all-parents-index objects)
|
||||
masks-index (cp/create-mask-index objects parents-index)
|
||||
bounds (gsh/selection-rect shapes)
|
||||
bounds #js {:x (:x bounds)
|
||||
:y (:y bounds)
|
||||
:width (:width bounds)
|
||||
:height (:height bounds)}]
|
||||
:height (:height bounds)}
|
||||
|
||||
(reduce (partial index-object objects z-index parents-index masks-index)
|
||||
(qdt/create bounds)
|
||||
shapes)))
|
||||
index (reduce (index-shape objects parents-index masks-index)
|
||||
(qdt/create bounds)
|
||||
shapes)
|
||||
|
||||
z-index (cp/calculate-z-index objects)]
|
||||
|
||||
{:index index :z-index z-index}))
|
||||
|
||||
(defn- update-index
|
||||
[index old-objects new-objects]
|
||||
[{index :index z-index :z-index} old-objects new-objects]
|
||||
|
||||
(let [changes? (fn [id]
|
||||
(not= (get old-objects id)
|
||||
|
@ -66,18 +69,21 @@
|
|||
(keys new-objects)))
|
||||
|
||||
shapes (->> changed-ids (mapv #(get new-objects %)) (filterv (comp not nil?)))
|
||||
z-index (cp/calculate-z-index new-objects)
|
||||
parents-index (cp/generate-child-all-parents-index new-objects shapes)
|
||||
masks-index (cp/create-mask-index new-objects parents-index)
|
||||
|
||||
new-index (qdt/remove-all index changed-ids)]
|
||||
new-index (qdt/remove-all index changed-ids)
|
||||
|
||||
(reduce (partial index-object new-objects z-index parents-index masks-index)
|
||||
new-index
|
||||
shapes)))
|
||||
index (reduce (index-shape new-objects parents-index masks-index)
|
||||
new-index
|
||||
shapes)
|
||||
|
||||
z-index (cp/update-z-index z-index changed-ids old-objects new-objects)]
|
||||
|
||||
{:index index :z-index z-index}))
|
||||
|
||||
(defn- query-index
|
||||
[index rect frame-id include-frames? include-groups? disabled-masks reverse?]
|
||||
[{index :index z-index :z-index} rect frame-id include-frames? include-groups? disabled-masks reverse?]
|
||||
(let [result (-> (qdt/search index (clj->js rect))
|
||||
(es6-iterator-seq))
|
||||
|
||||
|
@ -102,6 +108,11 @@
|
|||
(some (comp not overlaps?))
|
||||
not))
|
||||
|
||||
add-z-index
|
||||
(fn [{:keys [id frame-id] :as shape}]
|
||||
(assoc shape :z (+ (get z-index id)
|
||||
(get z-index frame-id 0))))
|
||||
|
||||
;; Shapes after filters of overlapping and criteria
|
||||
matching-shapes
|
||||
(into []
|
||||
|
@ -109,7 +120,8 @@
|
|||
(filter match-criteria?)
|
||||
(filter (comp overlaps? :frame))
|
||||
(filter (comp overlaps-masks? :masks))
|
||||
(filter overlaps?))
|
||||
(filter overlaps?)
|
||||
(map add-z-index))
|
||||
result)
|
||||
|
||||
keyfn (if reverse? (comp - :z) :z)]
|
||||
|
|
Loading…
Add table
Reference in a new issue