0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-10 17:18:21 -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))
(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

View file

@ -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}]
(let [group (get-in @st/state [:shapes-by-id group])]
(as-> shape $
(resolve-position $)
(container-rect $)))
(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}]

View file

@ -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,54 +31,44 @@
;; 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]
(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 (svg/calculate-transform shape)
tfm (transform)
attrs (merge {:id key :key key :transform tfm}
(make-debug-attrs shape))
shapes-by-id (get @st/state :shapes-by-id)]
@ -87,39 +78,14 @@
(map #(get shapes-by-id %))
(remove :hidden))]
(-> (factory item)
(rum/with-key (str (:id 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))