0
Fork 0
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:
Andrey Antukh 2016-01-25 18:32:17 +02:00
parent a57c8d982c
commit 3c5ac2d94c
3 changed files with 76 additions and 165 deletions

View file

@ -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

View file

@ -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}]

View file

@ -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))