🐛 Fix problem with alignment performance

This commit is contained in:
alonso.torres 2023-10-06 16:25:44 +02:00 committed by Andrés Moya
parent 859146ddc2
commit fe3740e329
7 changed files with 82 additions and 63 deletions

View file

@ -1,5 +1,11 @@
# CHANGELOG # CHANGELOG
## 1.19.5
### :bug: New features
- Fix problem with alignment performance
## 1.19.4 ## 1.19.4
### :sparkles: New features ### :sparkles: New features

View file

@ -6,8 +6,7 @@
(ns app.common.geom.align (ns app.common.geom.align
(:require (:require
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]))
[app.common.pages.helpers :refer [get-children]]))
;; --- Alignment ;; --- Alignment
@ -16,25 +15,18 @@
(declare calc-align-pos) (declare calc-align-pos)
(defn- recursive-move
"Move the shape and all its recursive children."
[shape dpoint objects]
(->> (get-children objects (:id shape))
(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
in the given axis. Take account the form of the shape and the in the given axis. Take account the form of the shape and the
possible rotation. What is aligned is the rectangle that wraps possible rotation. What is aligned is the rectangle that wraps
the shape with the given rectangle. If the shape is a group, the shape with the given rectangle. If the shape is a group,
move also all of its recursive children." move also all of its recursive children."
[shape rect axis objects] [shape rect axis]
(let [wrapper-rect (gsh/selection-rect [shape]) (let [wrapper-rect (gsh/selection-rect [shape])
align-pos (calc-align-pos wrapper-rect rect axis) align-pos (calc-align-pos wrapper-rect rect axis)
delta {:x (- (:x align-pos) (:x wrapper-rect)) delta {:x (- (:x align-pos) (:x wrapper-rect))
:y (- (:y align-pos) (:y wrapper-rect))}] :y (- (:y align-pos) (:y wrapper-rect))}]
(recursive-move shape delta objects))) (gsh/move shape delta)))
(defn calc-align-pos (defn calc-align-pos
[wrapper-rect rect axis] [wrapper-rect rect axis]
@ -73,22 +65,22 @@
It takes into account the form of the shape and the rotation, It takes into account the form of the shape and the rotation,
what is distributed is the wrapping rectangles of the shapes. what is distributed is the wrapping rectangles of the shapes.
If any shape is a group, move also all of its recursive children." If any shape is a group, move also all of its recursive children."
[shapes axis objects] [shapes axis]
(let [coord (if (= axis :horizontal) :x :y) (let [coord (if (= axis :horizontal) :x :y)
other-coord (if (= axis :horizontal) :y :x) other-coord (if (= axis :horizontal) :y :x)
size (if (= axis :horizontal) :width :height) size (if (= axis :horizontal) :width :height)
; The rectangle that wraps the whole selection ;; The rectangle that wraps the whole selection
wrapper-rect (gsh/selection-rect shapes) wrapper-rect (gsh/selection-rect shapes)
; Sort shapes by the center point in the given axis ;; Sort shapes by the center point in the given axis
sorted-shapes (sort-by #(coord (gsh/center-shape %)) shapes) sorted-shapes (sort-by #(coord (gsh/center-shape %)) shapes)
; Each shape wrapped in its own rectangle ;; Each shape wrapped in its own rectangle
wrapped-shapes (map #(gsh/selection-rect [%]) sorted-shapes) wrapped-shapes (map #(gsh/selection-rect [%]) sorted-shapes)
; The total space between shapes ;; The total space between shapes
space (reduce - (size wrapper-rect) (map size wrapped-shapes)) space (reduce - (size wrapper-rect) (map size wrapped-shapes))
unit-space (/ space (- (count wrapped-shapes) 1)) unit-space (/ space (- (count wrapped-shapes) 1))
; Calculate the distance we need to move each shape. ;; Calculate the distance we need to move each shape.
; The new position of each one is the position of the ;; The new position of each one is the position of the
; previous one plus its size plus the unit space. ;; previous one plus its size plus the unit space.
deltas (loop [shapes' wrapped-shapes deltas (loop [shapes' wrapped-shapes
start-pos (coord wrapper-rect) start-pos (coord wrapper-rect)
deltas []] deltas []]
@ -100,11 +92,11 @@
(if (= (count shapes') 1) (if (= (count shapes') 1)
(conj deltas delta) (conj deltas delta)
(recur (rest shapes') (recur (rest shapes')
new-pos new-pos
(conj deltas delta)))))] (conj deltas delta)))))]
(mapcat #(recursive-move %1 {coord %2 other-coord 0} objects) (map #(gsh/move %1 {coord %2 other-coord 0})
sorted-shapes deltas))) sorted-shapes deltas)))
;; Adjust to viewport ;; Adjust to viewport

View file

@ -137,6 +137,7 @@
(dm/export gco/center-points) (dm/export gco/center-points)
(dm/export gco/transform-points) (dm/export gco/transform-points)
(dm/export gco/shape->points) (dm/export gco/shape->points)
(dm/export gco/shapes->rect)
(dm/export gpr/make-rect) (dm/export gpr/make-rect)
(dm/export gpr/make-selrect) (dm/export gpr/make-selrect)

View file

@ -12,6 +12,16 @@
[app.common.geom.shapes.rect :as gpr] [app.common.geom.shapes.rect :as gpr]
[app.common.math :as mth])) [app.common.math :as mth]))
(defn shapes->rect
"Returns a rect that contains all the shapes and is aware of the
rotation of each shape. Mainly used for multiple selection."
[shapes]
(->> shapes
(keep (fn [shape]
(-> (:points shape)
(gpr/points->rect))))
(gpr/join-rects)))
(defn center-rect (defn center-rect
[{:keys [x y width height]}] [{:keys [x y width height]}]
(when (d/num? x y width height) (when (d/num? x y width height)

View file

@ -1021,9 +1021,6 @@
;; --- Shape / Selection Alignment and Distribution ;; --- Shape / Selection Alignment and Distribution
(declare align-object-to-parent)
(declare align-objects-list)
(defn can-align? [selected objects] (defn can-align? [selected objects]
(cond (cond
(empty? selected) false (empty? selected) false
@ -1031,11 +1028,18 @@
:else :else
(not= uuid/zero (:parent-id (get objects (first selected)))))) (not= uuid/zero (:parent-id (get objects (first selected))))))
(defn- move-shape (defn align-object-to-parent
[shape] [objects object-id axis]
(let [bbox (-> shape :points gsh/points->selrect) (let [object (get objects object-id)
pos (gpt/point (:x bbox) (:y bbox))] parent-id (:parent-id (get objects object-id))
(dwt/update-position (:id shape) pos))) parent (get objects parent-id)]
[(gal/align-to-rect object parent axis)]))
(defn align-objects-list
[objects selected axis]
(let [selected-objs (map #(get objects %) selected)
rect (gsh/shapes->rect selected-objs)]
(map #(gal/align-to-rect % rect axis) selected-objs)))
(defn align-objects (defn align-objects
[axis] [axis]
@ -1052,28 +1056,12 @@
moved (if (= 1 (count selected)) moved (if (= 1 (count selected))
(align-object-to-parent objects (first selected) axis) (align-object-to-parent objects (first selected) axis)
(align-objects-list objects selected axis)) (align-objects-list objects selected axis))
ids (map :id moved)
undo-id (js/Symbol)] undo-id (js/Symbol)]
(when (can-align? selected objects) (when (can-align? selected objects)
(rx/concat (rx/of (dwu/start-undo-transaction undo-id)
(rx/of (dwu/start-undo-transaction undo-id)) (dwt/position-shapes moved)
(->> (rx/from moved) (ptk/data-event :layout/update selected)
(rx/map move-shape)) (dwu/commit-undo-transaction undo-id)))))))
(rx/of (ptk/data-event :layout/update ids)
(dwu/commit-undo-transaction undo-id))))))))
(defn align-object-to-parent
[objects object-id axis]
(let [object (get objects object-id)
parent (:parent-id (get objects object-id))
parent-obj (get objects parent)]
(gal/align-to-rect object parent-obj axis objects)))
(defn align-objects-list
[objects selected axis]
(let [selected-objs (map #(get objects %) selected)
rect (gsh/selection-rect selected-objs)]
(mapcat #(gal/align-to-rect % rect axis objects) selected-objs)))
(defn can-distribute? [selected] (defn can-distribute? [selected]
(cond (cond
@ -1094,14 +1082,13 @@
objects (wsh/lookup-page-objects state page-id) objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state) selected (wsh/lookup-selected state)
moved (-> (map #(get objects %) selected) moved (-> (map #(get objects %) selected)
(gal/distribute-space axis objects)) (gal/distribute-space axis))
undo-id (js/Symbol)]
moved (d/index-by :id moved)
ids (keys moved)
update-fn #(get moved (:id %))]
(when (can-distribute? selected) (when (can-distribute? selected)
(rx/of (dch/update-shapes ids update-fn {:reg-objects? true}))))))) (rx/of (dwu/start-undo-transaction undo-id)
(dwt/position-shapes moved)
(ptk/data-event :layout/update selected)
(dwu/commit-undo-transaction undo-id)))))))
;; --- Shape Proportions ;; --- Shape Proportions

View file

@ -402,14 +402,15 @@
([] ([]
(apply-modifiers nil)) (apply-modifiers nil))
([{:keys [modifiers undo-transation? stack-undo?] :or {undo-transation? true stack-undo? false}}] ([{:keys [modifiers undo-transation? stack-undo? ignore-constraints ignore-snap-pixel]
:or {undo-transation? true stack-undo? false ignore-constraints false ignore-snap-pixel false}}]
(ptk/reify ::apply-modifiers (ptk/reify ::apply-modifiers
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [text-modifiers (get state :workspace-text-modifier) (let [text-modifiers (get state :workspace-text-modifier)
objects (wsh/lookup-page-objects state) objects (wsh/lookup-page-objects state)
object-modifiers (if modifiers object-modifiers (if modifiers
(calculate-modifiers state modifiers) (calculate-modifiers state ignore-constraints ignore-snap-pixel modifiers)
(get state :workspace-modifiers)) (get state :workspace-modifiers))
ids (or (keys object-modifiers) []) ids (or (keys object-modifiers) [])

View file

@ -687,7 +687,6 @@
(defn update-position (defn update-position
"Move shapes to a new position" "Move shapes to a new position"
[id position] [id position]
(js/console.log "DEBUG" (pr-str position))
(dm/assert! (uuid? id)) (dm/assert! (uuid? id))
(ptk/reify ::update-position (ptk/reify ::update-position
@ -707,8 +706,31 @@
modif-tree (dwm/create-modif-tree [id] (ctm/move-modifiers delta))] modif-tree (dwm/create-modif-tree [id] (ctm/move-modifiers delta))]
(rx/of (dwm/set-modifiers modif-tree false true) (rx/of (dwm/apply-modifiers {:modifiers modif-tree
(dwm/apply-modifiers)))))) :ignore-constraints false
:ignore-snap-pixel true}))))))
(defn position-shapes
[shapes]
(ptk/reify ::position-shapes
ptk/WatchEvent
(watch [_ state _]
(let [objects (wsh/lookup-page-objects state)
shapes (d/index-by :id shapes)
modif-tree
(dwm/build-modif-tree
(keys shapes)
objects
(fn [cshape]
(let [oshape (get shapes (:id cshape))
cpos (-> cshape :points first gpt/point)
opos (-> oshape :points first gpt/point)]
(ctm/move-modifiers (gpt/subtract opos cpos)))))]
(rx/of (dwm/apply-modifiers {:modifiers modif-tree
:ignore-constraints false
:ignore-snap-pixel true}))))))
(defn- move-shapes-to-frame (defn- move-shapes-to-frame
[ids frame-id drop-index] [ids frame-id drop-index]