Improved performance for auto-width/auto-height texts

This commit is contained in:
alonso.torres 2022-12-01 16:13:21 +01:00 committed by Alonso Torres
parent 29b1b4dbc9
commit 32350bcf87
12 changed files with 112 additions and 53 deletions

View file

@ -11,7 +11,7 @@
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.shape.layout :as ctl])) [app.common.types.shape.layout :as ctl]))
(defn- child-layout-bound-points (defn child-layout-bound-points
"Returns the bounds of the children as points" "Returns the bounds of the children as points"
[parent child parent-bounds child-bounds] [parent child parent-bounds child-bounds]

View file

@ -12,7 +12,6 @@
[app.common.geom.shapes.constraints :as gct] [app.common.geom.shapes.constraints :as gct]
[app.common.geom.shapes.flex-layout :as gcl] [app.common.geom.shapes.flex-layout :as gcl]
[app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.pixel-precision :as gpp]
[app.common.geom.shapes.points :as cpo]
[app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.points :as gpo]
[app.common.geom.shapes.transforms :as gtr] [app.common.geom.shapes.transforms :as gtr]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
@ -158,7 +157,7 @@
children-bounds children-bounds
(->> children (->> children
(mapv #(get-group-bounds objects bounds modif-tree %)))] (mapv #(get-group-bounds objects bounds modif-tree %)))]
(cpo/merge-parent-coords-bounds children-bounds current-bounds)) (gpo/merge-parent-coords-bounds children-bounds current-bounds))
(cph/mask-shape? shape) (cph/mask-shape? shape)
(get-group-bounds objects bounds modif-tree (-> children first)) (get-group-bounds objects bounds modif-tree (-> children first))

View file

@ -384,6 +384,17 @@
(-> (empty) (-> (empty)
(scale-content value))) (scale-content value)))
(defn change-size
[{:keys [selrect points transform transform-inverse] :as shape} width height]
(let [old-width (-> selrect :width)
old-height (-> selrect :height)
width (or width old-width)
height (or height old-height)
origin (first points)
scalex (/ width old-width)
scaley (/ height old-height)]
(resize-modifiers (gpt/point scalex scaley) origin transform transform-inverse)))
(defn change-dimensions-modifiers (defn change-dimensions-modifiers
[{:keys [transform transform-inverse] :as shape} attr value] [{:keys [transform transform-inverse] :as shape} attr value]
(us/assert map? shape) (us/assert map? shape)

View file

@ -375,7 +375,10 @@
"Initializes the selrect and points for a shape." "Initializes the selrect and points for a shape."
[shape] [shape]
(let [selrect (gsh/rect->selrect shape) (let [selrect (gsh/rect->selrect shape)
points (gsh/rect->points shape)] points (gsh/rect->points shape)
points (cond-> points
(:transform shape)
(gsh/transform-points (gsh/center-points points) (:transform shape)))]
(-> shape (-> shape
(assoc :selrect selrect (assoc :selrect selrect
:points points)))) :points points))))

View file

@ -14,13 +14,12 @@
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.text :as txt] [app.common.text :as txt]
[app.common.types.modifiers :as ctm] [app.common.types.modifiers :as ctm]
[app.common.types.shape :as cts]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.modifiers :as dwm]
[app.main.data.workspace.selection :as dws] [app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.shapes-update-layout :as dwul]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.util.router :as rt] [app.util.router :as rt]
@ -74,11 +73,14 @@
(when (and (not= content (:content shape)) (when (and (not= content (:content shape))
(some? (:current-page-id state))) (some? (:current-page-id state)))
(rx/of (rx/of
(dch/update-shapes [id] (fn [shape] (dch/update-shapes
(-> shape [id]
(assoc :content content) (fn [shape]
(merge modifiers) (let [{:keys [width height]} modifiers]
(cts/setup-rect-selrect)))) (-> shape
(assoc :content content)
(cond-> (or (some? width) (some? height))
(gsh/transform-shape (ctm/change-size shape width height)))))))
(dwu/commit-undo-transaction (:id shape)))))) (dwu/commit-undo-transaction (:id shape))))))
(when (some? id) (when (some? id)
@ -323,20 +325,25 @@
(let [shape (wsh/lookup-shape state id)] (let [shape (wsh/lookup-shape state id)]
(letfn [(update-fn [shape] (letfn [(update-fn [shape]
(let [{:keys [selrect grow-type]} shape (let [{:keys [selrect grow-type]} shape
{shape-width :width shape-height :height} selrect] {shape-width :width shape-height :height} selrect
(cond-> shape
(and (not-changed? shape-width new-width) (= grow-type :auto-width))
(gsh/transform-shape (ctm/change-dimensions-modifiers shape :width new-width))
(and (not-changed? shape-height new-height) shape
(or (= grow-type :auto-height) (= grow-type :auto-width))) (cond-> shape
(gsh/transform-shape (ctm/change-dimensions-modifiers shape :height new-height)))))] (and (not-changed? shape-width new-width) (= grow-type :auto-width))
(gsh/transform-shape (ctm/change-dimensions-modifiers shape :width new-width)))
shape
(cond-> shape
(and (not-changed? shape-height new-height)
(or (= grow-type :auto-height) (= grow-type :auto-width)))
(gsh/transform-shape (ctm/change-dimensions-modifiers shape :height new-height)))]
shape))]
(when (or (and (not-changed? (:width shape) new-width) (= (:grow-type shape) :auto-width)) (when (or (and (not-changed? (:width shape) new-width) (= (:grow-type shape) :auto-width))
(and (not-changed? (:height shape) new-height) (and (not-changed? (:height shape) new-height)
(or (= (:grow-type shape) :auto-height) (= (:grow-type shape) :auto-width)))) (or (= (:grow-type shape) :auto-height) (= (:grow-type shape) :auto-width))))
(rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false}) (rx/of (dch/update-shapes [id] update-fn {:reg-objects? true :save-undo? false}))))))))
(dwul/update-layout-positions [id]))))))))
(defn save-font (defn save-font
[data] [data]
@ -385,7 +392,9 @@
(not (mth/close? (:width props) (:width shape)))) (not (mth/close? (:width props) (:width shape))))
(and (some? (:height props)) (and (some? (:height props))
(not (mth/close? (:height props) (:height shape))))) (not (mth/close? (:height props) (:height shape)))))
(rx/of (dwul/update-layout-positions [id])))))))
(let [modif-tree (dwm/create-modif-tree [id] (ctm/reflow-modifiers))]
(rx/of (dwm/set-modifiers modif-tree))))))))
(defn clean-text-modifier (defn clean-text-modifier
[id] [id]
@ -401,7 +410,11 @@
(ptk/reify ::remove-text-modifier (ptk/reify ::remove-text-modifier
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(d/dissoc-in state [:workspace-text-modifier id])))) (d/dissoc-in state [:workspace-text-modifier id]))
ptk/WatchEvent
(watch [_ _ _]
(rx/of (dwm/apply-modifiers)))))
(defn commit-position-data (defn commit-position-data
[] []

View file

@ -257,7 +257,9 @@
(mf/defc text-editor-svg (mf/defc text-editor-svg
{::mf/wrap-props false} {::mf/wrap-props false}
[props] [props]
(let [shape (obj/get props "shape") (let [shape (obj/get props "shape")
modifiers (obj/get props "modifiers")
modifiers (get-in modifiers [(:id shape) :modifiers])
clip-id clip-id
(dm/str "text-edition-clip" (:id shape)) (dm/str "text-edition-clip" (:id shape))
@ -270,7 +272,10 @@
shape (cond-> shape shape (cond-> shape
(some? text-modifier) (some? text-modifier)
(dwt/apply-text-modifier text-modifier)) (dwt/apply-text-modifier text-modifier)
(some? modifiers)
(gsh/transform-shape modifiers))
bounding-box (gsht/position-data-selrect shape) bounding-box (gsht/position-data-selrect shape)

View file

@ -12,14 +12,19 @@
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc text-edition-outline (mf/defc text-edition-outline
[{:keys [shape zoom]}] [{:keys [shape zoom modifiers]}]
(let [text-modifier-ref (let [modifiers (get-in modifiers [(:id shape) :modifiers])
text-modifier-ref
(mf/use-memo (mf/deps (:id shape)) #(refs/workspace-text-modifier-by-id (:id shape))) (mf/use-memo (mf/deps (:id shape)) #(refs/workspace-text-modifier-by-id (:id shape)))
text-modifier text-modifier
(mf/deref text-modifier-ref) (mf/deref text-modifier-ref)
shape (cond-> shape shape (cond-> shape
(some? modifiers)
(gsh/transform-shape modifiers)
(some? text-modifier) (some? text-modifier)
(dwt/apply-text-modifier text-modifier)) (dwt/apply-text-modifier text-modifier))

View file

@ -36,13 +36,11 @@
(dissoc :position-data))) (dissoc :position-data)))
(defn fix-position [shape modifier] (defn fix-position [shape modifier]
(let [shape' (-> shape (let [shape' (gsh/transform-shape shape modifier)
(assoc :grow-type :fixed) ;; We need to remove the movement because the dynamic modifiers will have move it
(gsh/transform-shape modifier))
deltav (gpt/to-vec (gpt/point (:selrect shape')) deltav (gpt/to-vec (gpt/point (:selrect shape'))
(gpt/point (:selrect shape)))] (gpt/point (:selrect shape)))]
(gsh/transform-shape shape' (ctm/move-modifiers deltav)))) (gsh/transform-shape shape (ctm/move modifier deltav))))
(defn process-shape [modifiers {:keys [id] :as shape}] (defn process-shape [modifiers {:keys [id] :as shape}]
(let [modifier (dm/get-in modifiers [id :modifiers])] (let [modifier (dm/get-in modifiers [id :modifiers])]

View file

@ -204,9 +204,9 @@
[:div.viewport-overlays [:div.viewport-overlays
;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap ;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap
;; inside a foreign object "dummy" so this awkward behaviour is take into account ;; inside a foreign object "dummy" so this awkward behaviour is take into account
[:svg {:style {:top 0 :left 0 :position "fixed" :width "100%" :height "100%" :opacity 0}} [:svg {:style {:top 0 :left 0 :position "fixed" :width "100%" :height "100%" :opacity (when-not (debug? :html-text) 0)}}
[:foreignObject {:x 0 :y 0 :width "100%" :height "100%"} [:foreignObject {:x 0 :y 0 :width "100%" :height "100%"}
[:div {:style {:pointer-events "none"}} [:div {:style {:pointer-events (when-not (debug? :html-text) "none")}}
[:& stvh/viewport-texts [:& stvh/viewport-texts
{:key (dm/str "texts-" page-id) {:key (dm/str "texts-" page-id)
:page-id page-id :page-id page-id
@ -289,7 +289,8 @@
[:g {:style {:pointer-events (if disable-events? "none" "auto")}} [:g {:style {:pointer-events (if disable-events? "none" "auto")}}
(when show-text-editor? (when show-text-editor?
[:& editor/text-editor-svg {:shape editing-shape}]) [:& editor/text-editor-svg {:shape editing-shape
:modifiers modifiers}])
(when show-frame-outline? (when show-frame-outline?
[:& outline/shape-outlines [:& outline/shape-outlines
@ -298,7 +299,8 @@
(filter #(cph/frame-shape? (get base-objects %))) (filter #(cph/frame-shape? (get base-objects %)))
(remove selected) (remove selected)
(first))} (first))}
:zoom zoom}]) :zoom zoom
:modifiers modifiers}])
(when show-outlines? (when show-outlines?
[:& outline/shape-outlines [:& outline/shape-outlines
@ -307,7 +309,8 @@
:hover #{(:id @hover) @frame-hover} :hover #{(:id @hover) @frame-hover}
:highlighted highlighted :highlighted highlighted
:edition edition :edition edition
:zoom zoom}]) :zoom zoom
:modifiers modifiers}])
(when show-selection-handlers? (when show-selection-handlers?
[:& selection/selection-area [:& selection/selection-area
@ -321,7 +324,8 @@
(when show-text-editor? (when show-text-editor?
[:& text-edition-outline [:& text-edition-outline
{:shape (get base-objects edition) {:shape (get base-objects edition)
:zoom zoom}]) :zoom zoom
:modifiers modifiers}])
(when show-measures? (when show-measures?
[:& msr/measurement [:& msr/measurement

View file

@ -130,12 +130,15 @@
rect (gsh/center->rect point (/ 5 zoom) (/ 5 zoom))] rect (gsh/center->rect point (/ 5 zoom) (/ 5 zoom))]
(if (mf/ref-val hover-disabled-ref) (if (mf/ref-val hover-disabled-ref)
(rx/of nil) (rx/of nil)
(uw/ask-buffered! (->> (uw/ask-buffered!
{:cmd :selection/query {:cmd :selection/query
:page-id page-id :page-id page-id
:rect rect :rect rect
:include-frames? true :include-frames? true
:clip-children? (not mod?)}))))) :clip-children? (not mod?)})
;; When the ask-buffered is canceled returns null. We filter them
;; to improve the behavior
(rx/filter some?))))))
over-shapes-stream over-shapes-stream
(mf/use-memo (mf/use-memo

View file

@ -9,6 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.main.ui.hooks :as hooks]
[app.util.object :as obj] [app.util.object :as obj]
[app.util.path.format :as upf] [app.util.path.format :as upf]
[clojure.set :as set] [clojure.set :as set]
@ -18,10 +19,12 @@
(mf/defc outline (mf/defc outline
{::mf/wrap-props false} {::mf/wrap-props false}
[props] [props]
(let [shape (obj/get props "shape") (let [shape (obj/get props "shape")
zoom (obj/get props "zoom" 1) zoom (obj/get props "zoom" 1)
color (obj/get props "color")
modifier (obj/get props "modifier")
color (unchecked-get props "color") shape (gsh/transform-shape shape (:modifiers modifier))
transform (gsh/transform-str shape) transform (gsh/transform-str shape)
path? (= :path (:type shape)) path? (= :path (:type shape))
path-data path-data
@ -64,17 +67,22 @@
(mf/defc shape-outlines-render (mf/defc shape-outlines-render
{::mf/wrap-props false {::mf/wrap-props false
::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "zoom"]))]} ::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "zoom" "modifiers"]))]}
[props] [props]
(let [shapes (obj/get props "shapes") (let [shapes (obj/get props "shapes")
zoom (obj/get props "zoom") zoom (obj/get props "zoom")
modifiers (obj/get props "modifiers")
color (if (or (> (count shapes) 1) (nil? (:shape-ref (first shapes)))) color (if (or (> (count shapes) 1) (nil? (:shape-ref (first shapes))))
"var(--color-primary)" "var(--color-component-highlight)")] "var(--color-primary)" "var(--color-component-highlight)")]
(for [shape shapes] (for [shape shapes]
[:& outline {:key (str "outline-" (:id shape)) (let [modifier (get modifiers (:id shape))]
:shape shape [:& outline {:key (str "outline-" (:id shape))
:zoom zoom :shape shape
:color color}]))) :modifier modifier
:zoom zoom
:color color}]))))
(defn- show-outline? (defn- show-outline?
[shape] [shape]
@ -91,6 +99,7 @@
objects (obj/get props "objects") objects (obj/get props "objects")
edition (obj/get props "edition") edition (obj/get props "edition")
zoom (obj/get props "zoom") zoom (obj/get props "zoom")
modifiers (obj/get props "modifiers")
lookup (d/getf objects) lookup (d/getf objects)
edition? (fn [o] (= edition o)) edition? (fn [o] (= edition o))
@ -102,7 +111,13 @@
(set/union selected hover)) (set/union selected hover))
(into (comp (remove edition?) (into (comp (remove edition?)
(keep lookup)) (keep lookup))
highlighted))] highlighted))
modifiers (select-keys modifiers (map :id shapes))
modifiers (hooks/use-equal-memo modifiers)
shapes (hooks/use-equal-memo shapes)]
[:g.outlines [:g.outlines
[:& shape-outlines-render {:shapes shapes :zoom zoom}]])) [:& shape-outlines-render {:shapes shapes
:zoom zoom
:modifiers modifiers}]]))

View file

@ -83,6 +83,9 @@
;; Show the bounds relative to the parent ;; Show the bounds relative to the parent
:parent-bounds :parent-bounds
;; Show html text
:html-text
}) })
;; These events are excluded when we activate the :events flag ;; These events are excluded when we activate the :events flag