mirror of
https://github.com/penpot/penpot.git
synced 2025-02-10 09:08:31 -05:00
Reimplement the group rendering.
This commit is contained in:
parent
a57c8d982c
commit
3c5ac2d94c
3 changed files with 76 additions and 165 deletions
|
@ -117,7 +117,7 @@
|
||||||
(filter #(= (:page %) pageid))
|
(filter #(= (:page %) pageid))
|
||||||
(remove :hidden)
|
(remove :hidden)
|
||||||
(remove :blocked)
|
(remove :blocked)
|
||||||
(map sh/resolve-position)
|
(map sh/-outer-rect)
|
||||||
(filter #(sh/contained-in? % selrect))
|
(filter #(sh/contained-in? % selrect))
|
||||||
(map :id))]
|
(map :id))]
|
||||||
(->> (into #{} xf (vals (:shapes-by-id state)))
|
(->> (into #{} xf (vals (:shapes-by-id state)))
|
||||||
|
@ -221,38 +221,6 @@
|
||||||
(when x {:x x})
|
(when x {:x x})
|
||||||
(when y {:y y})))))
|
(when y {:y y})))))
|
||||||
|
|
||||||
(defn rebuild-group-size
|
|
||||||
[id]
|
|
||||||
(letfn [(update-shape-pos [state {:keys [id x y] :as data}]
|
|
||||||
(update-in state [:shapes-by-id id] assoc :x x :y y))
|
|
||||||
|
|
||||||
(update-group-size [shape shapes]
|
|
||||||
(let [{:keys [width height]} (sh/group-dimensions shapes)]
|
|
||||||
(assoc shape
|
|
||||||
:width width
|
|
||||||
:height height
|
|
||||||
:view-box [0 0 width height])))
|
|
||||||
|
|
||||||
(update-group [shape shapes x y]
|
|
||||||
(-> shape
|
|
||||||
(update-group-size shapes)
|
|
||||||
(sh/translate-coords x y +)))]
|
|
||||||
|
|
||||||
(reify
|
|
||||||
rs/UpdateEvent
|
|
||||||
(-apply-update [_ state]
|
|
||||||
(let [shape (get-in state [:shapes-by-id id])
|
|
||||||
shapes (map #(get-in state [:shapes-by-id %]) (:items shape))
|
|
||||||
;; shapes (->> (:items shape)
|
|
||||||
;; (map #(get-in state [:shapes-by-id %]))
|
|
||||||
;; (map (fn [v] (merge v (sh/container-rect v)))))
|
|
||||||
x (apply min (map :x shapes))
|
|
||||||
y (apply min (map :y shapes))
|
|
||||||
shapes (map #(sh/translate-coords % x y) shapes)]
|
|
||||||
(as-> state $
|
|
||||||
(reduce update-shape-pos $ shapes)
|
|
||||||
(update-in $ [:shapes-by-id id] #(update-group % shapes x y))))))))
|
|
||||||
|
|
||||||
;; TODO: rename fill to "color" for consistency.
|
;; TODO: rename fill to "color" for consistency.
|
||||||
|
|
||||||
(defn update-shape-fill
|
(defn update-shape-fill
|
||||||
|
@ -319,17 +287,9 @@
|
||||||
"Mark a shape selected for drawing in the canvas."
|
"Mark a shape selected for drawing in the canvas."
|
||||||
[]
|
[]
|
||||||
(reify
|
(reify
|
||||||
rs/WatchEvent
|
rs/UpdateEvent
|
||||||
(-apply-watch [_ state]
|
(-apply-update [_ state]
|
||||||
(let [selected (get-in state [:workspace :selected])
|
(assoc-in state [:workspace :selected] #{}))))
|
||||||
mevent (rs/swap-state #(assoc-in state [:workspace :selected] #{}))]
|
|
||||||
;; (rx/just mevent)))))
|
|
||||||
(->> (map #(get-in state [:shapes-by-id %]) selected)
|
|
||||||
(rx/from-coll)
|
|
||||||
(rx/filter :group)
|
|
||||||
(rx/map :group)
|
|
||||||
(rx/map rebuild-group-size)
|
|
||||||
(rx/merge (rx/just mevent)))))))
|
|
||||||
|
|
||||||
(defn copy-selected
|
(defn copy-selected
|
||||||
"Copy the selected shapes."
|
"Copy the selected shapes."
|
||||||
|
@ -344,7 +304,6 @@
|
||||||
(map #(add-shape % %) $)
|
(map #(add-shape % %) $)
|
||||||
(rx/from-coll $))))))
|
(rx/from-coll $))))))
|
||||||
|
|
||||||
|
|
||||||
(defn group-selected
|
(defn group-selected
|
||||||
[]
|
[]
|
||||||
(letfn [(update-shapes-on-page [state pid selected group]
|
(letfn [(update-shapes-on-page [state pid selected group]
|
||||||
|
@ -357,7 +316,6 @@
|
||||||
(let [{:keys [x y]} dimensions]
|
(let [{:keys [x y]} dimensions]
|
||||||
(reduce (fn [state {:keys [id] :as shape}]
|
(reduce (fn [state {:keys [id] :as shape}]
|
||||||
(as-> shape $
|
(as-> shape $
|
||||||
(sh/translate-coords $ x y)
|
|
||||||
(assoc $ :group group)
|
(assoc $ :group group)
|
||||||
(assoc-in state [:shapes-by-id id] $)))
|
(assoc-in state [:shapes-by-id id] $)))
|
||||||
state
|
state
|
||||||
|
|
|
@ -74,12 +74,16 @@
|
||||||
[shape props]
|
[shape props]
|
||||||
(merge shape props))
|
(merge shape props))
|
||||||
|
|
||||||
(defmethod -initialize :builtin/line
|
(defmethod -initialize :builtin/group
|
||||||
[shape {:keys [x y width height]}]
|
[shape {:keys [x y width height]}]
|
||||||
(merge shape
|
shape)
|
||||||
{:x1 x :y1 y
|
|
||||||
:x2 (+ x width)
|
;; (defmethod -initialize :builtin/line
|
||||||
:y2 (+ y height)}))
|
;; [shape {:keys [x y width height]}]
|
||||||
|
;; (merge shape
|
||||||
|
;; {:x1 x :y1 y
|
||||||
|
;; :x2 (+ x width)
|
||||||
|
;; :y2 (+ y height)}))
|
||||||
|
|
||||||
(defmethod -move ::shape
|
(defmethod -move ::shape
|
||||||
[shape {:keys [dx dy] :as opts}]
|
[shape {:keys [dx dy] :as opts}]
|
||||||
|
@ -87,13 +91,19 @@
|
||||||
:x (+ (:x shape) dx)
|
:x (+ (:x shape) dx)
|
||||||
:y (+ (:y shape) dy)))
|
:y (+ (:y shape) dy)))
|
||||||
|
|
||||||
(defmethod -move :builtin/line
|
(defmethod -move :builtin/group
|
||||||
[shape {:keys [dx dy] :as opts}]
|
[shape {:keys [dx dy] :as opts}]
|
||||||
(assoc shape
|
(assoc shape
|
||||||
:x1 (+ (:x1 shape) dx)
|
:dx (+ (:dx shape 0) dx)
|
||||||
:y1 (+ (:y1 shape) dy)
|
:dy (+ (:dy shape 0) dy)))
|
||||||
:x2 (+ (:x2 shape) dx)
|
|
||||||
:y2 (+ (:y2 shape) dy)))
|
;; (defmethod -move :builtin/line
|
||||||
|
;; [shape {:keys [dx dy] :as opts}]
|
||||||
|
;; (assoc shape
|
||||||
|
;; :x1 (+ (:x1 shape) dx)
|
||||||
|
;; :y1 (+ (:y1 shape) dy)
|
||||||
|
;; :x2 (+ (:x2 shape) dx)
|
||||||
|
;; :y2 (+ (:y2 shape) dy)))
|
||||||
|
|
||||||
(defmethod -resize ::shape
|
(defmethod -resize ::shape
|
||||||
[shape {:keys [width height] :as opts}]
|
[shape {:keys [width height] :as opts}]
|
||||||
|
@ -110,26 +120,20 @@
|
||||||
(assoc shape :rotation rotation))
|
(assoc shape :rotation rotation))
|
||||||
|
|
||||||
(declare container-rect)
|
(declare container-rect)
|
||||||
(declare resolve-position)
|
|
||||||
|
|
||||||
(defmethod -outer-rect ::shape
|
(defmethod -outer-rect ::shape
|
||||||
[{:keys [group] :as shape}]
|
[{:keys [group] :as shape}]
|
||||||
(as-> shape $
|
(let [group (get-in @st/state [:shapes-by-id group])]
|
||||||
(resolve-position $)
|
(as-> shape $
|
||||||
(container-rect $)))
|
(assoc $ :x (+ (:x shape) (:dx group 0)))
|
||||||
|
(assoc $ :y (+ (:y shape) (:dy group 0)))
|
||||||
|
(container-rect $))))
|
||||||
|
|
||||||
(defmethod -outer-rect :builtin/group
|
(defmethod -outer-rect :builtin/group
|
||||||
[{:keys [id group rotation view-box] :as shape}]
|
[{:keys [id group rotation dx dy view-box] :as shape}]
|
||||||
(let [shapes (->> (:items shape)
|
(let [shapes (->> (:items shape)
|
||||||
(map #(get-in @st/state [:shapes-by-id %]))
|
(map #(get-in @st/state [:shapes-by-id %]))
|
||||||
(map -outer-rect))
|
(map -outer-rect))
|
||||||
|
|
||||||
crect (-> shape
|
|
||||||
(resolve-position)
|
|
||||||
(container-rect))
|
|
||||||
|
|
||||||
shapes (into [crect] shapes)
|
|
||||||
|
|
||||||
x (apply min (map :x shapes))
|
x (apply min (map :x shapes))
|
||||||
y (apply min (map :y shapes))
|
y (apply min (map :y shapes))
|
||||||
x' (apply max (map (fn [{:keys [x width]}] (+ x width)) shapes))
|
x' (apply max (map (fn [{:keys [x width]}] (+ x width)) shapes))
|
||||||
|
@ -218,8 +222,6 @@
|
||||||
:x x
|
:x x
|
||||||
:y y}))
|
:y y}))
|
||||||
|
|
||||||
(declare resolve-position)
|
|
||||||
|
|
||||||
(defn outer-rect
|
(defn outer-rect
|
||||||
[shapes]
|
[shapes]
|
||||||
{:pre [(seq shapes)]}
|
{:pre [(seq shapes)]}
|
||||||
|
@ -245,21 +247,6 @@
|
||||||
y' (:y shape)]
|
y' (:y shape)]
|
||||||
(assoc shape :x (op x' x) :y (op y' y)))))
|
(assoc shape :x (op x' x) :y (op y' y)))))
|
||||||
|
|
||||||
(defn resolve-position
|
|
||||||
"Recursively resolve the real shape position in
|
|
||||||
the canvas."
|
|
||||||
[{:keys [width height x y group] :as shape}]
|
|
||||||
(if group
|
|
||||||
(let [group (get-in @st/state [:shapes-by-id group])
|
|
||||||
result (resolve-position
|
|
||||||
(assoc group
|
|
||||||
:x (+ (:x group) x)
|
|
||||||
:y (+ (:y group) y)))]
|
|
||||||
(assoc shape
|
|
||||||
:x (:x result)
|
|
||||||
:y (:y result)))
|
|
||||||
shape))
|
|
||||||
|
|
||||||
(defn resolve-parent
|
(defn resolve-parent
|
||||||
"Recursively resolve the real shape parent."
|
"Recursively resolve the real shape parent."
|
||||||
[{:keys [group] :as shape}]
|
[{:keys [group] :as shape}]
|
||||||
|
|
|
@ -4,20 +4,21 @@
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[rum.core :as rum]
|
[rum.core :as rum]
|
||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.shapes :as shapes]
|
[uxbox.shapes :as sh]
|
||||||
[uxbox.ui.icons :as i]
|
[uxbox.ui.icons :as i]
|
||||||
[uxbox.util.svg :as svg]
|
[uxbox.util.svg :as svg]
|
||||||
|
[uxbox.util.matrix :as mtx]
|
||||||
|
[uxbox.util.math :as mth]
|
||||||
[uxbox.util.data :refer (remove-nil-vals)]))
|
[uxbox.util.data :refer (remove-nil-vals)]))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Attribute transformations
|
;; Attribute transformations
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defn- extract-attrs
|
(defn- extract-style-attrs
|
||||||
"Extract predefinet attrs from shapes."
|
"Extract predefinet attrs from shapes."
|
||||||
[shape]
|
[shape]
|
||||||
(select-keys shape [:fill :opacity :stroke :stroke-opacity :stroke-width
|
(select-keys shape [:fill :opacity :stroke :stroke-opacity :stroke-width]))
|
||||||
:x1 :x2 :y1 :y2 :cx :cy :r]))
|
|
||||||
|
|
||||||
(defn- make-debug-attrs
|
(defn- make-debug-attrs
|
||||||
[shape]
|
[shape]
|
||||||
|
@ -30,96 +31,61 @@
|
||||||
;; Implementation
|
;; Implementation
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defmethod shapes/-render :builtin/icon
|
(defmethod sh/-render :builtin/icon
|
||||||
[{:keys [data id] :as shape} _]
|
[{:keys [data id] :as shape} _]
|
||||||
(let [key (str id)
|
(let [key (str id)
|
||||||
rfm (svg/calculate-transform shape)
|
rfm (svg/calculate-transform shape)
|
||||||
attrs (merge {:id key :key key :transform rfm}
|
attrs (merge {:id key :key key :transform rfm}
|
||||||
(extract-attrs shape)
|
;; (select-keys shape [:x :y :width :height])
|
||||||
(make-debug-attrs shape))]
|
(make-debug-attrs shape)
|
||||||
|
(extract-style-attrs shape))]
|
||||||
(html
|
(html
|
||||||
[:g attrs data])))
|
[:g attrs data])))
|
||||||
|
|
||||||
(defmethod shapes/-render :builtin/rect
|
|
||||||
[{:keys [id view-box] :as shape} _]
|
|
||||||
(let [key (str id)
|
|
||||||
rfm (svg/calculate-transform shape)
|
|
||||||
attrs (merge {:width (nth view-box 2)
|
|
||||||
:height (nth view-box 3)
|
|
||||||
:x 0 :y 0}
|
|
||||||
(extract-attrs shape)
|
|
||||||
(make-debug-attrs shape))]
|
|
||||||
(html
|
|
||||||
[:g {:id key :key key :transform rfm}
|
|
||||||
[:rect attrs]])))
|
|
||||||
|
|
||||||
(defmethod shapes/-render :builtin/circle
|
;; FIXME: the impl should be more clear.
|
||||||
[{:keys [id view-box] :as shape} _]
|
|
||||||
(let [key (str id)
|
|
||||||
rfm (svg/calculate-transform shape)
|
|
||||||
attrs (merge (extract-attrs shape)
|
|
||||||
(make-debug-attrs shape))]
|
|
||||||
(html
|
|
||||||
[:g {:id key :key key :transform rfm}
|
|
||||||
[:circle attrs]])))
|
|
||||||
|
|
||||||
(defmethod shapes/-render :builtin/line
|
(defmethod sh/-render :builtin/group
|
||||||
[{:keys [id view-box] :as shape} _]
|
[{:keys [items id dx dy rotation] :as shape} factory]
|
||||||
(let [key (str id)
|
(letfn [(rotation-matrix []
|
||||||
;; rfm (svg/calculate-transform shape)
|
(let [shapes-by-id (get @st/state :shapes-by-id)
|
||||||
attrs (extract-attrs shape)]
|
shapes (map #(get shapes-by-id %) items)
|
||||||
;; attrs (merge (extract-attrs shape)
|
{:keys [x y width height]} (sh/outer-rect shapes)
|
||||||
;; (make-debug-attrs shape))]
|
center-x (+ x (/ width 2))
|
||||||
(html
|
center-y (+ y (/ height 2))]
|
||||||
[:g {:id key :key key}
|
(mtx/multiply (svg/translate-matrix center-x center-y)
|
||||||
[:line attrs]])))
|
(svg/rotation-matrix rotation)
|
||||||
|
(svg/translate-matrix (- center-x)
|
||||||
|
(- center-y)))))
|
||||||
|
(translate-matrix []
|
||||||
|
(svg/translate-matrix (or dx 0) (or dy 0)))
|
||||||
|
|
||||||
(defmethod shapes/-render :builtin/group
|
(transform []
|
||||||
[{:keys [items id] :as shape} factory]
|
(let [result (mtx/multiply (rotation-matrix)
|
||||||
(let [key (str "group-" id)
|
(translate-matrix))
|
||||||
tfm (svg/calculate-transform shape)
|
result (flatten @result)]
|
||||||
attrs (merge {:id key :key key :transform tfm}
|
(->> (map #(nth result %) [0 3 1 4 2 5])
|
||||||
(make-debug-attrs shape))
|
(str/join ",")
|
||||||
shapes-by-id (get @st/state :shapes-by-id)]
|
(str/format "matrix(%s)"))))]
|
||||||
(html
|
(let [key (str "group-" id)
|
||||||
[:g attrs
|
tfm (transform)
|
||||||
(for [item (->> items
|
attrs (merge {:id key :key key :transform tfm}
|
||||||
(map #(get shapes-by-id %))
|
(make-debug-attrs shape))
|
||||||
(remove :hidden))]
|
shapes-by-id (get @st/state :shapes-by-id)]
|
||||||
(-> (factory item)
|
(html
|
||||||
(rum/with-key (str (:id item)))))])))
|
[:g attrs
|
||||||
|
(for [item (->> items
|
||||||
|
(map #(get shapes-by-id %))
|
||||||
|
(remove :hidden))]
|
||||||
|
(-> (factory item)
|
||||||
|
(rum/with-key (str (:id item)))))]))))
|
||||||
|
|
||||||
(defmethod shapes/-render-svg :builtin/icon
|
(defmethod sh/-render-svg :builtin/icon
|
||||||
[{:keys [data id view-box] :as shape}]
|
[{:keys [data id view-box] :as shape}]
|
||||||
(let [key (str "icon-svg-" id)
|
(let [key (str "icon-svg-" id)
|
||||||
view-box (apply str (interpose " " view-box))
|
view-box (apply str (interpose " " view-box))
|
||||||
props {:view-box view-box :id key :key key}
|
props {:view-box view-box :id key :key key}
|
||||||
attrs (-> shape
|
attrs (merge props
|
||||||
(extract-attrs)
|
(extract-style-attrs shape))]
|
||||||
(remove-nil-vals)
|
|
||||||
(merge props))]
|
|
||||||
(html
|
(html
|
||||||
[:svg attrs data])))
|
[:svg attrs data])))
|
||||||
|
|
||||||
(defmethod shapes/-render-svg :builtin/rect
|
|
||||||
[{:keys [id view-box] :as shape}]
|
|
||||||
(html i/box))
|
|
||||||
;; (let [key (str "icon-svg-" id)
|
|
||||||
;; view (apply str (interpose " " view-box))
|
|
||||||
;; props {:view-box view :id key :key key}
|
|
||||||
;; attrs (merge {:width (nth view-box 2)
|
|
||||||
;; :height (nth view-box 3)
|
|
||||||
;; :x 0 :y 0}
|
|
||||||
;; (extract-attrs shape)
|
|
||||||
;; (make-debug-attrs shape))]
|
|
||||||
;; (html
|
|
||||||
;; [:svg props
|
|
||||||
;; [:rect attrs]])))
|
|
||||||
|
|
||||||
(defmethod shapes/-render-svg :builtin/circle
|
|
||||||
[{:keys [id view-box] :as shape}]
|
|
||||||
(html i/circle))
|
|
||||||
|
|
||||||
(defmethod shapes/-render-svg :builtin/line
|
|
||||||
[{:keys [id view-box] :as shape}]
|
|
||||||
(html i/line))
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue