mirror of
https://github.com/penpot/penpot.git
synced 2025-04-05 11:31:35 -05:00
Merge pull request #2733 from penpot/alotor-performance
Performance enhancements
This commit is contained in:
commit
b273bd44c5
21 changed files with 398 additions and 216 deletions
|
@ -170,8 +170,7 @@
|
|||
(dm/get-prop p2 :x))
|
||||
dy (- (dm/get-prop p1 :y)
|
||||
(dm/get-prop p2 :y))]
|
||||
(mth/sqrt (+ (mth/pow dx 2)
|
||||
(mth/pow dy 2)))))
|
||||
(mth/hypot dx dy)))
|
||||
|
||||
(defn distance-vector
|
||||
"Calculate the distance, separated x and y."
|
||||
|
@ -191,8 +190,7 @@
|
|||
(assert (point? pt) "point instance expected")
|
||||
(let [x (dm/get-prop pt :x)
|
||||
y (dm/get-prop pt :y)]
|
||||
(mth/sqrt (+ (mth/pow x 2)
|
||||
(mth/pow y 2)))))
|
||||
(mth/hypot x y)))
|
||||
|
||||
(defn angle
|
||||
"Returns the smaller angle between two vectors.
|
||||
|
|
|
@ -28,6 +28,16 @@
|
|||
;; [(get-in objects [k :name]) v]))
|
||||
;; modif-tree))))
|
||||
|
||||
(defn children-sequence
|
||||
"Given an id returns a sequence of its children"
|
||||
[id objects]
|
||||
|
||||
(->> (tree-seq
|
||||
#(d/not-empty? (dm/get-in objects [% :shapes]))
|
||||
#(dm/get-in objects [% :shapes])
|
||||
id)
|
||||
(map #(get objects %))))
|
||||
|
||||
(defn resolve-tree-sequence
|
||||
"Given the ids that have changed search for layout roots to recalculate"
|
||||
[ids objects]
|
||||
|
@ -75,20 +85,12 @@
|
|||
|
||||
(cond-> result
|
||||
(not contains-parent?)
|
||||
(conj root)))))
|
||||
|
||||
(generate-tree ;; Generate a tree sequence from a given root id
|
||||
[id]
|
||||
(->> (tree-seq
|
||||
#(d/not-empty? (dm/get-in objects [% :shapes]))
|
||||
#(dm/get-in objects [% :shapes])
|
||||
id)
|
||||
(map #(get objects %))))]
|
||||
(conj root)))))]
|
||||
|
||||
(let [roots (->> ids (reduce calculate-common-roots #{}))]
|
||||
(concat
|
||||
(when (contains? ids uuid/zero) [(get objects uuid/zero)])
|
||||
(mapcat generate-tree roots)))))
|
||||
(mapcat #(children-sequence % objects) roots)))))
|
||||
|
||||
(defn- set-children-modifiers
|
||||
"Propagates the modifiers from a parent too its children applying constraints if necesary"
|
||||
|
@ -296,28 +298,88 @@
|
|||
result (assoc result (:id shape) new-bounds)]
|
||||
(recur result (rest shapes)))))))
|
||||
|
||||
(defn reflow-layout
|
||||
[objects old-modif-tree bounds ignore-constraints id]
|
||||
|
||||
(let [tree-seq (children-sequence id objects)
|
||||
|
||||
[modif-tree _]
|
||||
(reduce
|
||||
#(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}]
|
||||
tree-seq)
|
||||
|
||||
bounds (transform-bounds bounds objects modif-tree tree-seq)
|
||||
|
||||
modif-tree (merge-modif-tree old-modif-tree modif-tree)]
|
||||
[modif-tree bounds]))
|
||||
|
||||
(defn sizing-auto-modifiers
|
||||
"Recalculates the layouts to adjust the sizing: auto new sizes"
|
||||
[modif-tree sizing-auto-layouts objects bounds ignore-constraints]
|
||||
(loop [modif-tree modif-tree
|
||||
bounds bounds
|
||||
sizing-auto-layouts (reverse sizing-auto-layouts)]
|
||||
(if-let [current (first sizing-auto-layouts)]
|
||||
(let [parent-base (get objects current)
|
||||
(let [;; Step-1 resize the auto-width/height. Reflow the parents if they are also auto-width/height
|
||||
[modif-tree bounds to-reflow]
|
||||
(loop [modif-tree modif-tree
|
||||
bounds bounds
|
||||
sizing-auto-layouts (reverse sizing-auto-layouts)
|
||||
to-reflow #{}]
|
||||
(if-let [current (first sizing-auto-layouts)]
|
||||
(let [parent-base (get objects current)
|
||||
|
||||
resize-modif-tree
|
||||
{current {:modifiers (calc-auto-modifiers objects bounds parent-base)}}
|
||||
[modif-tree bounds]
|
||||
(if (contains? to-reflow current)
|
||||
(reflow-layout objects modif-tree bounds ignore-constraints current)
|
||||
[modif-tree bounds])
|
||||
|
||||
tree-seq (resolve-tree-sequence #{current} objects)
|
||||
auto-resize-modifiers
|
||||
(calc-auto-modifiers objects bounds parent-base)
|
||||
|
||||
[resize-modif-tree _]
|
||||
(reduce #(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [resize-modif-tree #{}] tree-seq)
|
||||
to-reflow
|
||||
(cond-> to-reflow
|
||||
(contains? to-reflow current)
|
||||
(disj current))]
|
||||
|
||||
bounds (transform-bounds bounds objects resize-modif-tree tree-seq)
|
||||
(if (ctm/empty? auto-resize-modifiers)
|
||||
(recur modif-tree
|
||||
bounds
|
||||
(rest sizing-auto-layouts)
|
||||
to-reflow)
|
||||
|
||||
modif-tree (merge-modif-tree modif-tree resize-modif-tree)]
|
||||
(recur modif-tree bounds (rest sizing-auto-layouts)))
|
||||
modif-tree)))
|
||||
(let [resize-modif-tree {current {:modifiers auto-resize-modifiers}}
|
||||
|
||||
tree-seq (children-sequence current objects)
|
||||
|
||||
[resize-modif-tree _]
|
||||
(reduce
|
||||
#(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [resize-modif-tree #{}]
|
||||
tree-seq)
|
||||
|
||||
bounds (transform-bounds bounds objects resize-modif-tree tree-seq)
|
||||
|
||||
modif-tree (merge-modif-tree modif-tree resize-modif-tree)
|
||||
|
||||
to-reflow
|
||||
(cond-> to-reflow
|
||||
(and (ctl/layout-child-id? objects current)
|
||||
(not= uuid/zero (:frame-id parent-base)))
|
||||
(conj (:frame-id parent-base)))]
|
||||
(recur modif-tree
|
||||
bounds
|
||||
(rest sizing-auto-layouts)
|
||||
to-reflow))))
|
||||
[modif-tree bounds to-reflow]))
|
||||
|
||||
;; Step-2: After resizing we still need to reflow the layout parents that are not auto-width/height
|
||||
|
||||
tree-seq (resolve-tree-sequence to-reflow objects)
|
||||
|
||||
[reflow-modif-tree _]
|
||||
(reduce
|
||||
#(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}]
|
||||
tree-seq)
|
||||
|
||||
result (merge-modif-tree modif-tree reflow-modif-tree)]
|
||||
|
||||
result))
|
||||
|
||||
(defn set-objects-modifiers
|
||||
([modif-tree objects ignore-constraints snap-pixel?]
|
||||
|
|
|
@ -117,7 +117,7 @@
|
|||
[x y] (->> coords (mapv solve-derivative))
|
||||
|
||||
;; normalize value
|
||||
d (mth/sqrt (+ (* x x) (* y y)))]
|
||||
d (mth/hypot x y)]
|
||||
|
||||
(if (mth/almost-zero? d)
|
||||
(gpt/point 0 0)
|
||||
|
|
|
@ -139,12 +139,18 @@
|
|||
#?(:cljs (math/toDegrees radians)
|
||||
:clj (Math/toDegrees radians)))
|
||||
|
||||
(defn hypot
|
||||
"Square root of the squares addition"
|
||||
[a b]
|
||||
#?(:cljs (js/Math.hypot a b)
|
||||
:clj (Math/hypot a b)))
|
||||
|
||||
(defn distance
|
||||
"Calculate the distance between two points."
|
||||
[[x1 y1] [x2 y2]]
|
||||
(let [dx (- x1 x2)
|
||||
dy (- y1 y2)]
|
||||
(-> (sqrt (+ (pow dx 2) (pow dy 2)))
|
||||
(-> (hypot dx dy)
|
||||
(precision 2))))
|
||||
|
||||
(defn log10
|
||||
|
@ -182,3 +188,4 @@
|
|||
"Get the sign (+1 / -1) for the number"
|
||||
[n]
|
||||
(if (neg? n) -1 1))
|
||||
|
||||
|
|
|
@ -100,15 +100,13 @@
|
|||
(and (= :frame (:type shape)) (= :flex (:layout shape)))))
|
||||
|
||||
(defn layout-child? [objects shape]
|
||||
(let [parent-id (:parent-id shape)
|
||||
parent (get objects parent-id)]
|
||||
(layout? parent)))
|
||||
(let [frame-id (:frame-id shape)
|
||||
frame (get objects frame-id)]
|
||||
(layout? frame)))
|
||||
|
||||
(defn layout-child-id? [objects id]
|
||||
(let [shape (get objects id)
|
||||
parent-id (:parent-id shape)
|
||||
parent (get objects parent-id)]
|
||||
(layout? parent)))
|
||||
(let [shape (get objects id)]
|
||||
(layout-child? objects shape)))
|
||||
|
||||
(defn inside-layout?
|
||||
"Check if the shape is inside a layout"
|
||||
|
|
|
@ -37,19 +37,21 @@
|
|||
(assoc :x (- (:x point) (* sx (- dy dx)))))))
|
||||
|
||||
(defn resize-shape [{:keys [x y width height] :as shape} initial point lock?]
|
||||
(let [draw-rect (gsh/make-rect initial (cond-> point lock? (adjust-ratio initial)))
|
||||
shape-rect (gsh/make-rect x y width height)
|
||||
(if (and (some? x) (some? y) (some? width) (some? height))
|
||||
(let [draw-rect (gsh/make-rect initial (cond-> point lock? (adjust-ratio initial)))
|
||||
shape-rect (gsh/make-rect x y width height)
|
||||
|
||||
scalev (gpt/point (/ (:width draw-rect) (:width shape-rect))
|
||||
(/ (:height draw-rect) (:height shape-rect)))
|
||||
scalev (gpt/point (/ (:width draw-rect) (:width shape-rect))
|
||||
(/ (:height draw-rect) (:height shape-rect)))
|
||||
|
||||
movev (gpt/to-vec (gpt/point shape-rect) (gpt/point draw-rect))]
|
||||
movev (gpt/to-vec (gpt/point shape-rect) (gpt/point draw-rect))]
|
||||
|
||||
(-> shape
|
||||
(assoc :click-draw? false)
|
||||
(gsh/transform-shape (-> (ctm/empty)
|
||||
(ctm/resize scalev (gpt/point x y))
|
||||
(ctm/move movev))))))
|
||||
(-> shape
|
||||
(assoc :click-draw? false)
|
||||
(gsh/transform-shape (-> (ctm/empty)
|
||||
(ctm/resize scalev (gpt/point x y))
|
||||
(ctm/move movev)))))
|
||||
shape))
|
||||
|
||||
(defn update-drawing [state initial point lock?]
|
||||
(update-in state [:workspace-drawing :object] resize-shape initial point lock?))
|
||||
|
|
|
@ -415,10 +415,14 @@
|
|||
[id]
|
||||
(ptk/reify ::clean-text-modifier
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(->> (rx/of #(update % :workspace-text-modifier dissoc id))
|
||||
;; We delay a bit the change so there is no weird transition to the user
|
||||
(rx/delay 50)))))
|
||||
(watch [_ state _]
|
||||
(let [current-value (dm/get-in state [:workspace-text-modifier id])]
|
||||
;; We only dissocc the value when hasn't change after a time
|
||||
(->> (rx/of (fn [state]
|
||||
(cond-> state
|
||||
(identical? (dm/get-in state [:workspace-text-modifier id]) current-value)
|
||||
(update :workspace-text-modifier dissoc id))))
|
||||
(rx/delay 100))))))
|
||||
|
||||
(defn remove-text-modifier
|
||||
[id]
|
||||
|
|
|
@ -219,6 +219,7 @@
|
|||
|
||||
(rx/concat
|
||||
(->> ms/mouse-position
|
||||
(rx/filter some?)
|
||||
(rx/with-latest-from ms/mouse-position-shift ms/mouse-position-alt)
|
||||
(rx/map normalize-proportion-lock)
|
||||
(rx/switch-map (fn [[point _ _ :as current]]
|
||||
|
@ -600,9 +601,17 @@
|
|||
move-events (->> stream
|
||||
(rx/filter (ptk/type? ::nudge-selected-shapes))
|
||||
(rx/filter #(= direction (deref %))))
|
||||
stopper (->> move-events
|
||||
(rx/debounce 100)
|
||||
(rx/take 1))
|
||||
|
||||
stopper
|
||||
(->> move-events
|
||||
;; We stop when there's been 1s without movement or after 250ms after a key-up
|
||||
(rx/switch-map #(rx/merge
|
||||
(rx/timer 1000)
|
||||
(->> stream
|
||||
(rx/filter ms/key-up?)
|
||||
(rx/delay 250))))
|
||||
(rx/take 1))
|
||||
|
||||
scale (if shift? (gpt/point (or (:big nudge) 10)) (gpt/point (or (:small nudge) 1)))
|
||||
mov-vec (gpt/multiply (get-displacement direction) scale)]
|
||||
|
||||
|
|
|
@ -324,11 +324,7 @@
|
|||
(l/derived :workspace-editor-state st/state))
|
||||
|
||||
(def workspace-modifiers
|
||||
(l/derived :workspace-modifiers st/state))
|
||||
|
||||
(defn workspace-modifiers-by-id
|
||||
[ids]
|
||||
(l/derived #(select-keys % ids) workspace-modifiers))
|
||||
(l/derived :workspace-modifiers st/state =))
|
||||
|
||||
(def workspace-modifiers-with-objects
|
||||
(l/derived
|
||||
|
@ -340,20 +336,29 @@
|
|||
(and (= (:modifiers a) (:modifiers b))
|
||||
(identical? (:objects a) (:objects b))))))
|
||||
|
||||
(defn workspace-modifiers-by-frame-id
|
||||
[frame-id]
|
||||
(def workspace-frame-modifiers
|
||||
(l/derived
|
||||
(fn [{:keys [modifiers objects]}]
|
||||
(let [keys (->> modifiers
|
||||
(keys)
|
||||
(filter (fn [id]
|
||||
(let [shape (get objects id)]
|
||||
(or (= frame-id id)
|
||||
(and (= frame-id (:frame-id shape))
|
||||
(not (= :frame (:type shape)))))))))]
|
||||
(select-keys modifiers keys)))
|
||||
workspace-modifiers-with-objects
|
||||
=))
|
||||
(->> modifiers
|
||||
(reduce
|
||||
(fn [result [id modifiers]]
|
||||
(let [shape (get objects id)
|
||||
frame-id (:frame-id shape)]
|
||||
(cond
|
||||
(cph/frame-shape? shape)
|
||||
(assoc-in result [id id] modifiers)
|
||||
|
||||
(some? frame-id)
|
||||
(assoc-in result [frame-id id] modifiers)
|
||||
|
||||
:else
|
||||
result)))
|
||||
{})))
|
||||
workspace-modifiers-with-objects))
|
||||
|
||||
(defn workspace-modifiers-by-frame-id
|
||||
[frame-id]
|
||||
(l/derived #(get % frame-id) workspace-frame-modifiers =))
|
||||
|
||||
(defn select-bool-children [id]
|
||||
(l/derived (partial wsh/select-bool-children id) st/state =))
|
||||
|
|
|
@ -21,6 +21,16 @@
|
|||
[v]
|
||||
(instance? KeyboardEvent v))
|
||||
|
||||
(defn key-up?
|
||||
[v]
|
||||
(and (keyboard-event? v)
|
||||
(= :up (:type v))))
|
||||
|
||||
(defn key-down?
|
||||
[v]
|
||||
(and (keyboard-event? v)
|
||||
(= :down (:type v))))
|
||||
|
||||
(defrecord MouseEvent [type ctrl shift alt meta])
|
||||
|
||||
(defn mouse-event?
|
||||
|
|
|
@ -110,9 +110,7 @@
|
|||
:circle [:> circle-wrapper opts]
|
||||
:svg-raw [:> svg-raw-wrapper opts]
|
||||
:bool [:> bool-wrapper opts]
|
||||
|
||||
;; Only used when drawing a new frame.
|
||||
:frame [:> nested-frame-wrapper opts]
|
||||
:frame [:> nested-frame-wrapper opts]
|
||||
|
||||
nil)])))
|
||||
|
||||
|
|
|
@ -30,29 +30,16 @@
|
|||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn strip-position-data [shape]
|
||||
(-> shape
|
||||
(cond-> (some? (meta (:position-data shape)))
|
||||
(with-meta (meta (:position-data shape))))
|
||||
(dissoc :position-data)))
|
||||
|
||||
(defn fix-position [shape modifier]
|
||||
(let [shape' (gsh/transform-shape shape modifier)
|
||||
(defn fix-position [shape]
|
||||
(let [modifiers (:modifiers shape)
|
||||
shape' (gsh/transform-shape shape modifiers)
|
||||
;; We need to remove the movement because the dynamic modifiers will have move it
|
||||
deltav (gpt/to-vec (gpt/point (:selrect shape'))
|
||||
(gpt/point (:selrect shape)))]
|
||||
(-> shape
|
||||
(gsh/transform-shape (ctm/move modifier deltav))
|
||||
(mdwm/update-grow-type shape))))
|
||||
|
||||
(defn process-shape [modifiers {:keys [id] :as shape}]
|
||||
(let [modifier (dm/get-in modifiers [id :modifiers])]
|
||||
(-> shape
|
||||
(cond-> (and (some? modifier) (not (ctm/only-move? modifier)))
|
||||
(fix-position modifier))
|
||||
(cond-> (nil? (:position-data shape))
|
||||
(assoc :migrate true))
|
||||
strip-position-data)))
|
||||
(gsh/transform-shape (ctm/move modifiers deltav))
|
||||
(mdwm/update-grow-type shape)
|
||||
(dissoc :modifiers))))
|
||||
|
||||
(defn- update-with-editor-state
|
||||
"Updates the shape with the current state in the editor"
|
||||
|
@ -87,6 +74,7 @@
|
|||
(not (mth/almost-zero? height))
|
||||
(not migrate))
|
||||
(st/emit! (dwt/resize-text id width height)))))
|
||||
|
||||
(st/emit! (dwt/clean-text-modifier id))))
|
||||
|
||||
(defn- update-text-modifier
|
||||
|
@ -136,8 +124,8 @@
|
|||
(or (identical? shape other)
|
||||
(and
|
||||
;; Check if both shapes are equivalent removing their geometry data
|
||||
(= (dissoc shape :migrate :points :selrect :height :width :x :y)
|
||||
(dissoc other :migrate :points :selrect :height :width :x :y))
|
||||
(= (dissoc shape :migrate :points :selrect :height :width :x :y :position-data :modifiers)
|
||||
(dissoc other :migrate :points :selrect :height :width :x :y :position-data :modifiers))
|
||||
|
||||
;; Check if the position and size is close. If any of these changes the shape has changed
|
||||
;; and if not there is no geometry relevant change
|
||||
|
@ -146,55 +134,69 @@
|
|||
(mth/close? (:width shape) (:width other))
|
||||
(mth/close? (:height shape) (:height other)))))
|
||||
|
||||
(mf/defc viewport-texts-wrapper
|
||||
{::mf/wrap-props false
|
||||
::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
|
||||
(mf/defc text-changes-renderer
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [text-shapes (obj/get props "text-shapes")
|
||||
modifiers (obj/get props "modifiers")
|
||||
prev-modifiers (hooks/use-previous modifiers)
|
||||
prev-text-shapes (hooks/use-previous text-shapes)
|
||||
|
||||
;; A change in position-data won't be a "real" change
|
||||
text-change?
|
||||
(fn [id]
|
||||
(let [new-shape (get text-shapes id)
|
||||
old-shape (get prev-text-shapes 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))]
|
||||
(or (and (not remote?)
|
||||
|
||||
(or (and (not remote?) ;; changes caused by a remote peer are not re-calculated
|
||||
(not (text-properties-equal? old-shape new-shape)))
|
||||
|
||||
(and (not= new-modifiers old-modifiers)
|
||||
(or (ctm/empty? new-modifiers)
|
||||
(ctm/empty? old-modifiers)))
|
||||
|
||||
(and (not= new-modifiers old-modifiers)
|
||||
(or (not (ctm/only-move? new-modifiers))
|
||||
(not (ctm/only-move? old-modifiers))))
|
||||
|
||||
;; When the position data is nil we force to recalculate
|
||||
(:migrate new-shape))))
|
||||
(nil? (:position-data new-shape)))))
|
||||
|
||||
changed-texts
|
||||
(mf/use-memo
|
||||
(mf/deps text-shapes modifiers)
|
||||
(mf/deps text-shapes)
|
||||
#(->> (keys text-shapes)
|
||||
(filter text-change?)
|
||||
(map (d/getf text-shapes))))
|
||||
|
||||
handle-update-modifier (mf/use-callback update-text-modifier)
|
||||
handle-update-shape (mf/use-callback update-text-shape)]
|
||||
|
||||
[:*
|
||||
[:.text-changes-renderer
|
||||
(for [{:keys [id] :as shape} changed-texts]
|
||||
[:& text-container {:shape shape
|
||||
:on-update (if (some? (get modifiers (:id shape)))
|
||||
handle-update-modifier
|
||||
handle-update-shape)
|
||||
:key (str (dm/str "text-container-" id))}])]))
|
||||
[:& text-container {:key (str (dm/str "text-container-" id))
|
||||
:shape shape
|
||||
:on-update handle-update-shape}])]))
|
||||
|
||||
(mf/defc text-modifiers-renderer
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [text-shapes (-> (obj/get props "text-shapes")
|
||||
(update-vals fix-position))
|
||||
|
||||
prev-text-shapes (hooks/use-previous text-shapes)
|
||||
|
||||
text-change?
|
||||
(fn [id]
|
||||
(let [new-shape (get text-shapes id)
|
||||
old-shape (get prev-text-shapes id)]
|
||||
(and
|
||||
(some? new-shape)
|
||||
(some? old-shape)
|
||||
(not (text-properties-equal? old-shape new-shape)))))
|
||||
|
||||
changed-texts
|
||||
(mf/use-memo
|
||||
(mf/deps text-shapes)
|
||||
#(->> (keys text-shapes)
|
||||
(filter text-change?)
|
||||
(map (d/getf text-shapes))))
|
||||
|
||||
handle-update-shape (mf/use-callback update-text-modifier)]
|
||||
|
||||
[:.text-changes-renderer
|
||||
(for [{:keys [id] :as shape} changed-texts]
|
||||
[:& text-container {:key (str (dm/str "text-container-" id))
|
||||
:shape shape
|
||||
:on-update handle-update-shape}])]))
|
||||
|
||||
(mf/defc viewport-text-editing
|
||||
{::mf/wrap-props false}
|
||||
|
@ -256,21 +258,30 @@
|
|||
text-shapes
|
||||
(mf/use-memo
|
||||
(mf/deps objects)
|
||||
#(into {} (filter (comp cph/text-shape? second)) objects))
|
||||
(fn []
|
||||
(into {} (filter (comp cph/text-shape? second)) objects)))
|
||||
|
||||
text-shapes
|
||||
(mf/use-memo
|
||||
(mf/deps text-shapes modifiers)
|
||||
#(update-vals text-shapes (partial process-shape modifiers)))
|
||||
(hooks/use-equal-memo text-shapes)
|
||||
|
||||
editing-shape (get text-shapes edition)
|
||||
|
||||
;; This memo is necessary so the viewport-text-wrapper memoize its props correctly
|
||||
text-shapes-wrapper
|
||||
text-shapes-changes
|
||||
(mf/use-memo
|
||||
(mf/deps text-shapes edition)
|
||||
(fn []
|
||||
(dissoc text-shapes edition)))]
|
||||
(-> text-shapes
|
||||
(dissoc edition))))
|
||||
|
||||
text-shapes-modifiers
|
||||
(mf/use-memo
|
||||
(mf/deps modifiers text-shapes)
|
||||
(fn []
|
||||
(into {}
|
||||
(keep (fn [[id modifiers]]
|
||||
(when-let [shape (get text-shapes id)]
|
||||
(vector id (merge shape modifiers)))))
|
||||
modifiers)))]
|
||||
|
||||
;; We only need the effect to run on "mount" because the next fonts will be changed when the texts are
|
||||
;; edited
|
||||
|
@ -284,5 +295,5 @@
|
|||
(when editing-shape
|
||||
[:& viewport-text-editing {:shape editing-shape}])
|
||||
|
||||
[:& viewport-texts-wrapper {:text-shapes text-shapes-wrapper
|
||||
:modifiers modifiers}]]))
|
||||
[:& text-modifiers-renderer {:text-shapes text-shapes-modifiers}]
|
||||
[:& text-changes-renderer {:text-shapes text-shapes-changes}]]))
|
||||
|
|
|
@ -28,28 +28,40 @@
|
|||
has-value? (not (nil? blur))
|
||||
multiple? (= blur :multiple)
|
||||
|
||||
change! (fn [update-fn] (st/emit! (dch/update-shapes ids update-fn)))
|
||||
change!
|
||||
(mf/use-callback
|
||||
(mf/deps ids)
|
||||
(fn [update-fn]
|
||||
(st/emit! (dch/update-shapes ids update-fn))))
|
||||
|
||||
handle-add
|
||||
(fn []
|
||||
(change! #(assoc % :blur (create-blur))))
|
||||
(mf/use-callback
|
||||
(mf/deps change!)
|
||||
(fn []
|
||||
(change! #(assoc % :blur (create-blur)))))
|
||||
|
||||
handle-delete
|
||||
(fn []
|
||||
(change! #(dissoc % :blur)))
|
||||
(mf/use-callback
|
||||
(mf/deps change!)
|
||||
(fn []
|
||||
(change! #(dissoc % :blur))))
|
||||
|
||||
handle-change
|
||||
(fn [value]
|
||||
(change! #(cond-> %
|
||||
(not (contains? % :blur))
|
||||
(assoc :blur (create-blur))
|
||||
(mf/use-callback
|
||||
(mf/deps change!)
|
||||
(fn [value]
|
||||
(change! #(cond-> %
|
||||
(not (contains? % :blur))
|
||||
(assoc :blur (create-blur))
|
||||
|
||||
:always
|
||||
(assoc-in [:blur :value] value))))
|
||||
:always
|
||||
(assoc-in [:blur :value] value)))))
|
||||
|
||||
handle-toggle-visibility
|
||||
(fn []
|
||||
(change! #(update-in % [:blur :hidden] not)))]
|
||||
(mf/use-callback
|
||||
(mf/deps change!)
|
||||
(fn []
|
||||
(change! #(update-in % [:blur :hidden] not))))]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.data.workspace.modifiers :as dwm]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.context :as ctx]
|
||||
[app.main.ui.hooks :as ui-hooks]
|
||||
|
@ -40,6 +41,7 @@
|
|||
[app.main.ui.workspace.viewport.snap-distances :as snap-distances]
|
||||
[app.main.ui.workspace.viewport.snap-points :as snap-points]
|
||||
[app.main.ui.workspace.viewport.utils :as utils]
|
||||
[app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]]
|
||||
[app.main.ui.workspace.viewport.widgets :as widgets]
|
||||
[beicon.core :as rx]
|
||||
[debug :refer [debug?]]
|
||||
|
@ -47,6 +49,20 @@
|
|||
|
||||
;; --- Viewport
|
||||
|
||||
(defn apply-modifiers-to-selected
|
||||
[selected objects text-modifiers modifiers]
|
||||
(into []
|
||||
(comp
|
||||
(keep (d/getf objects))
|
||||
(map (fn [{:keys [id] :as shape}]
|
||||
(cond-> shape
|
||||
(and (cph/text-shape? shape) (contains? text-modifiers id))
|
||||
(dwm/apply-text-modifier (get text-modifiers id))
|
||||
|
||||
(contains? modifiers id)
|
||||
(gsh/transform-shape (dm/get-in modifiers [id :modifiers]))))))
|
||||
selected))
|
||||
|
||||
(mf/defc viewport
|
||||
[{:keys [wlocal wglobal selected layout file] :as props}]
|
||||
(let [;; When adding data from workspace-local revisit `app.main.ui.workspace` to check
|
||||
|
@ -79,6 +95,7 @@
|
|||
base-objects (-> objects (ui-hooks/with-focus-objects focus))
|
||||
|
||||
modifiers (mf/deref refs/workspace-modifiers)
|
||||
text-modifiers (mf/deref refs/workspace-text-modifier)
|
||||
|
||||
objects-modified (mf/with-memo [base-objects modifiers]
|
||||
(gsh/apply-objects-modifiers base-objects modifiers selected))
|
||||
|
@ -98,7 +115,8 @@
|
|||
active-frames (mf/use-state #{})
|
||||
|
||||
;; REFS
|
||||
viewport-ref (mf/use-ref nil)
|
||||
[viewport-ref
|
||||
on-viewport-ref] (create-viewport-ref)
|
||||
|
||||
;; VARS
|
||||
disable-paste (mf/use-var false)
|
||||
|
@ -118,7 +136,8 @@
|
|||
drawing-tool (:tool drawing)
|
||||
drawing-obj (:object drawing)
|
||||
|
||||
selected-shapes (into [] (keep (d/getf objects-modified)) selected)
|
||||
selected-shapes (apply-modifiers-to-selected selected base-objects text-modifiers modifiers)
|
||||
|
||||
selected-frames (into #{} (map :frame-id) selected-shapes)
|
||||
|
||||
;; Only when we have all the selected shapes in one frame
|
||||
|
@ -140,15 +159,14 @@
|
|||
on-double-click (actions/on-double-click hover hover-ids drawing-path? base-objects edition workspace-read-only?)
|
||||
on-drag-enter (actions/on-drag-enter)
|
||||
on-drag-over (actions/on-drag-over)
|
||||
on-drop (actions/on-drop file viewport-ref zoom)
|
||||
on-drop (actions/on-drop file)
|
||||
on-mouse-down (actions/on-mouse-down @hover selected edition drawing-tool text-editing? node-editing?
|
||||
drawing-path? create-comment? space? viewport-ref zoom panning
|
||||
workspace-read-only?)
|
||||
drawing-path? create-comment? space? panning workspace-read-only?)
|
||||
on-mouse-up (actions/on-mouse-up disable-paste)
|
||||
on-pointer-down (actions/on-pointer-down)
|
||||
on-pointer-enter (actions/on-pointer-enter in-viewport?)
|
||||
on-pointer-leave (actions/on-pointer-leave in-viewport?)
|
||||
on-pointer-move (actions/on-pointer-move viewport-ref zoom move-stream)
|
||||
on-pointer-move (actions/on-pointer-move move-stream)
|
||||
on-pointer-up (actions/on-pointer-up)
|
||||
on-move-selected (actions/on-move-selected hover hover-ids selected space? workspace-read-only?)
|
||||
on-menu-selected (actions/on-menu-selected hover hover-ids selected workspace-read-only?)
|
||||
|
@ -269,7 +287,7 @@
|
|||
:preserveAspectRatio "xMidYMid meet"
|
||||
:key (str "viewport" page-id)
|
||||
:view-box (utils/format-viewbox vbox)
|
||||
:ref viewport-ref
|
||||
:ref on-viewport-ref
|
||||
:class (when drawing-tool "drawing")
|
||||
:style {:cursor @cursor}
|
||||
:fill "none"
|
||||
|
@ -302,7 +320,7 @@
|
|||
outlined-frame (get objects outlined-frame-id)]
|
||||
[:*
|
||||
[:& outline/shape-outlines
|
||||
{:objects objects-modified
|
||||
{:objects base-objects
|
||||
:hover #{outlined-frame-id}
|
||||
:zoom zoom
|
||||
:modifiers modifiers}]
|
||||
|
@ -423,8 +441,7 @@
|
|||
[:& scroll-bars/viewport-scrollbars
|
||||
{:objects base-objects
|
||||
:zoom zoom
|
||||
:vbox vbox
|
||||
:viewport-ref viewport-ref}]
|
||||
:vbox vbox}]
|
||||
|
||||
(when show-rules?
|
||||
[:& rules/rules
|
||||
|
@ -443,25 +460,25 @@
|
|||
;; DEBUG LAYOUT DROP-ZONES
|
||||
(when (debug? :layout-drop-zones)
|
||||
[:& wvd/debug-drop-zones {:selected-shapes selected-shapes
|
||||
:objects objects-modified
|
||||
:objects base-objects
|
||||
:hover-top-frame-id @hover-top-frame-id
|
||||
:zoom zoom}])
|
||||
|
||||
(when (debug? :layout-content-bounds)
|
||||
[:& wvd/debug-content-bounds {:selected-shapes selected-shapes
|
||||
:objects objects-modified
|
||||
:objects base-objects
|
||||
:hover-top-frame-id @hover-top-frame-id
|
||||
:zoom zoom}])
|
||||
|
||||
(when (debug? :layout-lines)
|
||||
[:& wvd/debug-layout-lines {:selected-shapes selected-shapes
|
||||
:objects objects-modified
|
||||
:objects base-objects
|
||||
: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
|
||||
:objects base-objects
|
||||
:hover-top-frame-id @hover-top-frame-id
|
||||
:zoom zoom}])
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
[app.main.ui.workspace.viewport.utils :as utils]
|
||||
[app.main.ui.workspace.viewport.viewport-ref :as uwvv]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.dom.dnd :as dnd]
|
||||
[app.util.dom.normalize-wheel :as nw]
|
||||
|
@ -34,11 +34,11 @@
|
|||
|
||||
(defn on-mouse-down
|
||||
[{:keys [id blocked hidden type]} selected edition drawing-tool text-editing?
|
||||
node-editing? drawing-path? create-comment? space? viewport-ref zoom panning
|
||||
node-editing? drawing-path? create-comment? space? panning
|
||||
workspace-read-only?]
|
||||
(mf/use-callback
|
||||
(mf/deps id blocked hidden type selected edition drawing-tool text-editing?
|
||||
node-editing? drawing-path? create-comment? @space? viewport-ref zoom
|
||||
node-editing? drawing-path? create-comment? @space?
|
||||
panning workspace-read-only?)
|
||||
(fn [bevent]
|
||||
(when (or (dom/class? (dom/get-target bevent) "viewport-controls")
|
||||
|
@ -61,8 +61,7 @@
|
|||
(dom/prevent-default bevent)
|
||||
(if mod?
|
||||
(let [raw-pt (dom/get-client-position event)
|
||||
viewport (mf/ref-val viewport-ref)
|
||||
pt (utils/translate-point-to-viewport viewport zoom raw-pt)]
|
||||
pt (uwvv/point->viewport raw-pt)]
|
||||
(st/emit! (dw/start-zooming pt)))
|
||||
(st/emit! (dw/start-panning))))
|
||||
|
||||
|
@ -322,15 +321,12 @@
|
|||
(= "TEXTAREA" (obj/get target "tagName")))]
|
||||
(st/emit! (ms/->KeyboardEvent :up key shift? ctrl? alt? meta? editing?))))))
|
||||
|
||||
(defn on-mouse-move [viewport-ref zoom]
|
||||
(defn on-mouse-move []
|
||||
(let [last-position (mf/use-var nil)]
|
||||
(mf/use-callback
|
||||
(mf/deps zoom)
|
||||
(fn [event]
|
||||
(let [event (.getBrowserEvent ^js event)
|
||||
raw-pt (dom/get-client-position event)
|
||||
viewport (mf/ref-val viewport-ref)
|
||||
pt (utils/translate-point-to-viewport viewport zoom raw-pt)
|
||||
(let [raw-pt (dom/get-client-position event)
|
||||
pt (uwvv/point->viewport raw-pt)
|
||||
|
||||
;; We calculate the delta because Safari's MouseEvent.movementX/Y drop
|
||||
;; events
|
||||
|
@ -350,30 +346,27 @@
|
|||
(kbd/alt? event)
|
||||
(kbd/meta? event))))))))
|
||||
|
||||
(defn on-pointer-move [viewport-ref zoom move-stream]
|
||||
(defn on-pointer-move [move-stream]
|
||||
(mf/use-callback
|
||||
(mf/deps zoom move-stream)
|
||||
(mf/deps move-stream)
|
||||
(fn [event]
|
||||
(let [raw-pt (dom/get-client-position event)
|
||||
viewport (mf/ref-val viewport-ref)
|
||||
pt (utils/translate-point-to-viewport viewport zoom raw-pt)]
|
||||
pt (uwvv/point->viewport raw-pt)]
|
||||
(rx/push! move-stream pt)))))
|
||||
|
||||
(defn on-mouse-wheel [viewport-ref zoom]
|
||||
(defn on-mouse-wheel [zoom]
|
||||
(mf/use-callback
|
||||
(mf/deps zoom)
|
||||
(fn [event]
|
||||
(let [viewport (mf/ref-val viewport-ref)
|
||||
event (.getBrowserEvent ^js event)
|
||||
(let [event (.getBrowserEvent ^js event)
|
||||
target (dom/get-target event)
|
||||
mod? (kbd/mod? event)]
|
||||
|
||||
(when (dom/is-child? viewport target)
|
||||
(when (uwvv/inside-viewport? target)
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(let [pt (->> (dom/get-client-position event)
|
||||
(utils/translate-point-to-viewport viewport zoom))
|
||||
|
||||
(let [raw-pt (dom/get-client-position event)
|
||||
pt (uwvv/point->viewport raw-pt)
|
||||
norm-event ^js (nw/normalize-wheel event)
|
||||
ctrl? (kbd/ctrl? event)
|
||||
delta-y (.-pixelY norm-event)
|
||||
|
@ -413,14 +406,12 @@
|
|||
(dom/prevent-default e)))))
|
||||
|
||||
(defn on-drop
|
||||
[file viewport-ref zoom]
|
||||
[file]
|
||||
(mf/use-fn
|
||||
(mf/deps zoom)
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(let [point (gpt/point (.-clientX event) (.-clientY event))
|
||||
viewport (mf/ref-val viewport-ref)
|
||||
viewport-coord (utils/translate-point-to-viewport viewport zoom point)
|
||||
viewport-coord (uwvv/point->viewport point)
|
||||
asset-id (-> (dnd/get-data event "text/asset-id") uuid/uuid)
|
||||
asset-name (dnd/get-data event "text/asset-name")
|
||||
asset-type (dnd/get-data event "text/asset-type")]
|
||||
|
|
|
@ -35,21 +35,29 @@
|
|||
(defn setup-dom-events [viewport-ref zoom disable-paste in-viewport? workspace-read-only?]
|
||||
(let [on-key-down (actions/on-key-down)
|
||||
on-key-up (actions/on-key-up)
|
||||
on-mouse-move (actions/on-mouse-move viewport-ref zoom)
|
||||
on-mouse-wheel (actions/on-mouse-wheel viewport-ref zoom)
|
||||
on-mouse-move (actions/on-mouse-move)
|
||||
on-mouse-wheel (actions/on-mouse-wheel zoom)
|
||||
on-paste (actions/on-paste disable-paste in-viewport? workspace-read-only?)]
|
||||
|
||||
;; We use the DOM listener because the goog.closure one forces reflow to generate its internal
|
||||
;; structure. As we don't need currently nothing from BrowserEvent we optimize by using the basic event
|
||||
(mf/use-layout-effect
|
||||
(mf/deps on-mouse-move)
|
||||
(fn []
|
||||
(let [node (mf/ref-val viewport-ref)]
|
||||
(.addEventListener node "mousemove" on-mouse-move)
|
||||
(fn []
|
||||
(.removeEventListener node "mousemove" on-mouse-move)))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps on-key-down on-key-up on-mouse-move on-mouse-wheel on-paste workspace-read-only?)
|
||||
(fn []
|
||||
(let [node (mf/ref-val viewport-ref)
|
||||
keys [(events/listen js/document EventType.KEYDOWN on-key-down)
|
||||
(let [keys [(events/listen js/document EventType.KEYDOWN on-key-down)
|
||||
(events/listen js/document EventType.KEYUP on-key-up)
|
||||
(events/listen node EventType.MOUSEMOVE on-mouse-move)
|
||||
;; bind with passive=false to allow the event to be cancelled
|
||||
;; https://stackoverflow.com/a/57582286/3219895
|
||||
(events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
|
||||
(events/listen js/window EventType.PASTE on-paste)]]
|
||||
|
||||
(fn []
|
||||
(doseq [key keys]
|
||||
(events/unlistenByKey key))))))))
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[app.common.pages.helpers :as cph]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.workspace.viewport.utils :as utils]
|
||||
[app.main.ui.workspace.viewport.viewport-ref :refer [point->viewport]]
|
||||
[app.util.dom :as dom]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
|||
|
||||
(mf/defc viewport-scrollbars
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [objects viewport-ref zoom vbox]}]
|
||||
[{:keys [objects zoom vbox]}]
|
||||
|
||||
(let [v-scrolling? (mf/use-state false)
|
||||
h-scrolling? (mf/use-state false)
|
||||
|
@ -126,10 +126,9 @@
|
|||
on-mouse-move
|
||||
(fn [event axis]
|
||||
(when-let [_ (or @v-scrolling? @h-scrolling?)]
|
||||
(let [viewport (mf/ref-val viewport-ref)
|
||||
start-pt (mf/ref-val start-ref)
|
||||
(let [start-pt (mf/ref-val start-ref)
|
||||
current-pt (dom/get-client-position event)
|
||||
current-pt-viewport (utils/translate-point-to-viewport viewport zoom current-pt)
|
||||
current-pt-viewport (point->viewport current-pt)
|
||||
y-delta (/ (* (mf/ref-val height-factor-ref) (- (:y current-pt) (:y start-pt))) zoom)
|
||||
x-delta (/ (* (mf/ref-val width-factor-ref) (- (:x current-pt) (:x start-pt))) zoom)
|
||||
new-v-scrollbar-y (-> current-pt-viewport
|
||||
|
@ -150,9 +149,8 @@
|
|||
|
||||
on-mouse-down
|
||||
(fn [event axis]
|
||||
(let [viewport (mf/ref-val viewport-ref)
|
||||
start-pt (dom/get-client-position event)
|
||||
viewport-point (utils/translate-point-to-viewport viewport zoom start-pt)
|
||||
(let [start-pt (dom/get-client-position event)
|
||||
viewport-point (point->viewport start-pt)
|
||||
new-h-scrollbar-x (:x viewport-point)
|
||||
new-v-scrollbar-y (:y viewport-point)
|
||||
v-scrollbar-y-padding (- v-scrollbar-y new-v-scrollbar-y)
|
||||
|
|
|
@ -6,13 +6,11 @@
|
|||
|
||||
(ns app.main.ui.workspace.viewport.utils
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.main.ui.cursors :as cur]
|
||||
[app.main.ui.formats :refer [format-number]]
|
||||
[app.util.dom :as dom]))
|
||||
[app.main.ui.formats :refer [format-number]]))
|
||||
|
||||
(defn format-viewbox [vbox]
|
||||
(dm/str (format-number(:x vbox 0)) " "
|
||||
|
@ -20,17 +18,6 @@
|
|||
(format-number (:width vbox 0)) " "
|
||||
(format-number (:height vbox 0))))
|
||||
|
||||
(defn translate-point-to-viewport [viewport zoom pt]
|
||||
(let [vbox (.. ^js viewport -viewBox -baseVal)
|
||||
brect (dom/get-bounding-rect viewport)
|
||||
brect (gpt/point (d/parse-integer (:left brect))
|
||||
(d/parse-integer (:top brect)))
|
||||
box (gpt/point (.-x vbox) (.-y vbox))
|
||||
zoom (gpt/point zoom)]
|
||||
(-> (gpt/subtract pt brect)
|
||||
(gpt/divide zoom)
|
||||
(gpt/add box))))
|
||||
|
||||
(defn get-cursor [cursor]
|
||||
(case cursor
|
||||
:hand cur/hand
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.workspace.viewport.viewport-ref
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.main.store :as st]
|
||||
[app.util.dom :as dom]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defonce viewport-ref (atom nil))
|
||||
(defonce current-observer (atom nil))
|
||||
(defonce viewport-brect (atom nil))
|
||||
|
||||
(defn init-observer
|
||||
[node on-change-bounds]
|
||||
|
||||
(let [observer (js/ResizeObserver. on-change-bounds)]
|
||||
(when (some? @current-observer)
|
||||
(.disconnect @current-observer))
|
||||
|
||||
(reset! current-observer observer)
|
||||
|
||||
(when (some? node)
|
||||
(.observe observer node))))
|
||||
|
||||
(defn on-change-bounds
|
||||
[_]
|
||||
(when @viewport-ref
|
||||
(let [brect (dom/get-bounding-rect @viewport-ref)
|
||||
brect (gpt/point (d/parse-integer (:left brect))
|
||||
(d/parse-integer (:top brect)))]
|
||||
(reset! viewport-brect brect))))
|
||||
|
||||
(defn create-viewport-ref
|
||||
[]
|
||||
|
||||
(let [ref (mf/use-ref nil)]
|
||||
[ref
|
||||
(mf/use-memo
|
||||
#(fn [node]
|
||||
(mf/set-ref-val! ref node)
|
||||
(reset! viewport-ref node)
|
||||
(init-observer node on-change-bounds)))]))
|
||||
|
||||
(defn point->viewport
|
||||
[pt]
|
||||
(let [zoom (dm/get-in @st/state [:workspace-local :zoom])]
|
||||
(when (some? @viewport-ref)
|
||||
(let [vbox (.. ^js @viewport-ref -viewBox -baseVal)
|
||||
brect @viewport-brect
|
||||
box (gpt/point (.-x vbox) (.-y vbox))
|
||||
zoom (gpt/point zoom)]
|
||||
(-> (gpt/subtract pt brect)
|
||||
(gpt/divide zoom)
|
||||
(gpt/add box))))))
|
||||
|
||||
(defn inside-viewport?
|
||||
[target]
|
||||
(dom/is-child? @viewport-ref target))
|
|
@ -890,8 +890,7 @@
|
|||
(defn calculate-ratio
|
||||
;; sqrt((actual-width)**2 + (actual-height)**2)/sqrt(2).
|
||||
[width height]
|
||||
(/ (mth/sqrt (+ (mth/pow width 2)
|
||||
(mth/pow height 2)))
|
||||
(/ (mth/hypot width height)
|
||||
(mth/sqrt 2)))
|
||||
|
||||
(defn fix-percents
|
||||
|
|
|
@ -63,7 +63,8 @@
|
|||
[shape-id]
|
||||
|
||||
(when (some? shape-id)
|
||||
(let [text-nodes (dom/query-all (dm/str "#html-text-node-" shape-id " .text-node"))
|
||||
(let [text-nodes (-> (dom/query (dm/fmt "#html-text-node-%" shape-id))
|
||||
(dom/query-all ".text-node"))
|
||||
load-fonts (->> text-nodes (map resolve-font))
|
||||
|
||||
process-text-node
|
||||
|
|
Loading…
Add table
Reference in a new issue