From 69bb4654c9f6b72e833039098333184d0eed9883 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 23 Nov 2022 13:03:37 +0100 Subject: [PATCH] :sparkles: Improve transforms performance --- common/src/app/common/attrs.cljc | 4 +- common/src/app/common/geom/matrix.cljc | 45 ++++--- common/src/app/common/geom/point.cljc | 4 + common/src/app/common/geom/shapes.cljc | 12 +- .../app/common/geom/shapes/constraints.cljc | 93 +++++++------- .../geom/shapes/flex_layout/drop_area.cljc | 37 +++--- .../common/geom/shapes/flex_layout/lines.cljc | 26 ++-- .../geom/shapes/flex_layout/modifiers.cljc | 42 ++++--- .../geom/shapes/flex_layout/positions.cljc | 21 ++-- .../src/app/common/geom/shapes/modifiers.cljc | 117 ++++++++++-------- .../common/geom/shapes/pixel_precision.cljc | 32 ++--- common/src/app/common/geom/shapes/points.cljc | 54 +++++++- .../app/common/geom/shapes/transforms.cljc | 26 ++-- common/src/app/common/types/modifiers.cljc | 45 ++++--- frontend/src/app/main/data/workspace.cljs | 13 +- .../src/app/main/data/workspace/shapes.cljs | 4 +- .../shapes/text/viewport_texts_html.cljs | 9 +- .../src/app/main/ui/workspace/viewport.cljs | 6 + .../app/main/ui/workspace/viewport/debug.cljs | 56 ++++++++- frontend/src/debug.cljs | 3 + 20 files changed, 402 insertions(+), 247 deletions(-) diff --git a/common/src/app/common/attrs.cljc b/common/src/app/common/attrs.cljc index 7409172fe..7bc8d5001 100644 --- a/common/src/app/common/attrs.cljc +++ b/common/src/app/common/attrs.cljc @@ -6,7 +6,7 @@ (ns app.common.attrs (:require - [app.common.geom.shapes.transforms :as gst] + [app.common.geom.shapes.transforms :as gtr] [app.common.math :as mth])) (defn- get-attr @@ -24,7 +24,7 @@ value (if-let [points (:points obj)] (if (not= points :multiple) - (let [rect (gst/selection-rect [obj])] + (let [rect (gtr/selection-rect [obj])] (if (= attr :ox) (:x rect) (:y rect))) :multiple) (get obj attr ::unset))) diff --git a/common/src/app/common/geom/matrix.cljc b/common/src/app/common/geom/matrix.cljc index b8145090f..ac7443f2d 100644 --- a/common/src/app/common/geom/matrix.cljc +++ b/common/src/app/common/geom/matrix.cljc @@ -91,27 +91,34 @@ (defn multiply ([^Matrix m1 ^Matrix m2] - (let [m1a (.-a m1) - m1b (.-b m1) - m1c (.-c m1) - m1d (.-d m1) - m1e (.-e m1) - m1f (.-f m1) + (cond + ;; nil matrixes are equivalent to unit-matrix + (and (nil? m1) (nil? m2)) (matrix) + (nil? m1) m2 + (nil? m2) m1 - m2a (.-a m2) - m2b (.-b m2) - m2c (.-c m2) - m2d (.-d m2) - m2e (.-e m2) - m2f (.-f m2)] + :else + (let [m1a (.-a m1) + m1b (.-b m1) + m1c (.-c m1) + m1d (.-d m1) + m1e (.-e m1) + m1f (.-f m1) - (Matrix. - (+ (* m1a m2a) (* m1c m2b)) - (+ (* m1b m2a) (* m1d m2b)) - (+ (* m1a m2c) (* m1c m2d)) - (+ (* m1b m2c) (* m1d m2d)) - (+ (* m1a m2e) (* m1c m2f) m1e) - (+ (* m1b m2e) (* m1d m2f) m1f)))) + m2a (.-a m2) + m2b (.-b m2) + m2c (.-c m2) + m2d (.-d m2) + m2e (.-e m2) + m2f (.-f m2)] + + (Matrix. + (+ (* m1a m2a) (* m1c m2b)) + (+ (* m1b m2a) (* m1d m2b)) + (+ (* m1a m2c) (* m1c m2d)) + (+ (* m1b m2c) (* m1d m2d)) + (+ (* m1a m2e) (* m1c m2f) m1e) + (+ (* m1b m2e) (* m1d m2f) m1f))))) ([m1 m2 & others] (reduce multiply (multiply m1 m2) others))) diff --git a/common/src/app/common/geom/point.cljc b/common/src/app/common/geom/point.cljc index 5b17160d9..36b0c9fad 100644 --- a/common/src/app/common/geom/point.cljc +++ b/common/src/app/common/geom/point.cljc @@ -189,6 +189,10 @@ (defn angle-sign [v1 v2] (if (> (* (:y v1) (:x v2)) (* (:x v1) (:y v2))) -1 1)) +(defn signed-angle-with-other + [v1 v2] + (* (angle-sign v1 v2) (angle-with-other v1 v2))) + (defn update-angle "Update the angle of the point." [p angle] diff --git a/common/src/app/common/geom/shapes.cljc b/common/src/app/common/geom/shapes.cljc index 54c07a570..b4aa9ef50 100644 --- a/common/src/app/common/geom/shapes.cljc +++ b/common/src/app/common/geom/shapes.cljc @@ -13,7 +13,7 @@ [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.constraints :as gct] [app.common.geom.shapes.corners :as gsc] - [app.common.geom.shapes.intersect :as gin] + [app.common.geom.shapes.intersect :as gsi] [app.common.geom.shapes.modifiers :as gsm] [app.common.geom.shapes.path :as gsp] [app.common.geom.shapes.rect :as gpr] @@ -178,8 +178,6 @@ (dm/export gtr/transform-bounds) (dm/export gtr/move-position-data) (dm/export gtr/apply-objects-modifiers) -(dm/export gtr/parent-coords-rect) -(dm/export gtr/parent-coords-points) ;; Constratins (dm/export gct/calc-child-modifiers) @@ -190,10 +188,10 @@ (dm/export gsp/open-path?) ;; Intersection -(dm/export gin/overlaps?) -(dm/export gin/has-point?) -(dm/export gin/has-point-rect?) -(dm/export gin/rect-contains-shape?) +(dm/export gsi/overlaps?) +(dm/export gsi/has-point?) +(dm/export gsi/has-point-rect?) +(dm/export gsi/rect-contains-shape?) ;; Bool diff --git a/common/src/app/common/geom/shapes/constraints.cljc b/common/src/app/common/geom/shapes/constraints.cljc index 2ced1cce1..b5e060214 100644 --- a/common/src/app/common/geom/shapes/constraints.cljc +++ b/common/src/app/common/geom/shapes/constraints.cljc @@ -6,12 +6,11 @@ (ns app.common.geom.shapes.constraints (:require + [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] - [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.intersect :as gsi] [app.common.geom.shapes.points :as gpo] - [app.common.geom.shapes.rect :as gre] - [app.common.geom.shapes.transforms :as gst] + [app.common.geom.shapes.transforms :as gtr] [app.common.math :as mth] [app.common.types.modifiers :as ctm] [app.common.uuid :as uuid])) @@ -184,7 +183,7 @@ (ctm/move-modifiers (displacement end-before end-after)))) (defmethod constraint-modifier :fixed - [_ axis child-points-before parent-points-before child-points-after parent-points-after transformed-parent] + [_ axis child-points-before parent-points-before child-points-after parent-points-after {:keys [transform transform-inverse]} modifiers] (let [;; Same as constraint end end-before (end-vector axis child-points-before parent-points-before) end-after (end-vector axis child-points-after parent-points-after) @@ -203,11 +202,16 @@ ;; displacement (so its left+top position is constant) scale (/ (gpt/length after-vec) (gpt/length before-vec)) - resize-origin (first child-points-after) - {:keys [transform transform-inverse]} transformed-parent] + resize-origin (gpo/origin child-points-after) + modif-transform (ctm/modifiers->transform modifiers) + modif-transform-inverse (gmt/inverse modif-transform) + resize-transform (gmt/multiply modif-transform transform) + resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse) + + resize-vector (get-scale axis scale)] (-> (ctm/empty) - (ctm/resize (get-scale axis scale) resize-origin transform transform-inverse) + (ctm/resize resize-vector resize-origin resize-transform resize-transform-inverse) (ctm/move disp-start)))) (defmethod constraint-modifier :center @@ -245,37 +249,36 @@ :top :scale))) -(defn bounding-box-parent-transform - "Returns a bounding box for the child in the same coordinate system - as the parent. - Returns a points array" - [child parent] - (-> child - :points - (gco/transform-points (:transform-inverse parent)) - (gre/points->rect) - (gre/rect->points) ;; Restore to points so we can transform them - (gco/transform-points (:transform parent)))) - (defn normalize-modifiers "Before aplying constraints we need to remove the deformation caused by the resizing of the parent" - [constraints-h constraints-v modifiers child parent transformed-child {:keys [transform transform-inverse] :as transformed-parent}] + [constraints-h constraints-v modifiers child {:keys [transform transform-inverse] :as parent} transformed-child-bounds transformed-parent-bounds] - (let [child-bb-before (gst/parent-coords-rect child parent) - child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) - scale-x (/ (:width child-bb-before) (:width child-bb-after)) - scale-y (/ (:height child-bb-before) (:height child-bb-after)) - resize-origin (-> transformed-parent :points gpo/origin)] + (let [child-bb-before (gpo/parent-coords-bounds (:points child) (:points parent)) + child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds) - (cond-> modifiers - (not= :scale constraints-h) - (ctm/resize (gpt/point scale-x 1) resize-origin transform transform-inverse) + scale-x (if (= :scale constraints-h) + 1 + (/ (gpo/width-points child-bb-before) (gpo/width-points child-bb-after))) - (not= :scale constraints-v) - (ctm/resize (gpt/point 1 scale-y) resize-origin transform transform-inverse)))) + scale-y (if (= :scale constraints-v) + 1 + (/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after))) + + resize-vector (gpt/point scale-x scale-y) + modif-transform (ctm/modifiers->transform modifiers) + modif-transform-inverse (gmt/inverse modif-transform) + resize-transform (gmt/multiply modif-transform transform) + resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse) + resize-origin (gpo/origin transformed-child-bounds)] + (-> modifiers + (ctm/resize + resize-vector + resize-origin + resize-transform + resize-transform-inverse)))) (defn calc-child-modifiers - [parent child modifiers ignore-constraints transformed-parent] + [parent child modifiers ignore-constraints parent-bounds transformed-parent-bounds] (let [modifiers (ctm/select-child-modifiers modifiers) @@ -292,26 +295,24 @@ (if (and (= :scale constraints-h) (= :scale constraints-v)) modifiers - (let [transformed-child (gst/transform-shape child (ctm/select-child-modifiers modifiers)) - modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child transformed-parent) + (let [child-bounds (:points child) + modifiers (ctm/select-child-modifiers modifiers) + transformed-child-bounds (gtr/transform-bounds child-bounds modifiers) + modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child-bounds transformed-parent-bounds) + transformed-child-bounds (gtr/transform-bounds child-bounds modifiers) - transformed-child (gst/transform-shape child modifiers) - - parent-points-before (bounding-box-parent-transform parent parent) - child-points-before (bounding-box-parent-transform child parent) - parent-points-after (bounding-box-parent-transform transformed-parent transformed-parent) - child-points-after (bounding-box-parent-transform transformed-child transformed-parent) + child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds) + child-points-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds) modifiers-h (constraint-modifier (constraints-h const->type+axis) :x - child-points-before parent-points-before - child-points-after parent-points-after - transformed-parent) + child-points-before parent-bounds + child-points-after transformed-parent-bounds + parent modifiers) modifiers-v (constraint-modifier (constraints-v const->type+axis) :y - child-points-before parent-points-before - child-points-after parent-points-after - transformed-parent)] - + child-points-before parent-bounds + child-points-after transformed-parent-bounds + parent modifiers)] (-> modifiers (ctm/add-modifiers modifiers-h) (ctm/add-modifiers modifiers-v)))))) diff --git a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc index b68057a17..8a5c7a562 100644 --- a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc @@ -10,25 +10,24 @@ [app.common.geom.matrix :as gmt] [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.flex-layout.lines :as fli] + [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.rect :as gsr] [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl])) (defn drop-child-areas - [{:keys [transform-inverse] :as frame} parent-rect child index reverse? prev-x prev-y last?] + [frame parent-rect child-bounds index reverse? prev-x prev-y last?] (let [col? (ctl/col? frame) row? (ctl/row? frame) [layout-gap-row layout-gap-col] (ctl/gaps frame) - start-p (-> child :points first) - center (gco/center-shape frame) - start-p (gmt/transform-point-center start-p center transform-inverse) + start-p (gpo/origin child-bounds) box-x (:x start-p) box-y (:y start-p) - box-width (-> child :selrect :width) - box-height (-> child :selrect :height) + box-width (gpo/width-points child-bounds) + box-height (gpo/height-points child-bounds) x (if col? (:x parent-rect) prev-x) y (if row? (:y parent-rect) prev-y) @@ -148,47 +147,45 @@ from-idx 0 prev-line-x (:x frame) prev-line-y (:y frame) + lines (seq lines)] - current-line (first lines) - lines (rest lines)] - - (if (nil? current-line) + (if (empty? lines) areas - (let [line-area (drop-line-area frame current-line prev-line-x prev-line-y (nil? (first lines))) + (let [current-line (first lines) + line-area (drop-line-area frame current-line prev-line-x prev-line-y (empty? (rest lines))) children (subvec children from-idx (+ from-idx (:num-children current-line))) next-areas (loop [areas areas prev-child-x (:x line-area) prev-child-y (:y line-area) - [index child] (first children) - children (rest children)] + children (seq children)] - (if (nil? child) + (if (empty? children) areas - (let [[child-area child-area-start child-area-end] - (drop-child-areas frame line-area child index (not reverse?) prev-child-x prev-child-y (nil? (first children)))] + (let [[index [child-bounds _]] (first children) + [child-area child-area-start child-area-end] + (drop-child-areas frame line-area child-bounds index (not reverse?) prev-child-x prev-child-y (empty? (rest children)))] (recur (conj areas child-area-start child-area-end) (+ (:x child-area) (:width child-area)) (+ (:y child-area) (:height child-area)) - (first children) (rest children)))))] (recur next-areas (+ from-idx (:num-children current-line)) (+ (:x line-area) (:width line-area)) (+ (:y line-area) (:height line-area)) - (first lines) (rest lines))))))) (defn get-drop-index [frame-id objects position] (let [frame (get objects frame-id) position (gmt/transform-point-center position (gco/center-shape frame) (:transform-inverse frame)) - children (cph/get-immediate-children objects frame-id) - layout-data (fli/calc-layout-data frame children) + children (->> (cph/get-immediate-children objects frame-id) + (map #(vector (gpo/parent-coords-bounds (:points %) (:points frame)) %))) + layout-data (fli/calc-layout-data frame children (:points frame)) drop-areas (layout-drop-areas frame layout-data children) area (d/seek #(gsr/contains-point? % position) drop-areas)] (:index area))) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/lines.cljc index 41dea20ea..664b91737 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/lines.cljc @@ -9,21 +9,20 @@ [app.common.data :as d] [app.common.geom.shapes.flex-layout.positions :as flp] [app.common.geom.shapes.points :as gpo] - [app.common.geom.shapes.transforms :as gst] [app.common.math :as mth] [app.common.types.shape.layout :as ctl])) (def conjv (fnil conj [])) (defn layout-bounds - [{:keys [layout-padding layout-padding-type] :as shape}] + [{:keys [layout-padding layout-padding-type] :as shape} shape-bounds] (let [;; Add padding to the bounds {pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding [pad-top pad-right pad-bottom pad-left] (if (= layout-padding-type :multiple) [pad-top pad-right pad-bottom pad-left] [pad-top pad-top pad-top pad-top])] - (gpo/pad-points (:points shape) pad-top pad-right pad-bottom pad-left))) + (gpo/pad-points shape-bounds pad-top pad-right pad-bottom pad-left))) (defn init-layout-lines "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" @@ -43,18 +42,17 @@ (loop [line-data nil result [] - child (first children) - children (rest children)] + children (seq children)] - (if (nil? child) + (if (empty? children) (cond-> result (some? line-data) (conj line-data)) - (let [{:keys [line-min-width line-min-height + (let [[child-bounds child] (first children) + {:keys [line-min-width line-min-height line-max-width line-max-height num-children children-data]} line-data - child-bounds (gst/parent-coords-points child shape) child-width (gpo/width-points child-bounds) child-height (gpo/height-points child-bounds) child-min-width (ctl/child-min-width child) @@ -98,7 +96,6 @@ :num-children (inc num-children) :children-data (conjv children-data child-data)} result - (first children) (rest children)) (recur {:line-min-width next-min-width @@ -108,7 +105,6 @@ :num-children 1 :children-data [child-data]} (cond-> result (some? line-data) (conj line-data)) - (first children) (rest children)))))))) (defn add-space-to-items @@ -300,9 +296,9 @@ (defn calc-layout-data "Digest the layout data to pass it to the constrains" - [shape children] + [shape children shape-bounds] - (let [layout-bounds (layout-bounds shape) + (let [layout-bounds (layout-bounds shape shape-bounds) reverse? (ctl/reverse? shape) children (cond->> children (not reverse?) reverse) @@ -310,10 +306,10 @@ layout-lines (->> (init-layout-lines shape children layout-bounds) (add-lines-positions shape layout-bounds) - (into [] - (comp (map (partial add-line-spacing shape layout-bounds)) - (map (partial add-children-resizes shape)))))] + (into [] (comp (map (partial add-line-spacing shape layout-bounds)) + (map (partial add-children-resizes shape)))))] {:layout-lines layout-lines :layout-bounds layout-bounds :reverse? reverse?})) + diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index 039f17f98..406a31927 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -6,27 +6,43 @@ (ns app.common.geom.shapes.flex-layout.modifiers (:require + [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes.flex-layout.positions :as fpo] [app.common.geom.shapes.points :as gpo] - [app.common.geom.shapes.transforms :as gst] + [app.common.geom.shapes.transforms :as gtr] [app.common.types.modifiers :as ctm] [app.common.types.shape.layout :as ctl])) (defn normalize-child-modifiers "Apply the modifiers and then normalized them against the parent coordinates" - [modifiers parent child {:keys [transform transform-inverse] :as transformed-parent}] + [modifiers {:keys [transform transform-inverse] :as parent} child transformed-parent-bounds] + + (let [child-bounds (:points child) + parent-bounds (:points parent) + + transformed-child-bounds (gtr/transform-bounds child-bounds modifiers) + + child-bb-before (gpo/parent-coords-bounds child-bounds parent-bounds) + child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds) + + scale-x (/ (gpo/width-points child-bb-before) (gpo/width-points child-bb-after)) + scale-y (/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after)) + + resize-vector (gpt/point scale-x scale-y) + modif-transform (ctm/modifiers->transform modifiers) + modif-transform-inverse (gmt/inverse modif-transform) + resize-transform (gmt/multiply modif-transform transform) + resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse) + resize-origin (gpo/origin transformed-child-bounds)] - (let [transformed-child (gst/transform-shape child modifiers) - child-bb-before (gst/parent-coords-rect child parent) - child-bb-after (gst/parent-coords-rect transformed-child transformed-parent) - scale-x (/ (:width child-bb-before) (:width child-bb-after)) - scale-y (/ (:height child-bb-before) (:height child-bb-after)) - resize-origin (-> transformed-parent :points gpo/origin) - resize-vector (gpt/point scale-x scale-y)] (-> modifiers (ctm/select-child-modifiers) - (ctm/resize resize-vector resize-origin transform transform-inverse)))) + (ctm/resize + resize-vector + resize-origin + resize-transform + resize-transform-inverse)))) (defn calc-fill-width-data "Calculates the size and modifiers for the width of an auto-fill child" @@ -74,10 +90,8 @@ (defn layout-child-modifiers "Calculates the modifiers for the layout" - [parent child layout-line] - (let [child-bounds (gst/parent-coords-points child parent) - - child-origin (gpo/origin child-bounds) + [parent child child-bounds layout-line] + (let [child-origin (gpo/origin child-bounds) child-width (gpo/width-points child-bounds) child-height (gpo/height-points child-bounds) diff --git a/common/src/app/common/geom/shapes/flex_layout/positions.cljc b/common/src/app/common/geom/shapes/flex_layout/positions.cljc index 3c710f669..cd5cff837 100644 --- a/common/src/app/common/geom/shapes/flex_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/positions.cljc @@ -167,7 +167,7 @@ "Calculates the position for the current shape given the layout-data context" [parent child child-width child-height - {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y line-height line-width] :as layout-data}] + {:keys [start-p layout-gap-row layout-gap-col margin-x margin-y line-height line-width layout-bounds] :as layout-data}] (let [row? (ctl/row? parent) col? (ctl/col? parent) @@ -193,9 +193,8 @@ [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child) - points (:points parent) - hv (partial gpo/start-hv points) - vv (partial gpo/start-vv points) + hv (partial gpo/start-hv layout-bounds) + vv (partial gpo/start-vv layout-bounds) corner-p (cond-> start-p @@ -247,13 +246,13 @@ (gpt/add (vv margin-y))) ;; Fix position when layout is flipped - corner-p - (cond-> corner-p - (:flip-x parent) - (gpt/add (hv child-width)) - - (:flip-y parent) - (gpt/add (vv child-height))) + ;;corner-p + ;;(cond-> corner-p + ;; (:flip-x parent) + ;; (gpt/add (hv child-width)) + ;; + ;; (:flip-y parent) + ;; (gpt/add (vv child-height))) next-p (cond-> start-p diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index c23e07258..5b022868e 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -12,6 +12,7 @@ [app.common.geom.shapes.constraints :as gct] [app.common.geom.shapes.flex-layout :as gcl] [app.common.geom.shapes.pixel-precision :as gpp] + [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gtr] [app.common.pages.helpers :as cph] [app.common.spec :as us] @@ -91,12 +92,12 @@ (defn- set-children-modifiers "Propagates the modifiers from a parent too its children applying constraints if necesary" - [modif-tree objects parent transformed-parent ignore-constraints] + [modif-tree objects parent transformed-parent-bounds ignore-constraints] (let [children (:shapes parent) modifiers (dm/get-in modif-tree [(:id parent) :modifiers])] + ;; Move modifiers don't need to calculate constraints (if (ctm/only-move? modifiers) - ;; Move modifiers don't need to calculate constraints (loop [modif-tree modif-tree children (seq children)] (if-let [current (first children)] @@ -105,49 +106,65 @@ modif-tree)) ;; Check the constraints, then resize - (let [parent (gtr/transform-shape parent (ctm/select-parent-modifiers modifiers))] + (let [parent-bounds (gtr/transform-bounds (:points parent) (ctm/select-parent-modifiers modifiers))] (loop [modif-tree modif-tree children (seq children)] - (if-let [current (first children)] - (let [child-modifiers (gct/calc-child-modifiers parent (get objects current) modifiers ignore-constraints transformed-parent)] + (if (empty? children) + modif-tree + (let [child-id (first children) + child (get objects child-id) + child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints parent-bounds @transformed-parent-bounds)] (recur (cond-> modif-tree (not (ctm/empty? child-modifiers)) - (update-in [current :modifiers] ctm/add-modifiers child-modifiers)) - (rest children))) - modif-tree)))))) + (update-in [child-id :modifiers] ctm/add-modifiers child-modifiers)) + (rest children))))))))) (defn- process-layout-children - [modif-tree objects parent transformed-parent] + [modif-tree objects parent transformed-parent-bounds] (letfn [(process-child [modif-tree child] (let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) child-modifiers (-> modifiers (ctm/select-child-geometry-modifiers) - (gcl/normalize-child-modifiers parent child transformed-parent))] + (gcl/normalize-child-modifiers parent child @transformed-parent-bounds))] (cond-> modif-tree (not (ctm/empty? child-modifiers)) (update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))] - (let [children (map (d/getf objects) (:shapes transformed-parent))] + (let [children (map (d/getf objects) (:shapes parent))] (reduce process-child modif-tree children)))) + +(defn get-bounds + [objects modif-tree shape] + + (let [modifiers (-> (dm/get-in modif-tree [(:id shape) :modifiers]) + (ctm/select-geometry)) + + children (cph/get-immediate-children objects (:id shape)) + bounds (cond + (cph/group-shape? shape) + (let [children-bounds (->> children (mapv (partial get-bounds objects modif-tree)))] + (gtr/group-bounds shape children-bounds)) + + (cph/mask-shape? shape) + (get-bounds objects modif-tree (-> children first)) + + :else + (:points shape))] + + (gtr/transform-bounds bounds modifiers))) + + (defn- set-layout-modifiers - [modif-tree objects parent] + [modif-tree objects parent transformed-parent-bounds] - (letfn [(apply-modifiers [modif-tree child] - (let [modifiers (-> (dm/get-in modif-tree [(:id child) :modifiers]) - (ctm/select-geometry))] - (cond - (cph/group-like-shape? child) - (gtr/apply-group-modifiers child objects modif-tree) + (letfn [(apply-modifiers [child] + [(-> (get-bounds objects modif-tree child) + (gpo/parent-coords-bounds @transformed-parent-bounds)) + child]) - (some? modifiers) - (gtr/transform-shape child modifiers) - - :else - child))) - - (set-child-modifiers [parent [layout-line modif-tree] child] + (set-child-modifiers [[layout-line modif-tree] [child-bounds child]] (let [[modifiers layout-line] - (gcl/layout-child-modifiers parent child layout-line) + (gcl/layout-child-modifiers parent child child-bounds layout-line) modif-tree (cond-> modif-tree @@ -156,13 +173,12 @@ [layout-line modif-tree]))] - (let [children (map (d/getf objects) (:shapes parent)) - children (->> children (map (partial apply-modifiers modif-tree))) - layout-data (gcl/calc-layout-data parent children) + (let [children (->> (:shapes parent) + (map (comp apply-modifiers (d/getf objects)))) + layout-data (gcl/calc-layout-data parent children @transformed-parent-bounds) children (into [] (cond-> children (not (:reverse? layout-data)) reverse)) max-idx (dec (count children)) layout-lines (:layout-lines layout-data)] - (loop [modif-tree modif-tree layout-line (first layout-lines) pending (rest layout-lines) @@ -172,7 +188,7 @@ children (subvec children from-idx to-idx) [_ modif-tree] - (reduce (partial set-child-modifiers parent) [layout-line modif-tree] children)] + (reduce set-child-modifiers [layout-line modif-tree] children)] (recur modif-tree (first pending) (rest pending) to-idx)) modif-tree))))) @@ -195,11 +211,9 @@ (ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))] (let [children (->> parent :shapes (map (d/getf objects))) - {auto-width :width auto-height :height} (when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent))) (gcl/layout-content-bounds parent children))] - (cond-> (ctm/empty) (and (some? auto-width) (ctl/auto-width? parent)) (set-parent-auto-width auto-width) @@ -214,11 +228,12 @@ root? (= uuid/zero parent-id) modifiers (-> (dm/get-in modif-tree [parent-id :modifiers]) (ctm/select-geometry)) - transformed-parent (gtr/transform-shape parent modifiers) + + transformed-parent-bounds (delay (gtr/transform-bounds (:points parent) modifiers)) has-modifiers? (ctm/child-modifiers? modifiers) layout? (ctl/layout? parent) - auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) + auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent)) parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) ;; If the current child is inside the layout we ignore the constraints @@ -226,11 +241,11 @@ [(cond-> modif-tree (and (not layout?) has-modifiers? parent? (not root?)) - (set-children-modifiers objects parent transformed-parent (or ignore-constraints inside-layout?)) + (set-children-modifiers objects parent transformed-parent-bounds (or ignore-constraints inside-layout?)) layout? - (-> (process-layout-children objects parent transformed-parent) - (set-layout-modifiers objects transformed-parent))) + (-> (process-layout-children objects parent transformed-parent-bounds) + (set-layout-modifiers objects parent transformed-parent-bounds))) ;; Auto-width/height can change the positions in the parent so we need to recalculate (cond-> autolayouts auto? (conj (:id parent)))])) @@ -247,21 +262,21 @@ [objects tree-seq modif-tree] (letfn [(apply-shape [objects {:keys [id] :as shape}] - (if (cph/group-shape? shape) - (let [children (cph/get-children objects id)] - (assoc objects id - (cond - (cph/mask-shape? shape) - (gtr/update-mask-selrect shape children) + (let [modifiers (get-in modif-tree [id :modifiers]) + object + (cond + (cph/mask-shape? shape) + (gtr/update-mask-selrect shape (cph/get-children objects id)) - :else - (gtr/update-group-selrect shape children)))) + (cph/group-shape? shape) + (gtr/update-group-selrect shape (cph/get-children objects id)) - (let [modifiers (get-in modif-tree [id :modifiers]) - object (cond-> shape - (some? modifiers) - (gtr/transform-shape modifiers))] - (assoc objects id object))))] + (some? modifiers) + (gtr/transform-shape shape modifiers) + + :else + shape)] + (assoc objects id object)))] (reduce apply-shape objects (reverse tree-seq)))) diff --git a/common/src/app/common/geom/shapes/pixel_precision.cljc b/common/src/app/common/geom/shapes/pixel_precision.cljc index 93dd26dcd..8b5c8b053 100644 --- a/common/src/app/common/geom/shapes/pixel_precision.cljc +++ b/common/src/app/common/geom/shapes/pixel_precision.cljc @@ -9,15 +9,15 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] + [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.rect :as gpr] - [app.common.geom.shapes.transforms :as gtr] [app.common.math :as mth] [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm])) (defn size-pixel-precision - [modifiers {:keys [points transform transform-inverse] :as shape}] + [modifiers {:keys [transform transform-inverse] :as shape} points] (let [origin (gpo/origin points) curr-width (gpo/width-points points) curr-height (gpo/height-points points) @@ -36,7 +36,7 @@ (ctm/resize scalev origin transform transform-inverse)))) (defn position-pixel-precision - [modifiers {:keys [points]}] + [modifiers _ points] (let [bounds (gpr/points->rect points) corner (gpt/point bounds) target-corner (gpt/round corner) @@ -47,24 +47,28 @@ (defn set-pixel-precision "Adjust modifiers so they adjust to the pixel grid" [modifiers shape] - (let [move? (ctm/only-move? modifiers)] - (cond-> modifiers - (not move?) - (size-pixel-precision shape) + (let [points (-> shape :points (gco/transform-points (ctm/modifiers->transform modifiers))) + has-resize? (not (ctm/only-move? modifiers)) - :always - (position-pixel-precision shape)))) + [modifiers points] + (let [modifiers + (cond-> modifiers + has-resize? (size-pixel-precision shape points)) + + points + (cond-> (:points shape) + has-resize? (gco/transform-points (ctm/modifiers->transform modifiers)))] + [modifiers points])] + (position-pixel-precision modifiers shape points))) (defn adjust-pixel-precision [modif-tree objects] (let [update-modifiers (fn [modif-tree shape] (let [modifiers (dm/get-in modif-tree [(:id shape) :modifiers])] - (if-not (ctm/has-geometry? modifiers) - modif-tree - (let [shape (gtr/transform-shape shape modifiers)] - (-> modif-tree - (update-in [(:id shape) :modifiers] set-pixel-precision shape))))))] + (cond-> modif-tree + (ctm/has-geometry? modifiers) + (update-in [(:id shape) :modifiers] set-pixel-precision shape))))] (->> (keys modif-tree) (map (d/getf objects)) diff --git a/common/src/app/common/geom/shapes/points.cljc b/common/src/app/common/geom/shapes/points.cljc index adae25ace..3bbfdeaa7 100644 --- a/common/src/app/common/geom/shapes/points.cljc +++ b/common/src/app/common/geom/shapes/points.cljc @@ -6,12 +6,21 @@ (ns app.common.geom.shapes.points (:require - [app.common.geom.point :as gpt])) + [app.common.geom.point :as gpt] + [app.common.geom.shapes.intersect :as gsi])) (defn origin [points] (nth points 0)) +(defn hv + [[p0 p1 _ _]] + (gpt/to-vec p0 p1)) + +(defn vv + [[p0 _ _ p3]] + (gpt/to-vec p0 p3)) + (defn start-hv "Horizontal vector from the origin with a magnitude `val`" [[p0 p1 _ _] val] @@ -60,3 +69,46 @@ (-> p1 (gpt/add right-v) (gpt/add top-v)) (-> p2 (gpt/add right-v) (gpt/add bottom-v)) (-> p3 (gpt/add left-v) (gpt/add bottom-v))]))) + + + +#_(defn parent-coords-rect + [child-bounds parent-bounds] + #_(-> child-bounds + (gco/transform-points (:transform-inverse parent)) + (gpr/points->rect))) + +(defn closest-first + "Reorders the points so the closest to the line start-end is the first" + [[a b c d] start end] + + (let [da (gpt/point-line-distance a start end) + db (gpt/point-line-distance b start end) + dc (gpt/point-line-distance c start end) + dd (gpt/point-line-distance d start end)] + + (cond + (and (<= da db) (<= da dc) (<= da dd)) + [a b c d] + + (and (<= db da) (<= db dc) (<= db dd)) + [b c d a] + + (and (<= dc da) (<= dc db) (<= dc dd)) + [c d a b] + + :else + [d a b c]))) + +(defn parent-coords-bounds + [bounds [p1 p2 _ p4]] + + (let [[b1 b2 b3 b4] (closest-first bounds p1 p2) + hv (gpt/to-vec p1 p2) + vv (gpt/to-vec p1 p4) + + i1 (gsi/line-line-intersect b1 (gpt/add hv b1) b4 (gpt/add b4 vv)) + i2 (gsi/line-line-intersect b1 (gpt/add hv b1) b2 (gpt/add b2 vv)) + i3 (gsi/line-line-intersect b3 (gpt/add hv b3) b2 (gpt/add b2 vv)) + i4 (gsi/line-line-intersect b3 (gpt/add hv b3) b4 (gpt/add b4 vv))] + [i1 i2 i3 i4])) diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 43b4dad21..43d8902e2 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -369,6 +369,16 @@ (update :width + (:width deltas)) (update :height + (:height deltas))))))) +(defn group-bounds + [group children-bounds] + (let [shape-center (gco/center-shape group) + points (flatten children-bounds) + points (if (empty? points) (:points group) points)] + (-> points + (gco/transform-points shape-center (:transform-inverse group (gmt/matrix))) + (gpr/squared-points) + (gco/transform-points shape-center (:transform group (gmt/matrix)))))) + (defn update-group-selrect [group children] (let [shape-center (gco/center-shape group) @@ -541,19 +551,3 @@ :else group)))) - -(defn parent-coords-rect - [child parent] - (-> child - :points - (gco/transform-points (:transform-inverse parent)) - (gpr/points->rect))) - -(defn parent-coords-points - [child parent] - (-> child - :points - (gco/transform-points (:transform-inverse parent)) - (gpr/points->rect) - (gpr/rect->points) - (gco/transform-points (:transform parent)))) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index d95d0d31f..cd4b445b5 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -8,6 +8,7 @@ (:refer-clojure :exclude [empty empty?]) (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes.common :as gco] @@ -50,7 +51,6 @@ (or (not (mth/almost-zero? (- (:x vector) 1))) (not (mth/almost-zero? (- (:y vector) 1))))) - (defn- mergeable-move? [op1 op2] (and (= :move (:type op1)) @@ -106,6 +106,13 @@ (conj item))) (conj operations op))))) +(defn valid-vector? + [{:keys [x y]}] + (and (some? x) + (some? y) + (not (mth/nan? x)) + (not (mth/nan? y)))) + ;; Public builder API (defn empty [] @@ -116,12 +123,14 @@ (move-parent modifiers (gpt/point x y))) ([modifiers vector] + (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) (cond-> modifiers (move-vec? vector) - (update :geometry-parent conjv {:type :move :vector vector})))) + (update :geometry-parent maybe-add-move {:type :move :vector vector})))) (defn resize-parent ([modifiers vector origin] + (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) (cond-> modifiers (resize-vec? vector) (update :geometry-parent maybe-add-resize {:type :resize @@ -129,6 +138,7 @@ :origin origin}))) ([modifiers vector origin transform transform-inverse] + (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) (cond-> modifiers (resize-vec? vector) (update :geometry-parent maybe-add-resize {:type :resize @@ -141,12 +151,14 @@ (move modifiers (gpt/point x y))) ([modifiers vector] + (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) (cond-> modifiers (move-vec? vector) (update :geometry-child maybe-add-move {:type :move :vector vector})))) (defn resize ([modifiers vector origin] + (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) (cond-> modifiers (resize-vec? vector) (update :geometry-child maybe-add-resize {:type :resize @@ -154,6 +166,7 @@ :origin origin}))) ([modifiers vector origin transform transform-inverse] + (assert (valid-vector? vector) (dm/str "Invalid move vector: " (:x vector) "," (:y vector))) (cond-> modifiers (resize-vec? vector) (update :geometry-child maybe-add-resize {:type :resize @@ -355,8 +368,9 @@ (defn only-move? "Returns true if there are only move operations" [{:keys [geometry-child geometry-parent]}] - (and (every? #(= :move (:type %)) geometry-child) - (every? #(= :move (:type %)) geometry-parent))) + (let [move-op? #(= :move (:type %))] + (and (every? move-op? geometry-child) + (every? move-op? geometry-parent)))) (defn has-geometry? [{:keys [geometry-parent geometry-child]}] @@ -418,16 +432,19 @@ (gmt/multiply (gmt/translate-matrix vector) matrix) :resize - (gmt/multiply - (-> (gmt/matrix) - (gmt/translate origin) - (cond-> (some? transform) - (gmt/multiply transform)) - (gmt/scale vector) - (cond-> (some? transform-inverse) - (gmt/multiply transform-inverse)) - (gmt/translate (gpt/negate origin))) - matrix) + (let [origin (cond-> origin + (or (some? transform-inverse)(some? transform)) + (gpt/transform transform-inverse))] + (gmt/multiply + (-> (gmt/matrix) + (cond-> (some? transform) + (gmt/multiply transform)) + (gmt/translate origin) + (gmt/scale vector) + (gmt/translate (gpt/negate origin)) + (cond-> (some? transform-inverse) + (gmt/multiply transform-inverse))) + matrix)) :rotation (gmt/multiply diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 24e941377..0d078ecbd 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -12,9 +12,8 @@ [app.common.files.features :as ffeat] [app.common.geom.align :as gal] [app.common.geom.point :as gpt] - [app.common.geom.proportions :as gpr] + [app.common.geom.proportions :as gpp] [app.common.geom.shapes :as gsh] - [app.common.geom.shapes.rect :as gpsr] [app.common.logging :as log] [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] @@ -937,7 +936,7 @@ (if-not lock (assoc shape :proportion-lock false) (-> (assoc shape :proportion-lock true) - (gpr/assign-proportions))))] + (gpp/assign-proportions))))] (rx/of (dch/update-shapes [id] assign-proportions)))))) (defn toggle-proportion-lock @@ -1776,10 +1775,10 @@ media (vals (:media file-data')) media-points - (map #(assoc % :points (gpsr/rect->points {:x 0 - :y 0 - :width (:width %) - :height (:height %)})) + (map #(assoc % :points (gsh/rect->points {:x 0 + :y 0 + :width (:width %) + :height (:height %)})) media) shape-grid diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 4143b3152..01a2bdb29 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -8,7 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] - [app.common.geom.proportions :as gpr] + [app.common.geom.proportions :as gpp] [app.common.geom.shapes :as gsh] [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] @@ -69,7 +69,7 @@ (get-shape-layer-position objects selected-non-frames attrs)] (-> (merge default-attrs attrs) - (gpr/setup-proportions) + (gpp/setup-proportions) (assoc :frame-id frame-id :parent-id parent-id :index index)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index 02c072434..6798a4a5e 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -146,8 +146,8 @@ (fn [id] (let [new-shape (get text-shapes id) old-shape (get prev-text-shapes id) - old-modifiers (get prev-modifiers id) - new-modifiers (get modifiers id) + old-modifiers (ctm/select-geometry (get prev-modifiers id)) + new-modifiers (ctm/select-geometry (get modifiers id)) remote? (some? (-> new-shape meta :session-id)) ] @@ -155,10 +155,9 @@ (not (identical? old-shape new-shape)) (not= (dissoc old-shape :migrate) (dissoc new-shape :migrate))) + (and (not= new-modifiers old-modifiers) - (or (nil? new-modifiers) - (nil? old-modifiers) - (not (ctm/only-move? new-modifiers)) + (or (not (ctm/only-move? new-modifiers)) (not (ctm/only-move? old-modifiers)))) ;; When the position data is nil we force to recalculate diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 80217083d..e50758d55 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -429,6 +429,12 @@ :hover-top-frame-id @hover-top-frame-id :zoom zoom}]) + (when (debug? :parent-bounds) + [:& wvd/debug-parent-bounds {:selected-shapes selected-shapes + :objects objects-modified + :hover-top-frame-id @hover-top-frame-id + :zoom zoom}]) + (when show-selection-handlers? [:g.selection-handlers {:clipPath "url(#clip-handlers)"} [:defs diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index f1fcecf0e..14da00e68 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -14,6 +14,7 @@ [app.common.geom.shapes.points :as gpo] [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl] + [app.common.uuid :as uuid] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -76,7 +77,7 @@ col? (ctl/col? shape) children (cph/get-immediate-children objects (:id shape)) - layout-data (gsl/calc-layout-data shape children) + layout-data (gsl/calc-layout-data shape children (:points shape)) layout-bounds (:layout-bounds layout-data) xv #(gpo/start-hv layout-bounds %) @@ -112,8 +113,9 @@ shape (or selected-frame (get objects hover-top-frame-id))] (when (and shape (:layout shape)) - (let [children (cph/get-immediate-children objects (:id shape)) - layout-data (gsl/calc-layout-data shape children) + (let [children (->> (cph/get-immediate-children objects (:id shape)) + (map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %))) + layout-data (gsl/calc-layout-data shape children (:points shape)) drop-areas (gsl/layout-drop-areas shape layout-data children)] [:g.debug-layout {:pointer-events "none" :transform (gsh/transform-str shape)} @@ -135,3 +137,51 @@ :alignment-baseline "hanging" :fill "black"} (:index drop-area)]])])))) + +(mf/defc shape-parent-bound + {::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "parent"]))] + ::mf/wrap-props false} + [props] + + (let [shape (unchecked-get props "shape") + parent (unchecked-get props "parent") + zoom (unchecked-get props "zoom") + [i1 i2 i3 i4] (gpo/parent-coords-bounds (:points shape) (:points parent))] + [:* + [:polygon {:points (->> [i1 i2 i3 i4] (map #(dm/fmt "%,%" (:x %) (:y %))) (str/join ",")) + :style {:fill "none" :stroke "red" :stroke-width (/ 1 zoom)}}] + + [:line {:x1 (:x i1) + :y1 (:y i1) + :x2 (:x i2) + :y2 (:y i2) + :style {:stroke "green" :stroke-width (/ 1 zoom)}}] + [:line {:x1 (:x i1) + :y1 (:y i1) + :x2 (:x i4) + :y2 (:y i4) + :style {:stroke "blue" :stroke-width (/ 1 zoom)}}]])) + +(mf/defc debug-parent-bounds + {::mf/wrap-props false} + [props] + + (let [objects (unchecked-get props "objects") + zoom (unchecked-get props "objects") + selected-shapes (unchecked-get props "selected-shapes") + hover-top-frame-id (unchecked-get props "hover-top-frame-id") + + selected-frame + (when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type))) + (first selected-shapes)) + + parent (or selected-frame (get objects hover-top-frame-id))] + + (when (and (some? parent) (not= uuid/zero (:id parent))) + (let [children (cph/get-immediate-children objects (:id parent))] + [:g.debug-parent-bounds {:pointer-events "none"} + (for [[idx child] (d/enumerate children)] + [:> shape-parent-bound {:key (dm/str "bound-" idx) + :zoom zoom + :shape child + :parent parent}])])))) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index f64e98f4b..18900f901 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -76,6 +76,9 @@ ;; Makes the pixel grid red so its more visibile :pixel-grid + + ;; Show the bounds relative to the parent + :parent-bounds }) ;; These events are excluded when we activate the :events flag