From 3c5ac2d94cd2a8ea3026118a11a775f90772ab92 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 25 Jan 2016 18:32:17 +0200 Subject: [PATCH] Reimplement the group rendering. --- src/uxbox/data/workspace.cljs | 50 ++------------ src/uxbox/shapes.cljs | 65 +++++++----------- src/uxbox/ui/shapes.cljs | 126 +++++++++++++--------------------- 3 files changed, 76 insertions(+), 165 deletions(-) diff --git a/src/uxbox/data/workspace.cljs b/src/uxbox/data/workspace.cljs index 065bbd0cef..3e5032027a 100644 --- a/src/uxbox/data/workspace.cljs +++ b/src/uxbox/data/workspace.cljs @@ -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 diff --git a/src/uxbox/shapes.cljs b/src/uxbox/shapes.cljs index 1e1b9186e1..712281f941 100644 --- a/src/uxbox/shapes.cljs +++ b/src/uxbox/shapes.cljs @@ -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}] diff --git a/src/uxbox/ui/shapes.cljs b/src/uxbox/ui/shapes.cljs index 2998ebfbe5..a61c7413ad 100644 --- a/src/uxbox/ui/shapes.cljs +++ b/src/uxbox/ui/shapes.cljs @@ -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))