mirror of
https://github.com/penpot/penpot.git
synced 2025-05-19 14:56:14 +02:00
🐛 Fix problems with thumbnails
This commit is contained in:
parent
f2bb59fd77
commit
c14ece9f8d
7 changed files with 271 additions and 250 deletions
|
@ -153,7 +153,8 @@
|
||||||
(ptk/reify ::duplicate-thumbnail
|
(ptk/reify ::duplicate-thumbnail
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [old-shape-thumbnail (get-in state [:workspace-file :thumbnails old-id])]
|
(let [page-id (get state :current-page-id)
|
||||||
(-> state (assoc-in [:workspace-file :thumbnails new-id] old-shape-thumbnail))))))
|
old-shape-thumbnail (get-in state [:workspace-file :thumbnails (dm/str page-id old-id)])]
|
||||||
|
(-> state (assoc-in [:workspace-file :thumbnails (dm/str page-id new-id)] old-shape-thumbnail))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,17 +55,26 @@
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height
|
||||||
:className "frame-background"}))
|
:className "frame-background"}))
|
||||||
path? (some? (.-d props))]
|
path? (some? (.-d props))
|
||||||
|
render-id (mf/use-ctx muc/render-ctx)]
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:image.frame-thumbnail
|
[:g {:clip-path (frame-clip-url shape render-id)}
|
||||||
{:id (dm/str "thumbnail-" (:id shape))
|
[:& frame-clip-def {:shape shape :render-id render-id}]
|
||||||
:xlinkHref (:thumbnail shape)
|
[:& shape-fills {:shape shape}
|
||||||
:x (:x shape)
|
(if path?
|
||||||
:y (:y shape)
|
[:> :path props]
|
||||||
:width (:width shape)
|
[:> :rect props])]
|
||||||
:height (:height shape)
|
|
||||||
;; DEBUG
|
[:image.frame-thumbnail
|
||||||
:style {:filter (when (debug? :thumbnails) "sepia(1)")}}]
|
{:id (dm/str "thumbnail-" (:id shape))
|
||||||
|
:xlinkHref (:thumbnail shape)
|
||||||
|
:x (:x shape)
|
||||||
|
:y (:y shape)
|
||||||
|
:width (:width shape)
|
||||||
|
:height (:height shape)
|
||||||
|
;; DEBUG
|
||||||
|
:style {:filter (when (debug? :thumbnails) "sepia(1)")}}]]
|
||||||
|
|
||||||
[:& shape-strokes {:shape shape}
|
[:& shape-strokes {:shape shape}
|
||||||
(if path?
|
(if path?
|
||||||
|
@ -96,16 +105,16 @@
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:g {:clip-path (frame-clip-url shape render-id)}
|
[:g {:clip-path (frame-clip-url shape render-id)}
|
||||||
[:*
|
[:& shape-fills {:shape shape}
|
||||||
[:& shape-fills {:shape shape}
|
(if path?
|
||||||
(if path?
|
[:> :path props]
|
||||||
[:> :path props]
|
[:> :rect props])]
|
||||||
[:> :rect props])]
|
|
||||||
|
|
||||||
|
[:g.frame-children
|
||||||
(for [item childs]
|
(for [item childs]
|
||||||
[:& shape-wrapper {:shape item
|
[:& shape-wrapper {:shape item
|
||||||
:key (dm/str (:id item))}])
|
:key (dm/str (:id item))}])]]
|
||||||
]]
|
|
||||||
[:& shape-strokes {:shape shape}
|
[:& shape-strokes {:shape shape}
|
||||||
(if path?
|
(if path?
|
||||||
[:> :path props]
|
[:> :path props]
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.thumbnails :as dwt]
|
[app.main.data.workspace.thumbnails :as dwt]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
thumbnail? (unchecked-get props "thumbnail?")
|
thumbnail? (unchecked-get props "thumbnail?")
|
||||||
objects (unchecked-get props "objects")
|
objects (unchecked-get props "objects")
|
||||||
|
|
||||||
|
render-id (mf/use-memo #(str (uuid/next)))
|
||||||
fonts (mf/use-memo (mf/deps shape objects) #(ff/shape->fonts shape objects))
|
fonts (mf/use-memo (mf/deps shape objects) #(ff/shape->fonts shape objects))
|
||||||
fonts (-> fonts (hooks/use-equal-memo))
|
fonts (-> fonts (hooks/use-equal-memo))
|
||||||
|
|
||||||
|
@ -73,7 +75,7 @@
|
||||||
thumbnail-data-ref (mf/use-memo (mf/deps page-id frame-id) #(refs/thumbnail-frame-data page-id frame-id))
|
thumbnail-data-ref (mf/use-memo (mf/deps page-id frame-id) #(refs/thumbnail-frame-data page-id frame-id))
|
||||||
thumbnail-data (mf/deref thumbnail-data-ref)
|
thumbnail-data (mf/deref thumbnail-data-ref)
|
||||||
|
|
||||||
thumbnail? (and thumbnail? (or (some? (:thumbnail shape)) (some? thumbnail-data)))
|
thumbnail? (and thumbnail? (some? thumbnail-data))
|
||||||
|
|
||||||
;; References to the current rendered node and the its parentn
|
;; References to the current rendered node and the its parentn
|
||||||
node-ref (mf/use-var nil)
|
node-ref (mf/use-var nil)
|
||||||
|
@ -117,11 +119,12 @@
|
||||||
@node-ref)
|
@node-ref)
|
||||||
(when (not @rendered?) (reset! rendered? true)))))
|
(when (not @rendered?) (reset! rendered? true)))))
|
||||||
|
|
||||||
[:g.frame-container {:key "frame-container" :ref on-frame-load}
|
[:& (mf/provider ctx/render-ctx) {:value render-id}
|
||||||
[:g.frame-thumbnail {:id (dm/str "thumbnail-container-" (:id shape))}
|
[:g.frame-container {:key "frame-container" :ref on-frame-load}
|
||||||
[:> frame/frame-thumbnail {:key (dm/str (:id shape))
|
[:g.frame-thumbnail-wrapper {:id (dm/str "thumbnail-container-" (:id shape))}
|
||||||
:shape (cond-> shape
|
[:> frame/frame-thumbnail {:key (dm/str (:id shape))
|
||||||
(some? thumbnail-data)
|
:shape (cond-> shape
|
||||||
(assoc :thumbnail thumbnail-data))}]
|
(some? thumbnail-data)
|
||||||
|
(assoc :thumbnail thumbnail-data))}]
|
||||||
|
|
||||||
thumb-renderer]]))))
|
thumb-renderer]]]))))
|
||||||
|
|
|
@ -7,10 +7,223 @@
|
||||||
(ns app.main.ui.workspace.shapes.frame.dynamic-modifiers
|
(ns app.main.ui.workspace.shapes.frame.dynamic-modifiers
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[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 :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.main.ui.workspace.viewport.utils :as utils]
|
[app.util.dom :as dom]
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
|
(defn- transform-no-resize
|
||||||
|
"If we apply a scale directly to the texts it will show deformed so we need to create this
|
||||||
|
correction matrix to \"undo\" the resize but keep the other transformations."
|
||||||
|
[{:keys [x y width height points transform transform-inverse] :as shape} current-transform modifiers]
|
||||||
|
|
||||||
|
(let [corner-pt (first points)
|
||||||
|
corner-pt (cond-> corner-pt (some? transform-inverse) (gpt/transform transform-inverse))
|
||||||
|
|
||||||
|
resize-x? (some? (:resize-vector modifiers))
|
||||||
|
resize-y? (some? (:resize-vector-2 modifiers))
|
||||||
|
|
||||||
|
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
|
||||||
|
flip-y? (or (neg? (get-in modifiers [:resize-vector :y]))
|
||||||
|
(neg? (get-in modifiers [:resize-vector-2 :y])))
|
||||||
|
|
||||||
|
result (cond-> (gmt/matrix)
|
||||||
|
(and (some? transform) (or resize-x? resize-y?))
|
||||||
|
(gmt/multiply transform)
|
||||||
|
|
||||||
|
resize-x?
|
||||||
|
(gmt/scale (gpt/inverse (:resize-vector modifiers)) corner-pt)
|
||||||
|
|
||||||
|
resize-y?
|
||||||
|
(gmt/scale (gpt/inverse (:resize-vector-2 modifiers)) corner-pt)
|
||||||
|
|
||||||
|
flip-x?
|
||||||
|
(gmt/scale (gpt/point -1 1) corner-pt)
|
||||||
|
|
||||||
|
flip-y?
|
||||||
|
(gmt/scale (gpt/point 1 -1) corner-pt)
|
||||||
|
|
||||||
|
(and (some? transform) (or resize-x? resize-y?))
|
||||||
|
(gmt/multiply transform-inverse))
|
||||||
|
|
||||||
|
[width height]
|
||||||
|
(if (or resize-x? resize-y?)
|
||||||
|
(let [pc (cond-> (gpt/point x y)
|
||||||
|
(some? transform)
|
||||||
|
(gpt/transform transform)
|
||||||
|
|
||||||
|
(some? current-transform)
|
||||||
|
(gpt/transform current-transform))
|
||||||
|
|
||||||
|
pw (cond-> (gpt/point (+ x width) y)
|
||||||
|
(some? transform)
|
||||||
|
(gpt/transform transform)
|
||||||
|
|
||||||
|
(some? current-transform)
|
||||||
|
(gpt/transform current-transform))
|
||||||
|
|
||||||
|
ph (cond-> (gpt/point x (+ y height))
|
||||||
|
(some? transform)
|
||||||
|
(gpt/transform transform)
|
||||||
|
|
||||||
|
(some? current-transform)
|
||||||
|
(gpt/transform current-transform))]
|
||||||
|
[(gpt/distance pc pw) (gpt/distance pc ph)])
|
||||||
|
[width height])]
|
||||||
|
|
||||||
|
[result width height]))
|
||||||
|
|
||||||
|
(defn get-nodes
|
||||||
|
"Retrieve the DOM nodes to apply the matrix transformation"
|
||||||
|
[base-node {:keys [id type masked-group?]}]
|
||||||
|
(let [shape-node (dom/query base-node (str "#shape-" id))
|
||||||
|
|
||||||
|
frame? (= :frame type)
|
||||||
|
group? (= :group type)
|
||||||
|
text? (= :text type)
|
||||||
|
mask? (and group? masked-group?)]
|
||||||
|
|
||||||
|
(cond
|
||||||
|
frame?
|
||||||
|
[shape-node
|
||||||
|
(dom/query shape-node ".frame-children")
|
||||||
|
(dom/query (str "#thumbnail-container-" id))
|
||||||
|
(dom/query (str "#thumbnail-" id))]
|
||||||
|
|
||||||
|
;; For groups we don't want to transform the whole group but only
|
||||||
|
;; its filters/masks
|
||||||
|
mask?
|
||||||
|
[(dom/query shape-node ".mask-clip-path")
|
||||||
|
(dom/query shape-node ".mask-shape")]
|
||||||
|
|
||||||
|
group?
|
||||||
|
(let [shape-defs (dom/query shape-node "defs")]
|
||||||
|
(d/concat-vec
|
||||||
|
(dom/query-all shape-defs ".svg-def")
|
||||||
|
(dom/query-all shape-defs ".svg-mask-wrapper")))
|
||||||
|
|
||||||
|
text?
|
||||||
|
[shape-node
|
||||||
|
(dom/query shape-node ".text-shape")]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[shape-node])))
|
||||||
|
|
||||||
|
(defn transform-region!
|
||||||
|
[node modifiers]
|
||||||
|
|
||||||
|
(let [{:keys [x y width height]}
|
||||||
|
(-> (gsh/make-selrect
|
||||||
|
(-> (dom/get-attribute node "data-old-x") d/parse-double)
|
||||||
|
(-> (dom/get-attribute node "data-old-y") d/parse-double)
|
||||||
|
(-> (dom/get-attribute node "data-old-width") d/parse-double)
|
||||||
|
(-> (dom/get-attribute node "data-old-height") d/parse-double))
|
||||||
|
(gsh/transform-selrect modifiers))]
|
||||||
|
(dom/set-attribute! node "x" x)
|
||||||
|
(dom/set-attribute! node "y" y)
|
||||||
|
(dom/set-attribute! node "width" width)
|
||||||
|
(dom/set-attribute! node "height" height)))
|
||||||
|
|
||||||
|
(defn start-transform!
|
||||||
|
[base-node shapes]
|
||||||
|
(doseq [shape shapes]
|
||||||
|
(when-let [nodes (get-nodes base-node shape)]
|
||||||
|
(doseq [node nodes]
|
||||||
|
(let [old-transform (dom/get-attribute node "transform")]
|
||||||
|
(when (some? old-transform)
|
||||||
|
(dom/set-attribute! node "data-old-transform" old-transform))
|
||||||
|
|
||||||
|
(when (or (= (dom/get-tag-name node) "linearGradient")
|
||||||
|
(= (dom/get-tag-name node) "radialGradient"))
|
||||||
|
(let [gradient-transform (dom/get-attribute node "gradientTransform")]
|
||||||
|
(when (some? gradient-transform)
|
||||||
|
(dom/set-attribute! node "data-old-gradientTransform" gradient-transform))))
|
||||||
|
|
||||||
|
(when (= (dom/get-tag-name node) "pattern")
|
||||||
|
(let [pattern-transform (dom/get-attribute node "patternTransform")]
|
||||||
|
(when (some? pattern-transform)
|
||||||
|
(dom/set-attribute! node "data-old-patternTransform" pattern-transform))))
|
||||||
|
|
||||||
|
(when (or (= (dom/get-tag-name node) "mask")
|
||||||
|
(= (dom/get-tag-name node) "filter"))
|
||||||
|
(let [old-x (dom/get-attribute node "x")
|
||||||
|
old-y (dom/get-attribute node "y")
|
||||||
|
old-width (dom/get-attribute node "width")
|
||||||
|
old-height (dom/get-attribute node "height")]
|
||||||
|
(dom/set-attribute! node "data-old-x" old-x)
|
||||||
|
(dom/set-attribute! node "data-old-y" old-y)
|
||||||
|
(dom/set-attribute! node "data-old-width" old-width)
|
||||||
|
(dom/set-attribute! node "data-old-height" old-height))))))))
|
||||||
|
|
||||||
|
(defn set-transform-att!
|
||||||
|
[node att value]
|
||||||
|
|
||||||
|
(let [old-att (dom/get-attribute node (dm/str "data-old-" att))
|
||||||
|
new-value (if (some? old-att)
|
||||||
|
(dm/str value " " old-att)
|
||||||
|
(str value))]
|
||||||
|
(dom/set-attribute! node att (str new-value))))
|
||||||
|
|
||||||
|
(defn update-transform!
|
||||||
|
[base-node shapes transforms modifiers]
|
||||||
|
(doseq [{:keys [id] :as shape} shapes]
|
||||||
|
(when-let [nodes (get-nodes base-node shape)]
|
||||||
|
(let [transform (get transforms id)
|
||||||
|
modifiers (get-in modifiers [id :modifiers])]
|
||||||
|
|
||||||
|
(doseq [node nodes]
|
||||||
|
(cond
|
||||||
|
;; Text shapes need special treatment because their resize only change
|
||||||
|
;; the text area, not the change size/position
|
||||||
|
(or (dom/class? node "text-shape")
|
||||||
|
(dom/class? node "frame-thumbnail"))
|
||||||
|
(let [[transform] (transform-no-resize shape transform modifiers)]
|
||||||
|
(set-transform-att! node "transform" transform))
|
||||||
|
|
||||||
|
(dom/class? node "frame-children")
|
||||||
|
(set-transform-att! node "transform" (gmt/inverse transform))
|
||||||
|
|
||||||
|
(or (= (dom/get-tag-name node) "mask")
|
||||||
|
(= (dom/get-tag-name node) "filter"))
|
||||||
|
(transform-region! node modifiers)
|
||||||
|
|
||||||
|
(or (= (dom/get-tag-name node) "linearGradient")
|
||||||
|
(= (dom/get-tag-name node) "radialGradient"))
|
||||||
|
(set-transform-att! node "gradientTransform" transform)
|
||||||
|
|
||||||
|
(= (dom/get-tag-name node) "pattern")
|
||||||
|
(set-transform-att! node "patternTransform" transform)
|
||||||
|
|
||||||
|
(and (some? transform) (some? node))
|
||||||
|
(set-transform-att! node "transform" transform)))))))
|
||||||
|
|
||||||
|
(defn remove-transform!
|
||||||
|
[base-node shapes]
|
||||||
|
(doseq [shape shapes]
|
||||||
|
(when-let [nodes (get-nodes base-node shape)]
|
||||||
|
(doseq [node nodes]
|
||||||
|
(when (some? node)
|
||||||
|
(cond
|
||||||
|
(= (dom/get-tag-name node) "foreignObject")
|
||||||
|
;; The shape width/height will be automaticaly setup when the modifiers are applied
|
||||||
|
nil
|
||||||
|
|
||||||
|
(or (= (dom/get-tag-name node) "mask")
|
||||||
|
(= (dom/get-tag-name node) "filter"))
|
||||||
|
(do
|
||||||
|
(dom/remove-attribute! node "data-old-x")
|
||||||
|
(dom/remove-attribute! node "data-old-y")
|
||||||
|
(dom/remove-attribute! node "data-old-width")
|
||||||
|
(dom/remove-attribute! node "data-old-height"))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(let [old-transform (dom/get-attribute node "data-old-transform")]
|
||||||
|
(if (some? old-transform)
|
||||||
|
(dom/remove-attribute! node "data-old-transform")
|
||||||
|
(dom/remove-attribute! node "transform")))))))))
|
||||||
|
|
||||||
(defn use-dynamic-modifiers
|
(defn use-dynamic-modifiers
|
||||||
[objects node modifiers]
|
[objects node modifiers]
|
||||||
|
|
||||||
|
@ -42,13 +255,13 @@
|
||||||
is-cur-val? (d/not-empty? modifiers)]
|
is-cur-val? (d/not-empty? modifiers)]
|
||||||
|
|
||||||
(when (and (not is-prev-val?) is-cur-val?)
|
(when (and (not is-prev-val?) is-cur-val?)
|
||||||
(utils/start-transform! node shapes))
|
(start-transform! node shapes))
|
||||||
|
|
||||||
(when is-cur-val?
|
(when is-cur-val?
|
||||||
(utils/update-transform! node shapes transforms modifiers))
|
(update-transform! node shapes transforms modifiers))
|
||||||
|
|
||||||
(when (and is-prev-val? (not is-cur-val?))
|
(when (and is-prev-val? (not is-cur-val?))
|
||||||
(utils/remove-transform! node @prev-shapes))
|
(remove-transform! node @prev-shapes))
|
||||||
|
|
||||||
(reset! prev-modifiers modifiers)
|
(reset! prev-modifiers modifiers)
|
||||||
(reset! prev-transforms transforms)
|
(reset! prev-transforms transforms)
|
||||||
|
|
|
@ -183,7 +183,7 @@
|
||||||
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover hover-ids @hover-disabled? focus zoom)
|
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover hover-ids @hover-disabled? focus zoom)
|
||||||
(hooks/setup-viewport-modifiers modifiers base-objects)
|
(hooks/setup-viewport-modifiers modifiers base-objects)
|
||||||
(hooks/setup-shortcuts node-editing? drawing-path?)
|
(hooks/setup-shortcuts node-editing? drawing-path?)
|
||||||
(hooks/setup-active-frames base-objects hover-ids selected active-frames zoom)
|
(hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform)
|
||||||
|
|
||||||
[:div.viewport
|
[:div.viewport
|
||||||
[:div.viewport-overlays {:ref overlays-ref}
|
[:div.viewport-overlays {:ref overlays-ref}
|
||||||
|
|
|
@ -219,20 +219,29 @@
|
||||||
(gsh/overlaps? frame vbox))))
|
(gsh/overlaps? frame vbox))))
|
||||||
|
|
||||||
(defn setup-active-frames
|
(defn setup-active-frames
|
||||||
[objects hover-ids selected active-frames zoom]
|
[objects hover-ids selected active-frames zoom transform]
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(mf/deps objects @hover-ids selected zoom)
|
(mf/deps objects @hover-ids selected zoom transform)
|
||||||
(fn []
|
(fn []
|
||||||
(when (some? @hover-ids)
|
(when (some? @hover-ids)
|
||||||
(let [hover-frame (when (> zoom 0.25) (last @hover-ids))
|
(let [hover-frame (when (> zoom 0.25) (last @hover-ids))
|
||||||
new-active-frames (if (some? hover-frame) #{hover-frame} #{})
|
new-active-frames (if (some? hover-frame) #{hover-frame} #{})
|
||||||
|
|
||||||
|
frame? #(= :frame (get-in objects [% :type]))
|
||||||
|
|
||||||
|
selected-frames (->> selected (filter frame?))
|
||||||
|
new-active-frames
|
||||||
|
(cond-> new-active-frames
|
||||||
|
(and (not= transform :move) (= (count selected-frames) 1))
|
||||||
|
(conj new-active-frames (first selected-frames)))
|
||||||
|
|
||||||
new-active-frames
|
new-active-frames
|
||||||
(into new-active-frames
|
(into new-active-frames
|
||||||
(comp
|
(comp
|
||||||
(filter #(not= :frame (get-in objects [% :type])))
|
(remove frame?)
|
||||||
(map #(get-in objects [% :frame-id])))
|
(map #(get-in objects [% :frame-id])))
|
||||||
selected) ]
|
selected)]
|
||||||
(reset! active-frames new-active-frames))))))
|
(reset! active-frames new-active-frames))))))
|
||||||
|
|
||||||
;; NOTE: this is executed on each page change, maybe we need to move
|
;; NOTE: this is executed on each page change, maybe we need to move
|
||||||
|
|
|
@ -8,224 +8,10 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.matrix :as gmt]
|
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
|
||||||
[app.main.ui.cursors :as cur]
|
[app.main.ui.cursors :as cur]
|
||||||
[app.util.dom :as dom]))
|
[app.util.dom :as dom]))
|
||||||
|
|
||||||
(defn- text-corrected-transform
|
|
||||||
"If we apply a scale directly to the texts it will show deformed so we need to create this
|
|
||||||
correction matrix to \"undo\" the resize but keep the other transformations."
|
|
||||||
[{:keys [x y width height points transform transform-inverse] :as shape} current-transform modifiers]
|
|
||||||
|
|
||||||
(let [corner-pt (first points)
|
|
||||||
corner-pt (cond-> corner-pt (some? transform-inverse) (gpt/transform transform-inverse))
|
|
||||||
|
|
||||||
resize-x? (some? (:resize-vector modifiers))
|
|
||||||
resize-y? (some? (:resize-vector-2 modifiers))
|
|
||||||
|
|
||||||
flip-x? (neg? (get-in modifiers [:resize-vector :x]))
|
|
||||||
flip-y? (or (neg? (get-in modifiers [:resize-vector :y]))
|
|
||||||
(neg? (get-in modifiers [:resize-vector-2 :y])))
|
|
||||||
|
|
||||||
result (cond-> (gmt/matrix)
|
|
||||||
(and (some? transform) (or resize-x? resize-y?))
|
|
||||||
(gmt/multiply transform)
|
|
||||||
|
|
||||||
resize-x?
|
|
||||||
(gmt/scale (gpt/inverse (:resize-vector modifiers)) corner-pt)
|
|
||||||
|
|
||||||
resize-y?
|
|
||||||
(gmt/scale (gpt/inverse (:resize-vector-2 modifiers)) corner-pt)
|
|
||||||
|
|
||||||
flip-x?
|
|
||||||
(gmt/scale (gpt/point -1 1) corner-pt)
|
|
||||||
|
|
||||||
flip-y?
|
|
||||||
(gmt/scale (gpt/point 1 -1) corner-pt)
|
|
||||||
|
|
||||||
(and (some? transform) (or resize-x? resize-y?))
|
|
||||||
(gmt/multiply transform-inverse))
|
|
||||||
|
|
||||||
[width height]
|
|
||||||
(if (or resize-x? resize-y?)
|
|
||||||
(let [pc (cond-> (gpt/point x y)
|
|
||||||
(some? transform)
|
|
||||||
(gpt/transform transform)
|
|
||||||
|
|
||||||
(some? current-transform)
|
|
||||||
(gpt/transform current-transform))
|
|
||||||
|
|
||||||
pw (cond-> (gpt/point (+ x width) y)
|
|
||||||
(some? transform)
|
|
||||||
(gpt/transform transform)
|
|
||||||
|
|
||||||
(some? current-transform)
|
|
||||||
(gpt/transform current-transform))
|
|
||||||
|
|
||||||
ph (cond-> (gpt/point x (+ y height))
|
|
||||||
(some? transform)
|
|
||||||
(gpt/transform transform)
|
|
||||||
|
|
||||||
(some? current-transform)
|
|
||||||
(gpt/transform current-transform))]
|
|
||||||
[(gpt/distance pc pw) (gpt/distance pc ph)])
|
|
||||||
[width height])]
|
|
||||||
|
|
||||||
[result width height]))
|
|
||||||
|
|
||||||
(defn get-nodes
|
|
||||||
"Retrieve the DOM nodes to apply the matrix transformation"
|
|
||||||
[base-node {:keys [id type masked-group?]}]
|
|
||||||
(let [shape-node (dom/query base-node (str "#shape-" id))
|
|
||||||
|
|
||||||
frame? (= :frame type)
|
|
||||||
group? (= :group type)
|
|
||||||
text? (= :text type)
|
|
||||||
mask? (and group? masked-group?)
|
|
||||||
|
|
||||||
;; When the shape is a frame we maybe need to move its thumbnail
|
|
||||||
thumb-node (when frame? (dom/query (str "#thumbnail-container-" id)))]
|
|
||||||
|
|
||||||
(cond
|
|
||||||
frame?
|
|
||||||
[thumb-node
|
|
||||||
(dom/get-parent (dom/query shape-node ".frame-background"))
|
|
||||||
(dom/query shape-node ".frame-clip")]
|
|
||||||
|
|
||||||
;; For groups we don't want to transform the whole group but only
|
|
||||||
;; its filters/masks
|
|
||||||
mask?
|
|
||||||
[(dom/query shape-node ".mask-clip-path")
|
|
||||||
(dom/query shape-node ".mask-shape")]
|
|
||||||
|
|
||||||
group?
|
|
||||||
(let [shape-defs (dom/query shape-node "defs")]
|
|
||||||
(d/concat-vec
|
|
||||||
(dom/query-all shape-defs ".svg-def")
|
|
||||||
(dom/query-all shape-defs ".svg-mask-wrapper")))
|
|
||||||
|
|
||||||
text?
|
|
||||||
[shape-node
|
|
||||||
(dom/query shape-node ".text-shape")]
|
|
||||||
|
|
||||||
:else
|
|
||||||
[shape-node])))
|
|
||||||
|
|
||||||
(defn transform-region!
|
|
||||||
[node modifiers]
|
|
||||||
|
|
||||||
(let [{:keys [x y width height]}
|
|
||||||
(-> (gsh/make-selrect
|
|
||||||
(-> (dom/get-attribute node "data-old-x") d/parse-double)
|
|
||||||
(-> (dom/get-attribute node "data-old-y") d/parse-double)
|
|
||||||
(-> (dom/get-attribute node "data-old-width") d/parse-double)
|
|
||||||
(-> (dom/get-attribute node "data-old-height") d/parse-double))
|
|
||||||
(gsh/transform-selrect modifiers))]
|
|
||||||
(dom/set-attribute! node "x" x)
|
|
||||||
(dom/set-attribute! node "y" y)
|
|
||||||
(dom/set-attribute! node "width" width)
|
|
||||||
(dom/set-attribute! node "height" height)))
|
|
||||||
|
|
||||||
(defn start-transform!
|
|
||||||
[base-node shapes]
|
|
||||||
(doseq [shape shapes]
|
|
||||||
(when-let [nodes (get-nodes base-node shape)]
|
|
||||||
(doseq [node nodes]
|
|
||||||
(let [old-transform (dom/get-attribute node "transform")]
|
|
||||||
(when (some? old-transform)
|
|
||||||
(dom/set-attribute! node "data-old-transform" old-transform))
|
|
||||||
|
|
||||||
(when (or (= (dom/get-tag-name node) "linearGradient")
|
|
||||||
(= (dom/get-tag-name node) "radialGradient"))
|
|
||||||
(let [gradient-transform (dom/get-attribute node "gradientTransform")]
|
|
||||||
(when (some? gradient-transform)
|
|
||||||
(dom/set-attribute! node "data-old-gradientTransform" gradient-transform))))
|
|
||||||
|
|
||||||
(when (= (dom/get-tag-name node) "pattern")
|
|
||||||
(let [pattern-transform (dom/get-attribute node "patternTransform")]
|
|
||||||
(when (some? pattern-transform)
|
|
||||||
(dom/set-attribute! node "data-old-patternTransform" pattern-transform))))
|
|
||||||
|
|
||||||
(when (or (= (dom/get-tag-name node) "mask")
|
|
||||||
(= (dom/get-tag-name node) "filter"))
|
|
||||||
(let [old-x (dom/get-attribute node "x")
|
|
||||||
old-y (dom/get-attribute node "y")
|
|
||||||
old-width (dom/get-attribute node "width")
|
|
||||||
old-height (dom/get-attribute node "height")]
|
|
||||||
(dom/set-attribute! node "data-old-x" old-x)
|
|
||||||
(dom/set-attribute! node "data-old-y" old-y)
|
|
||||||
(dom/set-attribute! node "data-old-width" old-width)
|
|
||||||
(dom/set-attribute! node "data-old-height" old-height))))))))
|
|
||||||
|
|
||||||
(defn set-transform-att!
|
|
||||||
[node att value]
|
|
||||||
|
|
||||||
(let [old-att (dom/get-attribute node (dm/str "data-old-" att))
|
|
||||||
new-value (if (some? old-att)
|
|
||||||
(dm/str value " " old-att)
|
|
||||||
(str value))]
|
|
||||||
(dom/set-attribute! node att (str new-value))))
|
|
||||||
|
|
||||||
(defn update-transform!
|
|
||||||
[base-node shapes transforms modifiers]
|
|
||||||
(doseq [{:keys [id type] :as shape} shapes]
|
|
||||||
(when-let [nodes (get-nodes base-node shape)]
|
|
||||||
(let [transform (get transforms id)
|
|
||||||
modifiers (get-in modifiers [id :modifiers])
|
|
||||||
|
|
||||||
[text-transform _text-width _text-height]
|
|
||||||
(when (= :text type)
|
|
||||||
(text-corrected-transform shape transform modifiers))]
|
|
||||||
|
|
||||||
(doseq [node nodes]
|
|
||||||
(cond
|
|
||||||
;; Text shapes need special treatment because their resize only change
|
|
||||||
;; the text area, not the change size/position
|
|
||||||
(dom/class? node "text-shape")
|
|
||||||
(when (some? text-transform)
|
|
||||||
(set-transform-att! node "transform" text-transform))
|
|
||||||
|
|
||||||
(or (= (dom/get-tag-name node) "mask")
|
|
||||||
(= (dom/get-tag-name node) "filter"))
|
|
||||||
(transform-region! node modifiers)
|
|
||||||
|
|
||||||
(or (= (dom/get-tag-name node) "linearGradient")
|
|
||||||
(= (dom/get-tag-name node) "radialGradient"))
|
|
||||||
(set-transform-att! node "gradientTransform" transform)
|
|
||||||
|
|
||||||
(= (dom/get-tag-name node) "pattern")
|
|
||||||
(set-transform-att! node "patternTransform" transform)
|
|
||||||
|
|
||||||
(and (some? transform) (some? node))
|
|
||||||
(set-transform-att! node "transform" transform)))))))
|
|
||||||
|
|
||||||
(defn remove-transform!
|
|
||||||
[base-node shapes]
|
|
||||||
(doseq [shape shapes]
|
|
||||||
(when-let [nodes (get-nodes base-node shape)]
|
|
||||||
(doseq [node nodes]
|
|
||||||
(when (some? node)
|
|
||||||
(cond
|
|
||||||
(= (dom/get-tag-name node) "foreignObject")
|
|
||||||
;; The shape width/height will be automaticaly setup when the modifiers are applied
|
|
||||||
nil
|
|
||||||
|
|
||||||
(or (= (dom/get-tag-name node) "mask")
|
|
||||||
(= (dom/get-tag-name node) "filter"))
|
|
||||||
(do
|
|
||||||
(dom/remove-attribute! node "data-old-x")
|
|
||||||
(dom/remove-attribute! node "data-old-y")
|
|
||||||
(dom/remove-attribute! node "data-old-width")
|
|
||||||
(dom/remove-attribute! node "data-old-height"))
|
|
||||||
|
|
||||||
:else
|
|
||||||
(let [old-transform (dom/get-attribute node "data-old-transform")]
|
|
||||||
(if (some? old-transform)
|
|
||||||
(dom/remove-attribute! node "data-old-transform")
|
|
||||||
(dom/remove-attribute! node "transform")))))))))
|
|
||||||
|
|
||||||
(defn format-viewbox [vbox]
|
(defn format-viewbox [vbox]
|
||||||
(dm/str (:x vbox 0) " "
|
(dm/str (:x vbox 0) " "
|
||||||
(:y vbox 0) " "
|
(:y vbox 0) " "
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue