Change resize to use DOM transformations

This commit is contained in:
alonso.torres 2021-12-21 12:32:04 +01:00
parent fa09fff2b5
commit b2211aec59
38 changed files with 839 additions and 717 deletions

View file

@ -6,9 +6,6 @@
(ns app.main.ui.shapes.bool
(:require
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.path :as gsp]
[app.common.path.bool :as pb]
[app.common.path.shapes-to-path :as stp]
[app.main.ui.hooks :refer [use-equal-memo]]
@ -17,87 +14,26 @@
[app.util.object :as obj]
[rumext.alpha :as mf]))
(mf/defc debug-bool
{::mf/wrap-props false}
[props]
(let [frame (obj/get props "frame")
shape (obj/get props "shape")
childs (obj/get props "childs")
[content-a content-b]
(mf/use-memo
(mf/deps shape childs)
(fn []
(let [childs (d/mapm #(-> %2 (gsh/translate-to-frame frame) gsh/transform-shape) childs)
[content-a content-b]
(->> (:shapes shape)
(map #(get childs %))
(filter #(not (:hidden %)))
(map #(stp/convert-to-path % childs))
(map :content)
(map pb/close-paths)
(map pb/add-previous))]
(pb/content-intersect-split content-a content-b))))]
[:g.debug-bool
[:g.shape-a
[:& path-shape {:shape (-> shape
(assoc :type :path)
(assoc :stroke-color "blue")
(assoc :stroke-opacity 1)
(assoc :stroke-width 1)
(assoc :stroke-style :solid)
(dissoc :fill-color :fill-opacity)
(assoc :content content-b))
:frame frame}]
(for [{:keys [x y]} (gsp/content->points (pb/close-paths content-b))]
[:circle {:cx x
:cy y
:r 2.5
:style {:fill "blue"}}])]
[:g.shape-b
[:& path-shape {:shape (-> shape
(assoc :type :path)
(assoc :stroke-color "red")
(assoc :stroke-opacity 1)
(assoc :stroke-width 0.5)
(assoc :stroke-style :solid)
(dissoc :fill-color :fill-opacity)
(assoc :content content-a))
:frame frame}]
(for [{:keys [x y]} (gsp/content->points (pb/close-paths content-a))]
[:circle {:cx x
:cy y
:r 1.25
:style {:fill "red"}}])]])
)
(defn bool-shape
[shape-wrapper]
(mf/fnc bool-shape
{::mf/wrap-props false}
[props]
(let [frame (obj/get props "frame")
shape (obj/get props "shape")
(let [shape (obj/get props "shape")
childs (obj/get props "childs")
childs (use-equal-memo childs)
include-metadata? (mf/use-ctx use/include-metadata-ctx)
bool-content
(mf/use-memo
(mf/deps shape childs)
(fn []
(let [childs (d/mapm #(-> %2 gsh/transform-shape (gsh/translate-to-frame frame)) childs)]
(->> (:shapes shape)
(map #(get childs %))
(filter #(not (:hidden %)))
(map #(stp/convert-to-path % childs))
(mapv :content)
(pb/content-bool (:bool-type shape))))))]
(->> (:shapes shape)
(map #(get childs %))
(filter #(not (:hidden %)))
(map #(stp/convert-to-path % childs))
(mapv :content)
(pb/content-bool (:bool-type shape)))))]
[:*
[:& path-shape {:shape (assoc shape :content bool-content)}]
@ -105,10 +41,5 @@
(when include-metadata?
[:> "penpot:bool" {}
(for [item (->> (:shapes shape) (mapv #(get childs %)))]
[:& shape-wrapper {:frame frame
:shape item
:key (:id item)}])])
#_[:& debug-bool {:frame frame
:shape shape
:childs childs}]])))
[:& shape-wrapper {:shape item
:key (:id item)}])])])))

View file

@ -25,7 +25,12 @@
(let [;; When not active the embedding we return the URI
url-mapping (fn [obs]
(if embed?
(rx/merge-map http/fetch-data-uri obs)
(->> obs
(rx/merge-map
(fn [uri]
(->> (http/fetch-data-uri uri true)
;; If fetching give an error we store the URI as its `data-uri`
(rx/catch #(rx/of (hash-map uri uri)))))))
(rx/map identity obs)))
sub (->> (rx/from urls)

View file

@ -113,7 +113,7 @@
filter-x (min x (+ x offset-x (- spread) (- blur) -5))
filter-y (min y (+ y offset-y (- spread) (- blur) -5))
filter-width (+ width (mth/abs offset-x) (* spread 2) (* blur 2) 10)
filter-height (+ height (mth/abs offset-x) (* spread 2) (* blur 2) 10)]
filter-height (+ height (mth/abs offset-y) (* spread 2) (* blur 2) 10)]
{:x1 filter-x
:y1 filter-y
:x2 (+ filter-x filter-width)
@ -208,26 +208,31 @@
margin (gsh/shape-stroke-margin shape stroke-width)]
(+ stroke-width margin)))
(defn change-filter-in
"Adds the previous filter as `filter-in` parameter"
[filters]
(map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters))))
(mf/defc filters
[{:keys [filter-id shape]}]
(let [filters (shape->filters shape)
;; Adds the previous filter as `filter-in` parameter
filters (map #(assoc %1 :filter-in %2) filters (cons nil (map :id filters)))
bounds (get-filters-bounds shape filters (or (-> shape :blur :value) 0))
padding (calculate-padding shape)]
(let [filters (-> shape shape->filters change-filter-in)
bounds (get-filters-bounds shape filters (or (-> shape :blur :value) 0))
padding (calculate-padding shape)
selrect (:selrect shape)
filter-x (/ (- (:x bounds) (:x selrect) padding) (:width selrect))
filter-y (/ (- (:y bounds) (:y selrect) padding) (:height selrect))
filter-width (/ (+ (:width bounds) (* 2 padding)) (:width selrect))
filter-height (/ (+ (:height bounds) (* 2 padding)) (:height selrect))]
[:*
(when (> (count filters) 2)
[:filter {:id filter-id
:x (- (:x bounds) padding)
:y (- (:y bounds) padding)
:width (+ (:width bounds) (* 2 padding))
:height (+ (:height bounds) (* 2 padding))
:filterUnits "userSpaceOnUse"
[:filter {:id filter-id
:x filter-x
:y filter-y
:width filter-width
:height filter-height
:filterUnits "objectBoundingBox"
:color-interpolation-filters "sRGB"}
(for [entry filters]
[:& filter-entry {:entry entry}])])]))

View file

@ -10,6 +10,22 @@
[app.util.object :as obj]
[rumext.alpha :as mf]))
(defn frame-clip-id
[shape render-id]
(str "frame-clip-" (:id shape) "-" render-id))
(defn frame-clip-url
[shape render-id]
(when (= :frame (:type shape))
(str "url(#" (frame-clip-id shape render-id) ")")))
(mf/defc frame-clip-def
[{:keys [shape render-id]}]
(when (= :frame (:type shape))
(let [{:keys [x y width height]} shape]
[:clipPath {:id (frame-clip-id shape render-id) :class "frame-clip"}
[:rect {:x x :y y :width width :height height}]])))
(defn frame-shape
[shape-wrapper]
(mf/fnc frame-shape
@ -17,7 +33,7 @@
[props]
(let [childs (unchecked-get props "childs")
shape (unchecked-get props "shape")
{:keys [width height]} shape
{:keys [x y width height]} shape
has-background? (or (some? (:fill-color shape))
(some? (:fill-color-gradient shape)))
@ -25,8 +41,8 @@
props (-> (attrs/extract-style-attrs shape)
(obj/merge!
#js {:x 0
:y 0
#js {:x x
:y y
:width width
:height height
:className "frame-background"}))]
@ -34,7 +50,6 @@
(when (or has-background? has-stroke?)
[:> :rect props])
(for [item childs]
[:& shape-wrapper {:frame shape
:shape item
[:& shape-wrapper {:shape item
:key (:id item)}])])))

View file

@ -17,8 +17,7 @@
(mf/fnc group-shape
{::mf/wrap-props false}
[props]
(let [frame (unchecked-get props "frame")
shape (unchecked-get props "shape")
(let [shape (unchecked-get props "shape")
childs (unchecked-get props "childs")
render-id (mf/use-ctx muc/render-ctx)
masked-group? (:masked-group? shape)
@ -46,11 +45,10 @@
[:> clip-wrapper clip-props
[:> mask-wrapper mask-props
(when masked-group?
[:> render-mask #js {:frame frame :mask mask}])
[:> render-mask #js {:mask mask}])
(for [item childs]
[:& shape-wrapper {:frame frame
:shape item
[:& shape-wrapper {:shape item
:key (:id item)}])]]))))

View file

@ -34,13 +34,9 @@
(mf/fnc mask-shape
{::mf/wrap-props false}
[props]
(let [frame (unchecked-get props "frame")
mask (unchecked-get props "mask")
(let [mask (unchecked-get props "mask")
render-id (mf/use-ctx muc/render-ctx)
mask' (-> mask
(gsh/transform-shape)
(gsh/translate-to-frame frame))]
mask' (gsh/transform-shape mask)]
[:defs
[:filter {:id (filter-id render-id mask)}
[:feFlood {:flood-color "white"
@ -52,13 +48,13 @@
;; Clip path is necessary so the elements inside the mask won't affect
;; the events outside. Clip hides the elements but mask doesn't (like display vs visibility)
;; we cannot use clips instead of mask because clips can only be simple shapes
[:clipPath {:id (clip-id render-id mask)}
[:clipPath {:class "mask-clip-path"
:id (clip-id render-id mask)}
[:polyline {:points (->> (:points mask')
(map #(str (:x %) "," (:y %)))
(str/join " "))}]]
[:mask {:id (mask-id render-id mask)}
[:mask {:class "mask-shape"
:id (mask-id render-id mask)}
[:g {:filter (filter-url render-id mask)}
[:& shape-wrapper {:frame frame
:shape (-> mask
(dissoc :shadow :blur))}]]]])))
[:& shape-wrapper {:shape (dissoc mask :shadow :blur)}]]]])))

View file

@ -14,6 +14,7 @@
[app.main.ui.shapes.export :as ed]
[app.main.ui.shapes.fill-image :as fim]
[app.main.ui.shapes.filters :as filters]
[app.main.ui.shapes.frame :as frame]
[app.main.ui.shapes.gradients :as grad]
[app.main.ui.shapes.svg-defs :as defs]
[app.util.object :as obj]
@ -26,6 +27,8 @@
(let [shape (obj/get props "shape")
children (obj/get props "children")
pointer-events (obj/get props "pointer-events")
type (:type shape)
render-id (mf/use-memo #(str (uuid/next)))
filter-id (str "filter_" render-id)
styles (-> (obj/new)
@ -34,10 +37,6 @@
(cond-> (and (:blend-mode shape) (not= (:blend-mode shape) :normal))
(obj/set! "mixBlendMode" (d/name (:blend-mode shape)))))
{:keys [x y width height type]} shape
frame? (= :frame type)
group? (= :group type)
include-metadata? (mf/use-ctx ed/include-metadata-ctx)
wrapper-props
@ -50,26 +49,14 @@
wrapper-props
(cond-> wrapper-props
frame?
(-> (obj/set! "x" x)
(obj/set! "y" y)
(obj/set! "width" width)
(obj/set! "height" height)
(obj/set! "xmlns" "http://www.w3.org/2000/svg")
(obj/set! "xmlnsXlink" "http://www.w3.org/1999/xlink")
(cond->
include-metadata?
(obj/set! "xmlns:penpot" "https://penpot.app/xmlns"))))
(= :frame type)
(obj/set! "clipPath" (frame/frame-clip-url shape render-id))
wrapper-props
(cond-> wrapper-props
group?
(attrs/add-style-attrs shape))
wrapper-tag (if frame? "svg" "g")]
(= :group type)
(attrs/add-style-attrs shape))]
[:& (mf/provider muc/render-ctx) {:value render-id}
[:> wrapper-tag wrapper-props
[:> :g wrapper-props
(when include-metadata?
[:& ed/export-data {:shape shape}])
@ -79,5 +66,6 @@
[:& grad/gradient {:shape shape :attr :fill-color-gradient}]
[:& grad/gradient {:shape shape :attr :stroke-color-gradient}]
[:& fim/fill-image-pattern {:shape shape :render-id render-id}]
[:& cs/stroke-defs {:shape shape :render-id render-id}]]
[:& cs/stroke-defs {:shape shape :render-id render-id}]
[:& frame/frame-clip-def {:shape shape :render-id render-id}]]
children]]))

View file

@ -88,8 +88,7 @@
{::mf/wrap-props false}
[props]
(let [frame (unchecked-get props "frame")
shape (unchecked-get props "shape")
(let [shape (unchecked-get props "shape")
childs (unchecked-get props "childs")
{:keys [content]} shape
@ -103,12 +102,12 @@
svg-root?
[:& svg-root {:shape shape}
(for [item childs]
[:& shape-wrapper {:frame frame :shape item :key (:id item)}])]
[:& shape-wrapper {:shape item :key (:id item)}])]
svg-tag?
[:& svg-element {:shape shape}
(for [item childs]
[:& shape-wrapper {:frame frame :shape item :key (:id item)}])]
[:& shape-wrapper {:shape item :key (:id item)}])]
svg-leaf?
content