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