0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-25 07:58:49 -05:00

🐛 Synchronize text positions in components

This commit is contained in:
Andrés Moya 2022-05-17 09:59:09 +02:00 committed by Alonso Torres
parent fa00d674eb
commit d666755159
6 changed files with 84 additions and 18 deletions

View file

@ -100,7 +100,6 @@
(assert (point? other))
(Point. (/ x ox) (/ y oy)))
(defn min
([] (min nil nil))
([p1] (min p1 nil))
@ -139,6 +138,15 @@
(mth/sqrt (+ (mth/pow dx 2)
(mth/pow dy 2)))))
(defn distance-vector
"Calculate the distance, separated x and y."
[{x :x y :y :as p} {ox :x oy :y :as other}]
(assert (point? p))
(assert (point? other))
(let [dx (mth/abs (- x ox))
dy (mth/abs (- y oy))]
(Point. dx dy)))
(defn length
[{x :x y :y :as p}]
(assert (point? p))

View file

@ -6,6 +6,7 @@
(ns app.common.geom.shapes
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt]
[app.common.geom.shapes.bool :as gsb]
@ -38,6 +39,14 @@
;; --- Helpers
(defn left-bound
[shape]
(get shape :x (:x (:selrect shape)))) ; Paths don't have :x attribute
(defn top-bound
[shape]
(get shape :y (:y (:selrect shape)))) ; Paths don't have :y attribute
(defn fully-contained?
"Checks if one rect is fully inside the other"
[rect other]
@ -96,6 +105,35 @@
(mth/sqrt (* 2 stroke-width stroke-width))
(- (mth/sqrt (* 2 stroke-width stroke-width)) stroke-width)))
(defn close-attrs?
"Compares two shapes attributes to see if they are equal or almost
equal (in case of numeric). Takes into account attributes that are
data structures with numbers inside."
([attr val1 val2]
(close-attrs? attr val1 val2 mth/float-equal-precision))
([attr val1 val2 precision]
(let [close-val? (fn [num1 num2] (< (mth/abs (- num1 num2)) precision))]
(cond
(and (number? val1) (number? val2))
(close-val? val1 val2)
(= attr :selrect)
(every? #(close-val? (get val1 %) (get val2 %))
[:x :y :x1 :y1 :x2 :y2 :width :height])
(= attr :points)
(every? #(and (close-val? (:x (first %)) (:x (second %)))
(close-val? (:y (first %)) (:y (second %))))
(d/zip val1 val2))
(= attr :position-data)
(every? #(and (close-val? (:x (first %)) (:x (second %)))
(close-val? (:y (first %)) (:y (second %))))
(d/zip val1 val2))
:else
(= val1 val2)))))
;; EXPORTS
(dm/export gco/center-shape)

View file

@ -11,6 +11,7 @@
[app.common.exceptions :as ex]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.bool :as gshb]
[app.common.math :as mth]
[app.common.pages.common :refer [component-sync-attrs]]
[app.common.pages.helpers :as cph]
[app.common.pages.init :as init]
@ -433,25 +434,35 @@
(defmethod process-operation :set
[shape op]
(let [attr (:attr op)
val (:val op)
ignore (:ignore-touched op)
(let [attr (:attr op)
group (get component-sync-attrs attr)
val (:val op)
shape-val (get shape attr)
ignore (:ignore-touched op)
ignore-geometry (:ignore-geometry op)
shape-ref (:shape-ref shape)
group (get component-sync-attrs attr)
root-name? (and (= group :name-group)
(:component-root? shape))]
is-geometry? (and (or (= group :geometry-group)
(and (= group :content-group) (= (:type shape) :path)))
(not (#{:width :height} attr))) ;; :content in paths are also considered geometric
shape-ref (:shape-ref shape)
root-name? (and (= group :name-group)
(:component-root? shape))
;; For geometric attributes, there are cases in that the value changes
;; slightly (e.g. when rounding to pixel, or when recalculating text
;; positions in different zoom levels). To take this into account, we
;; ignore geometric changes smaller than 1 pixel.
equal? (if is-geometry?
(gsh/close-attrs? attr val shape-val 1)
(gsh/close-attrs? attr val shape-val))]
(cond-> shape
;; Depending on the origin of the attribute change, we need or not to
;; set the "touched" flag for the group the attribute belongs to.
;; In some cases we need to ignore touched only if the attribute is
;; geometric (position, width or transformation).
(and shape-ref group (not ignore) (not= val (get shape attr))
(and shape-ref group (not ignore) (not equal?)
(not root-name?)
(not (and ignore-geometry
(and (= group :geometry-group)
(not (#{:width :height} attr))))))
(not (and ignore-geometry is-geometry?)))
(->
(update :touched cph/set-touched-group group)
(dissoc :remote-synced?))

View file

@ -59,8 +59,10 @@
:y :geometry-group
:width :geometry-group
:height :geometry-group
:rotation :geometry-group
:transform :geometry-group
:transform-inverse :geometry-group
:position-data :geometry-group
:opacity :layer-effects-group
:blend-mode :layer-effects-group
:shadow :shadow-group

View file

@ -252,15 +252,23 @@
shape-delta
(when root
(gpt/point (- (:x shape) (:x root))
(- (:y shape) (:y root))))
(gpt/point (- (gsh/left-bound shape) (gsh/left-bound root))
(- (gsh/top-bound shape) (gsh/top-bound root))))
transformed-shape-delta
(when transformed-root
(gpt/point (- (:x transformed-shape) (:x transformed-root))
(- (:y transformed-shape) (:y transformed-root))))
(gpt/point (- (gsh/left-bound transformed-shape) (gsh/left-bound transformed-root))
(- (gsh/top-bound transformed-shape) (gsh/top-bound transformed-root))))
ignore-geometry? (= shape-delta transformed-shape-delta)]
;; There are cases in that the coordinates change slightly (e.g. when
;; rounding to pixel, or when recalculating text positions in different
;; zoom levels). To take this into account, we ignore movements smaller
;; than 1 pixel.
distance (if (and shape-delta transformed-shape-delta)
(gpt/distance-vector shape-delta transformed-shape-delta)
(gpt/point 0 0))
ignore-geometry? (and (< (:x distance) 1) (< (:y distance) 1))]
[root transformed-root ignore-geometry?]))

View file

@ -72,7 +72,6 @@
(defn- update-text-modifier
[{:keys [grow-type id]} node]
(let [position-data (utp/calc-position-data node)
props {:position-data position-data}