Merge branch 'resize-refactor'

This commit is contained in:
Andrey Antukh
2016-12-20 21:36:22 +01:00
24 changed files with 846 additions and 483 deletions

View File

@@ -3,7 +3,6 @@
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.constants)
@@ -18,5 +17,3 @@
(def canvas-scroll-padding 50)
(def canvas-start-scroll-x (- canvas-start-x canvas-scroll-padding))
(def canvas-start-scroll-y (- canvas-start-y canvas-scroll-padding))

View File

@@ -3,7 +3,6 @@
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.data.dashboard
(:require [beicon.core :as rx]

View File

@@ -9,10 +9,11 @@
[cuerdas.core :as str]
[beicon.core :as rx]
[lentes.core :as l]
[uxbox.main.repo :as rp]
[uxbox.store :as st]
[uxbox.util.spec :as us]
[potok.core :as ptk]
[uxbox.store :as st]
[uxbox.main.repo :as rp]
[uxbox.util.rlocks :as rlocks]
[uxbox.util.spec :as us]
[uxbox.util.router :as r]
[uxbox.util.i18n :refer (tr)]
[uxbox.util.forms :as sc]
@@ -308,6 +309,7 @@
(rx/merge
(->> stream
(rx/take-until stopper)
(rx/filter #(not= @rlocks/lock :shape/resize))
(rx/filter #(satisfies? IPageUpdate %))
(rx/debounce 1000)
(rx/map #(persist-page id)))

View File

@@ -3,7 +3,6 @@
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.data.projects
(:require [cuerdas.core :as str]

View File

@@ -3,23 +3,23 @@
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.data.shapes
(:require [beicon.core :as rx]
[uxbox.util.uuid :as uuid]
[potok.core :as ptk]
[uxbox.util.router :as r]
[uxbox.store :as st]
[uxbox.util.forms :as sc]
[uxbox.util.geom.point :as gpt]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.router :as r]
[uxbox.util.rlocks :as rlocks]
[uxbox.util.workers :as uw]
[uxbox.main.constants :as c]
[uxbox.main.geom :as geom]
[uxbox.store :as st]
[uxbox.main.data.core :refer (worker)]
[uxbox.main.data.shapes-impl :as impl]
[uxbox.main.data.pages :as udp]
[uxbox.util.rlocks :as rlocks]
[uxbox.util.geom.point :as gpt]))
[uxbox.main.data.pages :as udp]))
;; --- Shapes CRUD
@@ -71,18 +71,21 @@
(gpt/point c/canvas-start-x
c/canvas-start-y))
(declare apply-temporal-displacement)
(defn initial-align-shape
[id]
(reify
ptk/WatchEvent
(watch [_ state s]
(let [shape (get-in state [:shapes id])
shape (geom/outer-rect state shape)
point (gpt/point (:x shape) (:y shape))
point (gpt/add point canvas-coords)]
(->> (align-point point)
(rx/map #(gpt/subtract % point))
(rx/map #(move-shape id %)))))))
(let [{:keys [x1 y1] :as shape} (->> (get-in state [:shapes id])
(geom/shape->rect-shape state))
point1 (gpt/point x1 y1)
point2 (gpt/add point1 canvas-coords)]
(->> (align-point point2)
(rx/map #(gpt/subtract % canvas-coords))
(rx/map (fn [{:keys [x y] :as pt}]
(apply-temporal-displacement id (gpt/subtract pt point1)))))))))
(defn update-line-attrs
[sid {:keys [x1 y1 x2 y2] :as opts}]
@@ -120,6 +123,92 @@
(update [_ state]
(update-in state [:shapes sid] geom/resize-dim opts))))
;; --- Apply Temporal Displacement
(deftype ApplyTemporalDisplacement [id delta]
ptk/UpdateEvent
(update [_ state]
(let [current-delta (get-in state [:shapes id :tmp-displacement] (gpt/point 0 0))
delta (gpt/add current-delta delta)]
(assoc-in state [:shapes id :tmp-displacement] delta))))
(defn apply-temporal-displacement
[id pt]
{:pre [(uuid? id) (gpt/point? pt)]}
(ApplyTemporalDisplacement. id pt))
;; --- Apply Displacement
(deftype ApplyDisplacement [id]
ptk/UpdateEvent
(update [_ state]
(let [{:keys [tmp-displacement type] :as shape} (get-in state [:shapes id])
xfmt (gmt/translate-matrix tmp-displacement)]
(if (= type :group)
(letfn [(update-item [state id]
(let [{:keys [type items] :as shape} (get-in state [:shapes id])]
(if (= type :group)
(reduce update-item state items)
(update-in state [:shapes id]
(fn [shape]
(as-> (dissoc shape :tmp-displacement) $
(geom/transform state $ xfmt)))))))]
(-> (reduce update-item state (:items shape))
(update-in [:shapes id] dissoc :tmp-displacement)))
(update-in state [:shapes id] (fn [shape]
(as-> (dissoc shape :tmp-displacement) $
(geom/transform state $ xfmt))))))))
(defn apply-displacement
[id]
{:pre [(uuid? id)]}
(ApplyDisplacement. id))
;; --- Apply Temporal Resize Matrix
(deftype ApplyTemporalResizeMatrix [id mx]
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:shapes id :tmp-resize-xform] mx)))
(defn apply-temporal-resize-matrix
"Attach temporal resize matrix transformation to the shape."
[id mx]
(ApplyTemporalResizeMatrix. id mx))
;; --- Apply Resize Matrix
(declare apply-resize-matrix)
(deftype ApplyResizeMatrix [id]
ptk/UpdateEvent
(update [_ state]
(let [{:keys [type tmp-resize-xform]
:or {tmp-resize-xform (gmt/matrix)}
:as shape} (get-in state [:shapes id])]
(if (= type :group)
(letfn [(update-item [state id]
(let [{:keys [type items] :as shape} (get-in state [:shapes id])]
(if (= type :group)
(reduce update-item state items)
(update-in state [:shapes id]
(fn [shape]
(as-> (dissoc shape :tmp-resize-xform) $
(geom/transform state $ tmp-resize-xform)))))))]
(-> (reduce update-item state (:items shape))
(update-in [:shapes id] dissoc :tmp-resize-xform)))
(update-in state [:shapes id] (fn [shape]
(as-> (dissoc shape :tmp-resize-xform) $
(geom/transform state $ tmp-resize-xform))))))))
(defn apply-resize-matrix
"Apply definitivelly the resize matrix transformation to the shape."
[id]
{:pre [(uuid? id)]}
(ApplyResizeMatrix. id))
(defn update-vertex-position
[id {:keys [vid delta]}]
(reify
@@ -209,7 +298,6 @@
(when rx {:rx rx})
(when ry {:ry ry})))))
;; --- Shape Proportions
(defn lock-proportions
@@ -379,17 +467,20 @@
id (first (get-in state [:pages page :shapes]))]
(assoc-in state [:workspace :selected] #{id})))))
(deftype SelectShape [id]
ptk/UpdateEvent
(update [_ state]
(let [selected (get-in state [:workspace :selected])
state (if (contains? selected id)
(update-in state [:workspace :selected] disj id)
(update-in state [:workspace :selected] conj id))]
(update-in state [:workspace :flags] conj :element-options))))
(defn select-shape
"Mark a shape selected for drawing in the canvas."
[id]
(reify
ptk/UpdateEvent
(update [_ state]
(let [selected (get-in state [:workspace :selected])
state (if (contains? selected id)
(update-in state [:workspace :selected] disj id)
(update-in state [:workspace :selected] conj id))]
(update-in state [:workspace :flags] conj :element-options)))))
(SelectShape. id))
;; --- Select Shapes

View File

@@ -12,6 +12,7 @@
;; --- Relative Movement
;; TODO: revisit, maybe dead code
(declare move-rect)
(declare move-path)
(declare move-circle)
@@ -118,31 +119,47 @@
(declare size-rect)
(declare size-circle)
(declare size-path)
(defn size
"Calculate the size of the shape."
[shape]
(case (:type shape)
:group (assoc shape :width 100 :height 100)
:circle (size-circle shape)
:text (size-rect shape)
:rect (size-rect shape)
:icon (size-rect shape)
:image (size-rect shape)
:path (size-rect shape)))
:path (size-path shape)))
(defn- size-path
[{:keys [points x1 y1 x2 y2] :as shape}]
(if (and x1 y1 x2 y2)
(assoc shape
:width (- x2 x1)
:height (- y2 y1))
(let [minx (apply min (map :x points))
miny (apply min (map :y points))
maxx (apply max (map :x points))
maxy (apply max (map :y points))]
(assoc shape
:width (- maxx minx)
:height (- maxy miny)))))
(defn- size-rect
"A specialized function for calculate size
for rect-like shapes."
[{:keys [x1 y1 x2 y2] :as shape}]
{:width (- x2 x1)
:height (- y2 y1)})
(merge shape {:width (- x2 x1)
:height (- y2 y1)}))
(defn- size-circle
"A specialized function for calculate size
for circle shape."
[{:keys [rx ry]}]
{:width (* rx 2)
:height (* ry 2)})
[{:keys [rx ry] :as shape}]
(merge shape {:width (* rx 2)
:height (* ry 2)}))
;; --- Vertex Access
@@ -196,7 +213,7 @@
"A specialized function for vertex movement
for rect-like shapes."
[shape vid {dx :x dy :y lock? :lock}]
(letfn [(handle-positioning [{:keys [x1 x2 y1 y2 proportion] :as shape}]
(letfn [(handle-positioning [{:keys [x1 x2 y1 y2] :as shape}]
(case vid
:top-left (assoc shape
:x1 (min x2 (+ x1 dx))
@@ -465,66 +482,125 @@
:proportion (/ width height)
:proportion-lock true)))
;; --- Inner Rect
;; --- Coerce to Rect-like shape.
(declare apply-rotation-transformation)
(declare inner-rect-circle)
(declare inner-rect-group)
(declare inner-rect-path)
(declare inner-rect-generic)
(declare circle->rect-shape)
(declare path->rect-shape)
(declare group->rect-shape)
(defn inner-rect
([shape] (inner-rect @st/state shape))
([state shape]
(case (:type shape)
:circle (inner-rect-circle state shape)
:group (inner-rect-group state shape)
:path (inner-rect-path state shape)
(inner-rect-generic state shape))))
(defn shape->rect-shape
"Coerce shape to rect like shape."
([shape] (shape->rect-shape @st/state shape))
([state {:keys [type] :as shape}]
(case type
:circle (circle->rect-shape state shape)
:path (path->rect-shape state shape)
:group (group->rect-shape state shape)
shape)))
(defn- inner-rect-generic
[state {:keys [x1 y1] :as shape}]
(-> (assoc shape :x x1 :y y1)
(merge (size shape))
(apply-rotation-transformation)))
(defn shapes->rect-shape
([shapes] (shapes->rect-shape @st/state shapes))
([state shapes]
{:pre [(seq shapes)]}
(let [shapes (map shape->rect-shape shapes)
minx (apply min (map :x1 shapes))
miny (apply min (map :y1 shapes))
maxx (apply max (map :x2 shapes))
maxy (apply max (map :y2 shapes))]
{:x1 minx
:y1 miny
:x2 maxx
:y2 maxy
::shapes shapes})))
(defn- inner-rect-path
(defn- group->rect-shape
[state {:keys [items] :as group}]
(let [shapes (map #(get-in state [:shapes %]) items)]
(shapes->rect-shape state shapes)))
(defn- path->rect-shape
[state {:keys [points] :as shape}]
(let [minx (apply min (map :x points))
miny (apply min (map :y points))
maxx (apply max (map :x points))
maxy (apply max (map :y points))
props {:x minx
:y miny
:width (- maxx minx)
:height (- maxy miny)}]
(-> (merge shape props)
(apply-rotation-transformation))))
maxy (apply max (map :y points))]
(assoc shape
:x1 minx
:y1 miny
:x2 maxx
:y2 maxy)))
(defn- inner-rect-circle
[state {:keys [cx cy rx ry group] :as shape}]
(let [props {:x (- cx rx)
:y (- cy ry)
:width (* rx 2)
:height (* ry 2)}]
(-> (merge shape props)
(apply-rotation-transformation))))
(defn- circle->rect-shape
[state {:keys [cx cy rx ry] :as shape}]
(let [width (* rx 2)
height (* ry 2)
x1 (- cx rx)
y1 (- cy ry)]
(assoc shape
:x1 x1
:y1 y1
:x2 (+ x1 width)
:y2 (+ y1 height))))
(defn- inner-rect-group
[state {:keys [id group rotation dx dy] :as shape}]
(let [shapes (->> (:items shape)
(map #(get-in state [:shapes %]))
(map #(inner-rect state %)))
x (apply min (map :x shapes))
y (apply min (map :y shapes))
x' (apply max (map (fn [{:keys [x width]}] (+ x width)) shapes))
y' (apply max (map (fn [{:keys [y height]}] (+ y height)) shapes))
width (- x' x)
height (- y' y)
x (+ x dx)
y (+ y dy)]
(-> (merge shape {:width width :height height :x x :y y})
(apply-rotation-transformation))))
;; --- Transform Shape
(declare transform-rect)
(declare transform-circle)
(declare transform-path)
(defn transform
"Apply the matrix transformation to shape."
([shape xfmt] (transform @st/state shape xfmt))
([state {:keys [type] :as shape} xfmt]
(case type
:rect (transform-rect shape xfmt)
:icon (transform-rect shape xfmt)
:text (transform-rect shape xfmt)
:image (transform-rect shape xfmt)
:path (transform-path shape xfmt)
:circle (transform-circle shape xfmt))))
(defn- transform-rect
[{:keys [x1 y1] :as shape} mx]
(let [{:keys [width height]} (size shape)
tl (gpt/transform [x1 y1] mx)
tr (gpt/transform [(+ x1 width) y1] mx)
bl (gpt/transform [x1 (+ y1 height)] mx)
br (gpt/transform [(+ x1 width) (+ y1 height)] mx)
minx (apply min (map :x [tl tr bl br]))
maxx (apply max (map :x [tl tr bl br]))
miny (apply min (map :y [tl tr bl br]))
maxy (apply max (map :y [tl tr bl br]))]
(assoc shape
:x1 minx
:y1 miny
:x2 (+ minx (- maxx minx))
:y2 (+ miny (- maxy miny)))))
(defn- transform-circle
[{:keys [cx cy rx ry] :as shape} xfmt]
(let [{:keys [x1 y1 x2 y2]} (shape->rect-shape shape)
tl (gpt/transform [x1 y1] xfmt)
tr (gpt/transform [x2 y1] xfmt)
bl (gpt/transform [x1 y2] xfmt)
br (gpt/transform [x2 y2] xfmt)
x (apply min (map :x [tl tr bl br]))
y (apply min (map :y [tl tr bl br]))
maxx (apply max (map :x [tl tr bl br]))
maxy (apply max (map :y [tl tr bl br]))
width (- maxx x)
height (- maxy y)
cx (+ x (/ width 2))
cy (+ y (/ height 2))
rx (/ width 2)
ry (/ height 2)]
(assoc shape :cx cx :cy cy :rx rx :ry ry)))
(defn- transform-path
[{:keys [points] :as shape} xfmt]
(let [points (map #(gpt/transform % xfmt) points)]
(assoc shape :points points)))
;; --- Outer Rect
@@ -671,100 +747,6 @@
:x x
:y y}))
;; --- Transformation Matrix
(declare transformation-matrix-rect)
(declare transformation-matrix-text)
(declare transformation-matrix-circle)
(declare transformation-matrix-icon)
(declare transformation-matrix-path)
(declare transformation-matrix-group)
(defn transformation-matrix
([shape]
(transformation-matrix @st/state shape))
([state shape]
(case (:type shape)
:rect (transformation-matrix-rect state shape)
:text (transformation-matrix-text state shape)
:circle (transformation-matrix-circle state shape)
:icon (transformation-matrix-icon state shape)
:image (transformation-matrix-icon state shape)
:path (transformation-matrix-path state shape)
:group (transformation-matrix-group state shape))))
(defn- transformation-matrix-rect
[state {:keys [x1 y1 rotation] :or {rotation 0} :as shape}]
(let [{:keys [width height]} (size shape)
center-x (+ x1 (/ width 2))
center-y (+ y1 (/ height 2))]
(-> (gmt/matrix)
(gmt/translate center-x center-y)
(gmt/rotate rotation)
(gmt/translate (- center-x) (- center-y)))))
(defn- transformation-matrix-text
[state {:keys [x1 y1 rotation] :or {rotation 0} :as shape}]
(let [{:keys [width height]} (size shape)
center-x (+ x1 (/ width 2))
center-y (+ y1 (/ height 2))]
(-> (gmt/matrix)
(gmt/translate center-x center-y)
(gmt/rotate rotation)
(gmt/translate (- center-x) (- center-y)))))
(defn- transformation-matrix-icon
[state {:keys [x1 y1 rotation view-box] :or {rotation 0} :as shape}]
(let [{:keys [width height]} (size shape)
orig-width (nth view-box 2)
orig-height (nth view-box 3)
scale-x (/ width orig-width)
scale-y (/ height orig-height)
center-x (- width (/ width 2))
center-y (- height (/ height 2))]
(-> (gmt/matrix)
(gmt/translate x1 y1)
(gmt/translate center-x center-y)
(gmt/rotate rotation)
(gmt/translate (- center-x) (- center-y))
(gmt/scale scale-x scale-y))))
(defn- transformation-matrix-path
[state {:keys [x1 y1 rotation view-box] :or {rotation 0} :as shape}]
(let [{:keys [width height]} (size shape)
orig-width (nth view-box 2)
orig-height (nth view-box 3)
scale-x (/ width orig-width)
scale-y (/ height orig-height)
center-x (- width (/ width 2))
center-y (- height (/ height 2))]
(-> (gmt/matrix)
(gmt/translate x1 y1)
(gmt/translate center-x center-y)
(gmt/rotate rotation)
(gmt/translate (- center-x) (- center-y))
(gmt/scale scale-x scale-y))))
(defn- transformation-matrix-circle
[state {:keys [cx cy rx ry rotation] :or {rotation 0} :as shape}]
(-> (gmt/matrix)
(gmt/translate cx cy)
(gmt/rotate rotation)
(gmt/translate (- cx) (- cy))))
(defn- transformation-matrix-group
[state {:keys [dx dy rotation items] :or {rotation 0} :as shape}]
(let [shapes-by-id (get state :shapes)
shapes (map #(get shapes-by-id %) items)
{:keys [x y width height]} (outer-rect-coll shapes)
center-x (+ x (/ width 2))
center-y (+ y (/ height 2))]
(-> (gmt/matrix)
(gmt/translate (or dx 0) (or dy 0))
(gmt/translate center-x center-y)
(gmt/rotate rotation)
(gmt/translate (- center-x) (- center-y)))))
;; --- Helpers
(defn apply-rotation

View File

@@ -2,22 +2,23 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.auth.login
(:require [lentes.core :as l]
[cuerdas.core :as str]
[uxbox.util.router :as rt]
[uxbox.util.dom :as dom]
[potok.core :as ptk]
[uxbox.util.forms :as forms]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.store :as st]
[uxbox.main.data.auth :as da]
[uxbox.main.data.messages :as udm]
[uxbox.main.ui.icons :as i]
[uxbox.main.ui.messages :as uum]
[uxbox.main.ui.navigation :as nav]))
[uxbox.main.ui.navigation :as nav]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.router :as rt]
[uxbox.util.dom :as dom]
[uxbox.util.forms :as forms]))
(def form-data (forms/focus-data :login st/state))
(def set-value! (partial forms/set-value! :login))

View File

@@ -2,7 +2,8 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.auth.recovery
(:require [lentes.core :as l]

View File

@@ -2,7 +2,8 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.auth.recovery-request
(:require [lentes.core :as l]

View File

@@ -2,7 +2,8 @@
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.auth.register
(:require [lentes.core :as l]

View File

@@ -5,50 +5,39 @@
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main.ui.shapes.circle
(:require [sablono.core :refer-macros [html]]
[rum.core :as rum]
[lentes.core :as l]
[uxbox.util.mixins :as mx :include-macros true]
(:require [lentes.core :as l]
[uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.geom :as geom]))
[uxbox.main.geom :as geom]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt]
[uxbox.util.mixins :as mx :include-macros true]))
;; --- Circle Component
(declare circle-shape)
(defn- circle-component-render
[own shape]
(mx/defc circle-component
{:mixins [mx/reactive mx/static]}
[shape]
(let [{:keys [id x y width height group]} shape
selected (mx/react common/selected-ref)
selected? (contains? selected id)
on-mouse-down #(common/on-mouse-down % shape selected)]
(html
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down}
(circle-shape shape identity)])))
(def circle-component
(mx/component
{:render circle-component-render
:name "circle-component"
:mixins [mx/static mx/reactive]}))
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down}
(circle-shape shape identity)]))
;; --- Circle Shape
(defn- circle-shape-render
[own {:keys [id] :as shape}]
(let [key (str "shape-" id)
rfm (geom/transformation-matrix shape)
props (select-keys shape [:cx :cy :rx :ry])
attrs (-> (attrs/extract-style-attrs shape)
(merge {:id key :key key :transform (str rfm)})
(merge props))]
(html
[:ellipse attrs])))
(mx/defc circle-shape
{:mixins [mx/static]}
[{:keys [id tmp-resize-xform tmp-displacement] :as shape}]
(let [xfmt (cond-> (or tmp-resize-xform (gmt/matrix))
tmp-displacement (gmt/translate tmp-displacement))
(def circle-shape
(mx/component
{:render circle-shape-render
:name "circle-shape"
:mixins [mx/static]}))
props {:transform (str xfmt) :id (str id)}
attrs (merge props
(attrs/extract-style-attrs shape)
(select-keys shape [:cx :cy :rx :ry]))]
[:ellipse attrs]))

View File

@@ -10,11 +10,12 @@
[beicon.core :as rx]
[potok.core :as ptk]
[uxbox.store :as st]
[uxbox.main.geom :as geom]
[uxbox.main.data.shapes :as uds]
[uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.workspace.base :as wb]
[uxbox.util.geom.point :as gpt]
[uxbox.util.rlocks :as rlocks]
[uxbox.main.geom :as geom]
[uxbox.util.dom :as dom]))
;; --- Refs
@@ -36,13 +37,19 @@
(defn start-move
[]
(letfn [(on-start [shape]
(letfn [(on-move [shape delta]
(st/emit! (uds/apply-temporal-displacement shape delta)))
(on-stop [{:keys [id] :as shape}]
(rlocks/release! :shape/move)
(st/emit! (uds/apply-displacement shape)))
(on-start [shape]
(let [stoper (->> (rx/map first wb/events-s)
(rx/filter #(= % :mouse/up))
(rx/take 1))
stream (rx/take-until stoper wb/mouse-delta-s)
on-move #(st/emit! (uds/move-shape shape %))
on-stop #(rlocks/release! :shape/move)]
stream (->> wb/mouse-delta-s
(rx/take-until stoper))
on-move (partial on-move shape)
on-stop (partial on-stop shape)]
(when @wb/alignment-ref
(st/emit! (uds/initial-align-shape shape)))
(rx/subscribe stream on-move nil on-stop)))]

View File

@@ -7,7 +7,7 @@
(ns uxbox.main.ui.shapes.group
(:require [lentes.core :as l]
[uxbox.store :as st]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.main.geom :as geom]
[uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.ui.shapes.icon :as icon]
@@ -16,7 +16,9 @@
[uxbox.main.ui.shapes.text :as text]
[uxbox.main.ui.shapes.path :as path]
[uxbox.main.ui.shapes.image :as image]
[uxbox.main.geom :as geom]))
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.mixins :as mx :include-macros true]))
;; --- Helpers
@@ -64,12 +66,14 @@
(mx/defc group-shape
{:mixins [mx/static mx/reactive]}
[{:keys [items id dx dy rotation] :as shape} factory]
(let [key (str "shape-" id)
rfm (geom/transformation-matrix shape)
attrs (merge {:id key :key key :transform (str rfm)}
(attrs/extract-style-attrs shape)
(attrs/make-debug-attrs shape))]
[{:keys [id items tmp-resize-xform tmp-displacement] :as shape} factory]
(let [xfmt (cond-> (or tmp-resize-xform (gmt/matrix))
tmp-displacement (gmt/translate tmp-displacement))
props {:id (str id)
:transform (str xfmt)}
attrs (merge props (attrs/extract-style-attrs shape))]
[:g attrs
(for [item (reverse items)
:let [key (str item)]]

View File

@@ -5,10 +5,11 @@
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main.ui.shapes.icon
(:require [uxbox.util.mixins :as mx :include-macros true]
[uxbox.main.ui.shapes.common :as common]
(:require [uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.geom :as geom]))
[uxbox.main.geom :as geom]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.geom.matrix :as gmt]))
;; --- Icon Component
@@ -28,19 +29,30 @@
(mx/defc icon-shape
{:mixins [mx/static]}
[{:keys [x1 y1 content id metadata] :as shape} factory]
(let [key (str "shape-" id)
;; rfm (geom/transformation-matrix shape)
[shape]
(let [{:keys [x1 y1 content id metadata
width height
tmp-resize-xform
tmp-displacement]} (geom/size shape)
[_ _ orw orh] (:view-box metadata)
scalex (/ width orw)
scaley (/ height orh)
view-box (apply str (interpose " " (:view-box metadata)))
size (geom/size shape)
attrs (merge {:id key :key key ;; :transform (str rfm)
:x x1 :y y1 :view-box view-box
:preserve-aspect-ratio "none"
:dangerouslySetInnerHTML {:__html content}}
size
(attrs/extract-style-attrs shape)
(attrs/make-debug-attrs shape))]
[:svg attrs]))
xfmt (cond-> (or tmp-resize-xform (gmt/matrix))
tmp-displacement (gmt/translate tmp-displacement)
true (gmt/translate x1 y1)
true (gmt/scale scalex scaley))
props {:id (str id)
:preserve-aspect-ratio "none"
:dangerouslySetInnerHTML {:__html content}
:transform (str xfmt)}
attrs (merge props (attrs/extract-style-attrs shape))]
[:g attrs]))
;; --- Icon SVG
@@ -48,7 +60,7 @@
{:mixins [mx/static]}
[{:keys [content id metadata] :as shape}]
(let [view-box (apply str (interpose " " (:view-box metadata)))
id (str "icon-svg-" id)
props {:view-box view-box :id id
props {:view-box view-box
:id (str id)
:dangerouslySetInnerHTML {:__html content}}]
[:svg props]))

View File

@@ -7,14 +7,14 @@
(ns uxbox.main.ui.shapes.image
(:require [beicon.core :as rx]
[lentes.core :as l]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.http :as http]
[potok.core :as ptk]
[uxbox.store :as st]
[uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.data.images :as udi]
[uxbox.main.geom :as geom]))
[uxbox.main.geom :as geom]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.geom.matrix :as gmt]))
;; --- Refs
@@ -51,13 +51,22 @@
(mx/defc image-shape
{:mixins [mx/static]}
[{:keys [id x1 y1 image] :as shape}]
(let [key (str "shape-" id)
;; rfm (geom/transformation-matrix shape)
size (geom/size shape)
props {:x x1 :y y1 :id key :key key
[shape]
(let [{:keys [id x1 y1 image
width height
tmp-resize-xform
tmp-displacement]} (geom/size shape)
xfmt (cond-> (or tmp-resize-xform (gmt/matrix))
tmp-displacement (gmt/translate tmp-displacement))
props {:x x1 :y y1
:id (str id)
:preserve-aspect-ratio "none"
:xlink-href (:url image)}
attrs (-> (attrs/extract-style-attrs shape)
(merge props size))]
:xlink-href (:url image)
:transform (str xfmt)
:width width
:height height}
attrs (merge props (attrs/extract-style-attrs shape))]
[:image attrs]))

View File

@@ -5,13 +5,14 @@
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.main.ui.shapes.path
(:require [uxbox.util.mixins :as mx :include-macros true]
[potok.core :as ptk]
(:require [potok.core :as ptk]
[uxbox.store :as st]
[uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.main.data.shapes :as uds]
[uxbox.main.geom :as geom]))
[uxbox.main.geom :as geom]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.mixins :as mx :include-macros true]))
;; --- Path Component
@@ -45,11 +46,11 @@
(mx/defc path-shape
{:mixins [mx/static]}
[{:keys [id drawing?] :as shape}]
(let [key (str "shape-" id)
rfm (geom/transformation-matrix shape)
attrs (-> (attrs/extract-style-attrs shape)
(merge {:id key :key key :d (render-path shape)})
(merge (when-not drawing?
#_{:transform (str rfm)})))]
[{:keys [id tmp-resize-xform tmp-displacement] :as shape}]
(let [xfmt (cond-> (or tmp-resize-xform (gmt/matrix))
tmp-displacement (gmt/translate tmp-displacement))
props {:transform (str xfmt)
:id (str id)
:d (render-path shape)}
attrs (merge props (attrs/extract-style-attrs shape))]
[:path attrs]))

View File

@@ -7,8 +7,10 @@
(ns uxbox.main.ui.shapes.rect
(:require [uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.main.geom :as geom]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.dom :as dom]))
;; --- Rect Component
@@ -23,18 +25,26 @@
selected? (contains? selected id)
on-mouse-down #(common/on-mouse-down % shape selected)]
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down}
:on-mouse-down on-mouse-down
}
(rect-shape shape identity)]))
;; --- Rect Shape
(mx/defc rect-shape
{:mixins [mx/static]}
[{:keys [id x1 y1] :as shape}]
(let [key (str "shape-" id)
rfm (geom/transformation-matrix shape)
size (geom/size shape)
props {:x x1 :y y1 :id key :key key :transform (str rfm)}
attrs (-> (attrs/extract-style-attrs shape)
(merge props size))]
[shape]
(let [{:keys [id x1 y1 width height
tmp-resize-xform
tmp-displacement]} (geom/size shape)
xfmt (cond-> (or tmp-resize-xform (gmt/matrix))
tmp-displacement (gmt/translate tmp-displacement))
props {:x x1 :y y1 :id id
:width width
:height height
:transform (str xfmt)}
attrs (merge (attrs/extract-style-attrs shape) props)]
[:rect attrs]))

View File

@@ -9,14 +9,16 @@
"Multiple selection handlers component."
(:require [lentes.core :as l]
[beicon.core :as rx]
[uxbox.store :as st]
[uxbox.util.mixins :as mx :include-macros true]
[potok.core :as ptk]
[uxbox.store :as st]
[uxbox.main.constants :as c]
[uxbox.main.data.shapes :as uds]
[uxbox.main.ui.workspace.base :as wb]
[uxbox.util.rlocks :as rlocks]
[uxbox.main.ui.shapes.common :as scommon]
[uxbox.main.geom :as geom]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.rlocks :as rlocks]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom]))
@@ -41,115 +43,257 @@
(def edition-ref scommon/edition-ref)
(defn transform-rect
[{:keys [x1 y1 x2 y2] :as shape} xfmt]
(if xfmt
(let [tl (gpt/transform [x1 y1] xfmt)
tr (gpt/transform [x2 y1] xfmt)
bl (gpt/transform [x1 y2] xfmt)
br (gpt/transform [x2 y2] xfmt)
minx (apply min (map :x [tl tr bl br]))
maxx (apply max (map :x [tl tr bl br]))
miny (apply min (map :y [tl tr bl br]))
maxy (apply max (map :y [tl tr bl br]))]
(assoc shape
:x1 minx
:y1 miny
:x2 maxx
:y2 maxy))
shape))
;; --- Resize Implementation
(defn- start-resize
[vid sid]
(letfn [(on-resize [[delta ctrl?]]
(let [params {:vid vid :delta (assoc delta :lock ctrl?)}]
(st/emit! (uds/update-vertex-position sid params))))
[vid ids shape]
(letfn [(gen-matrix [shape {scalex :x scaley :y}]
(case vid
:top-left
(-> (gmt/matrix)
(gmt/translate (+ (:x2 shape))
(+ (:y2 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x2 shape))
(- (:y2 shape))))
:top-right
(-> (gmt/matrix)
(gmt/translate (+ (:x1 shape))
(+ (:y2 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x1 shape))
(- (:y2 shape))))
:top
(-> (gmt/matrix)
(gmt/translate (+ (:x1 shape))
(+ (:y2 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x1 shape))
(- (:y2 shape))))
:bottom-left
(-> (gmt/matrix)
(gmt/translate (+ (:x2 shape))
(+ (:y1 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x2 shape))
(- (:y1 shape))))
:bottom-right
(-> (gmt/matrix)
(gmt/translate (+ (:x1 shape))
(+ (:y1 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x1 shape))
(- (:y1 shape))))
:bottom
(-> (gmt/matrix)
(gmt/translate (+ (:x1 shape))
(+ (:y1 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x1 shape))
(- (:y1 shape))))
:right
(-> (gmt/matrix)
(gmt/translate (+ (:x1 shape))
(+ (:y1 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x1 shape))
(- (:y1 shape))))
:left
(-> (gmt/matrix)
(gmt/translate (+ (:x2 shape))
(+ (:y1 shape)))
(gmt/scale scalex scaley)
(gmt/translate (- (:x2 shape))
(- (:y1 shape))))
))
(on-resize [shape scale]
(let [mt (gen-matrix shape scale)
xf (map #(uds/apply-temporal-resize-matrix % mt))]
(apply st/emit! (sequence xf ids))))
(on-end []
(rlocks/release! :shape/resize))]
(apply st/emit! (map uds/apply-resize-matrix ids))
(rlocks/release! :shape/resize))
(calculate-ratio [orig-shape {:keys [width height] :as shape}]
{:x (/ width (:width orig-shape))
:y (/ height (:height orig-shape))})
(apply-delta [shape [{:keys [x y] :as point} ctrl?]]
(case vid
:top-left
(let [width (- (:x2 shape) x)
height (- (:y2 shape) y)
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
:top-right
(let [width (- x (:x1 shape))
height (- (:y2 shape) y)
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
:top
(let [width (- (:x2 shape) (:x1 shape))
height (- (:y2 shape) y)
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
:bottom-left
(let [width (- (:x2 shape) x)
height (- y (:y1 shape))
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
:bottom-right
(let [width (- x (:x1 shape))
height (- y (:y1 shape))
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
:bottom
(let [width (- (:x2 shape) (:x1 shape))
height (- y (:y1 shape))
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
:left
(let [width (- (:x2 shape) x)
height (- (:y2 shape) (:y1 shape))
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
:right
(let [width (- x (:x1 shape))
height (- (:y2 shape) (:y1 shape))
proportion (:proportion shape)]
(assoc shape
:width width
:height (if ctrl? (/ width proportion) height)))
))]
(let [stoper (->> wb/events-s
(rx/map first)
(rx/filter #(= % :mouse/up))
(rx/take 1))
stream (->> wb/mouse-delta-s
stream (->> wb/mouse-canvas-s
(rx/map #(gpt/divide % @wb/zoom-ref))
(rx/mapcat (fn [point]
(if @wb/alignment-ref
(uds/align-point point)
(rx/of point))))
(rx/take-until stoper)
(rx/with-latest-from vector wb/mouse-ctrl-s))]
(rx/with-latest-from vector wb/mouse-ctrl-s)
(rx/scan apply-delta shape)
(rx/map (partial calculate-ratio shape)))]
(rlocks/acquire! :shape/resize)
(when @wb/alignment-ref
(st/emit! (uds/initial-vertext-align sid vid)))
(rx/subscribe stream on-resize nil on-end))))
(rx/subscribe stream
(partial on-resize shape)
nil
on-end))))
;; --- Controls (Component)
(mx/defc controls
{:mixins [mx/static]}
[{:keys [width height x1 y1]} zoom on-mouse-down]
[:g.controls
[:rect.main {:x x1 :y y1
:width width
:height height
:stroke-dasharray (str (/ 5.0 zoom) "," (/ 5 zoom))
:style {:stroke "#333" :fill "transparent"
:stroke-opacity "1"}}]
[:circle.top
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :top %)
:r (/ 6.0 zoom)
:cx (+ x1 (/ width 2))
:cy (- y1 2)})]
[:circle.right
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :right %)
:r (/ 6.0 zoom)
:cy (+ y1 (/ height 2))
:cx (+ x1 width 1)})]
[:circle.bottom
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :bottom %)
:r (/ 6.0 zoom)
:cx (+ x1 (/ width 2))
:cy (+ y1 height 2)})]
[:circle.left
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :left %)
:r (/ 6.0 zoom)
:cy (+ y1 (/ height 2))
:cx (- x1 3)})]
[:circle.top-left
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :top-left %)
:r (/ 6.0 zoom)
:cx x1
:cy y1})]
[:circle.top-right
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :top-right %)
:r (/ 6.0 zoom)
:cx (+ x1 width)
:cy y1})]
[:circle.bottom-left
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :bottom-left %)
:r (/ 6.0 zoom)
:cx x1
:cy (+ y1 height)})]
[:circle.bottom-right
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :bottom-right %)
:r (/ 6.0 zoom)
:cx (+ x1 width)
:cy (+ y1 height)})]])
;; --- Selection Handlers (Component)
(mx/defc multiple-selection-handlers
[shapes]
(let [{:keys [width height x y]} (geom/outer-rect-coll shapes)]
[:g.controls
[:rect.main {:x x :y y
:width width
:height height
:stroke-dasharray "5,5"
:style {:stroke "#333" :fill "transparent"
:stroke-opacity "1"}}]]))
(mx/defc single-not-editable-selection-handlers
[{:keys [id] :as shape} zoom]
(let [{:keys [width height x y]} (geom/outer-rect shape)]
[:g.controls
[:rect.main {:x x :y y
:width width
:height height
:stroke-dasharray (str (/ 5.0 zoom) "," (/ 5.0 zoom))
:style {:stroke "#333"
:fill "transparent"
:stroke-opacity "1"}}]]))
(mx/defc single-selection-handlers
[{:keys [id] :as shape} zoom]
(letfn [(on-mouse-down [vid event]
(dom/stop-propagation event)
(start-resize vid id))]
(let [{:keys [x y width height]} (geom/outer-rect shape)]
[:g.controls
[:rect.main {:x x :y y
:width width
:height height
:stroke-dasharray (str (/ 5.0 zoom) "," (/ 5.0 zoom))
:style {:stroke "#333"
:fill "transparent"
:stroke-opacity "1"}}]
[:circle.top
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :top %)
:r (/ 6.0 zoom)
:cx (+ x (/ width 2))
:cy (- y 2)})]
[:circle.right
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :right %)
:r (/ 6.0 zoom)
:cy (+ y (/ height 2))
:cx (+ x width 1)})]
[:circle.bottom
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :bottom %)
:r (/ 6.0 zoom)
:cx (+ x (/ width 2))
:cy (+ y height 2)})]
[:circle.left
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :left %)
:r (/ 6.0 zoom)
:cy (+ y (/ height 2))
:cx (- x 3)})]
[:circle.top-left
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :top-left %)
:r (/ 6.0 zoom)
:cx x
:cy y})]
[:circle.top-right
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :top-right %)
:r (/ 6.0 zoom)
:cx (+ x width)
:cy y})]
[:circle.bottom-left
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :bottom-left %)
:r (/ 6.0 zoom)
:cx x
:cy (+ y height)})]
[:circle.bottom-right
(merge +circle-props+
{:on-mouse-down #(on-mouse-down :bottom-right %)
:r (/ 6.0 zoom)
:cx (+ x width)
:cy (+ y height)})]])))
(defn start-path-edition
[shape-id index]
(letfn [(on-move [delta]
@@ -181,6 +325,43 @@
:stroke "#28c4d4"
:style {:cursor "pointer"}}])]))
(mx/defc multiple-selection-handlers
{:mixins [mx/static]}
[[shape & rest :as shapes] zoom]
(let [resize-xf (:tmp-resize-xform shape (gmt/matrix))
displc-xf (-> (:tmp-displacement shape (gpt/point 0 0))
(gmt/translate-matrix))
selection (-> (geom/shapes->rect-shape shapes)
(assoc :type :rect)
(geom/transform resize-xf)
(geom/transform displc-xf)
(geom/size))
on-click #(do (dom/stop-propagation %2)
(start-resize %1 (map :id shapes) selection))]
;; (println "single-selection-handlers" displc-xf)
;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :x2 :y2]))
;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :width :height]))
(controls selection zoom on-click)))
(mx/defc single-selection-handlers
{:mixins [mx/static]}
[{:keys [id] :as shape} zoom]
(let [resize-xf (:tmp-resize-xform shape (gmt/matrix))
displc-xf (-> (:tmp-displacement shape (gpt/point 0 0))
(gmt/translate-matrix))
selection (-> (geom/shape->rect-shape shape)
;; (transform-rect resize-xf)
(assoc :type :rect)
(geom/transform resize-xf)
(geom/transform displc-xf)
(geom/size))
on-click #(do (dom/stop-propagation %2)
(start-resize %1 #{id} selection))]
;; (println "single-selection-handlers" displc-xf)
;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :x2 :y2]))
;; (println "single-selection-handlers" (select-keys selection [:x1 :y1 :width :height]))
(controls selection zoom on-click)))
(mx/defc selection-handlers
{:mixins [mx/reactive mx/static]}
[]
@@ -196,20 +377,10 @@
(> shapes-num 1)
(multiple-selection-handlers shapes zoom)
(= :path (:type shape))
(if (= @edition-ref (:id shape))
(path-edition-selection-handlers shape zoom)
(single-selection-handlers shape zoom))
:else
(cond
(= :path (:type shape))
(if (= @edition-ref (:id shape))
(path-edition-selection-handlers shape zoom)
(single-not-editable-selection-handlers shape zoom))
(= :text (:type shape))
(if (= @edition-ref (:id shape))
(single-not-editable-selection-handlers shape zoom)
(single-selection-handlers (first shapes) zoom))
(= :group (:type shape))
(single-not-editable-selection-handlers shape zoom)
:else
(single-selection-handlers (first shapes) zoom)))))
(single-selection-handlers shape zoom))))

View File

@@ -9,15 +9,16 @@
[lentes.core :as l]
[goog.events :as events]
[potok.core :as ptk]
[uxbox.util.mixins :as mx :include-macros true]
[uxbox.util.color :as color]
[uxbox.util.dom :as dom]
[uxbox.store :as st]
[uxbox.main.geom :as geom]
[uxbox.main.data.shapes :as uds]
[uxbox.main.ui.shapes.common :as common]
[uxbox.main.ui.shapes.attrs :as attrs]
[uxbox.util.color :as color]
[uxbox.util.dom :as dom]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.rlocks :as rlocks]
[uxbox.main.geom :as geom])
[uxbox.util.mixins :as mx :include-macros true])
(:import goog.events.EventType))
;; --- Events
@@ -106,8 +107,8 @@
[{:keys [id x1 y1 content] :as shape}]
(let [size (geom/size shape)
style (make-style shape)
rfm (geom/transformation-matrix shape)
props {:x x1 :y y1 :transform (str rfm)}
;; rfm (geom/transformation-matrix shape)
props {:x x1 :y y1} ;; :transform (str rfm)}
props (merge props size)]
(letfn [#_(on-blur [ev]
(rlocks/release! :ui/text-edit)
@@ -126,15 +127,38 @@
;; --- Text Shape
;; NOTE: this is a hack for the browser rendering.
;;
;; Without forcing rerender, when the shape is displaced
;; and only x and y attrs are updated in dom, the whole content
;; of the foreignObject becomes sometimes partially or
;; completelly invisible. The complete dom rerender fixes that
;; problem.
(defn- text-shape-did-update
[own]
(let [pref (mx/ref-node own "fo")
html (.-innerHTML pref)]
(set! (.-innerHTML pref) html)
own))
(mx/defc text-shape
{:mixins [mx/static]}
[{:keys [id x1 y1 content] :as shape}]
(let [key (str "shape-" id)
rfm (geom/transformation-matrix shape)
size (geom/size shape)
props {:x x1 :y y1
:transform (str rfm)}
attrs (merge props size)
style (make-style shape)]
[:foreignObject attrs
[:p {:style style} content]]))
{:mixins [mx/static]
:did-update text-shape-did-update}
[{:keys [tmp-resize-xform] :as shape}]
(let [shape (cond-> (geom/size shape)
tmp-resize-xform (geom/transform shape tmp-resize-xform))
{:keys [id x1 y1 content
width height
tmp-displacement]} (geom/size shape)
xfmt (cond-> (gmt/matrix)
tmp-displacement (gmt/translate tmp-displacement))
style (make-style shape)
props {:x x1 :y y1 :id (str id) :ref "fo"
:width width :height height
:transform (str xfmt)}]
[:foreignObject props
[:p {:ref "p" :style style} content]]))

View File

@@ -44,63 +44,7 @@
(let [[a b c d tx ty] v]
(Matrix. a b c d tx ty))))
(defn ^boolean matrix?
"Return true if `v` is Matrix instance."
[v]
(instance? Matrix v))
(defn matrix
"Create a new matrix instance."
([]
(Matrix. 1 0 0 1 0 0))
([v]
(-matrix v))
([a b c d tx ty]
(Matrix. a b c d tx ty)))
(defn rotate
"Apply rotation transformation to the matrix."
([m angle]
(let [center (gpt/point 0 0)]
(rotate m angle center)))
([m angle center]
(let [angle (mth/radians angle)
x (:x center)
y (:y center)
cos (mth/cos angle)
sin (mth/sin angle)
nsin (- sin)
tx (- x (+ (* x cos)) (* y sin))
ty (- y (- (* x sin)) (* y cos))
a (+ (* cos (:a m)) (* sin (:b m)))
b (+ (* nsin (:a m)) (* cos (:b m)))
c (+ (* cos (:c m)) (* sin (:d m)))
d (+ (* nsin (:c m)) (* cos (:d m)))
tx' (+ (:tx m) (* tx (:a m)) (* ty (:b m)))
ty' (+ (:ty m) (* tx (:c m)) (* ty (:d m)))]
(Matrix. a b c d tx' ty'))))
(defn scale
"Apply scale transformation to the matrix."
([m v] (scale m v v))
([m x y]
(assoc m
:a (* (:a m) x)
:c (* (:c m) x)
:b (* (:b m) y)
:d (* (:d m) y))))
(defn translate
"Apply translate transformation to the matrix."
([m pt]
(let [pt (gpt/-point pt)]
(assoc m
:tx (+ (:tx m) (* (:x pt) (:a m)) (* (:y pt) (:b m)))
:ty (+ (:ty m) (* (:x pt) (:c m)) (* (:y pt) (:d m))))))
([m x y]
(translate m (gpt/point x y))))
(defn append
(defn multiply
([m om]
(let [a1 (:a m)
b1 (:b m)
@@ -122,7 +66,101 @@
(+ tx1 (* tx2 a1) (* ty2 b1))
(+ ty1 (* tx2 c1) (* ty2 d1)))))
([m om & others]
(reduce append (append m om) others)))
(reduce multiply (multiply m om) others)))
(defn ^boolean matrix?
"Return true if `v` is Matrix instance."
[v]
(instance? Matrix v))
(defn matrix
"Create a new matrix instance."
([]
(Matrix. 1 0 0 1 0 0))
([v]
(-matrix v))
([a b c d tx ty]
(Matrix. a b c d tx ty)))
(defn translate-matrix
([pt]
(let [pt (gpt/-point pt)]
(Matrix. 1 0 0 1 (:x pt) (:y pt))))
([x y]
(translate-matrix (gpt/point x y))))
(defn scale-matrix
([s]
(Matrix. s 0 0 s 0 0))
([sx sy]
(Matrix. sx 0 0 sy 0 0)))
(defn rotate-matrix
[a]
(let [a (mth/radians a)]
(Matrix. (mth/cos a)
(mth/sin a)
(- (mth/sin a))
(mth/cos a)
0 0)))
(defn rotate
"Apply rotation transformation to the matrix."
([m angle]
(multiply m (rotate-matrix angle)))
([m angle center]
(multiply m
(translate-matrix center)
(rotate-matrix angle)
(translate-matrix (gpt/negate center)))))
;; ([m angle]
;; (let [center (gpt/point 0 0)]
;; (rotate m angle center)))
;; ([m angle center]
;; (let [angle (mth/radians angle)
;; x (:x center)
;; y (:y center)
;; cos (mth/cos angle)
;; sin (mth/sin angle)
;; nsin (- sin)
;; tx (- x (+ (* x cos)) (* y sin))
;; ty (- y (- (* x sin)) (* y cos))
;; a (+ (* cos (:a m)) (* sin (:b m)))
;; b (+ (* nsin (:a m)) (* cos (:b m)))
;; c (+ (* cos (:c m)) (* sin (:d m)))
;; d (+ (* nsin (:c m)) (* cos (:d m)))
;; tx' (+ (:tx m) (* tx (:a m)) (* ty (:b m)))
;; ty' (+ (:ty m) (* tx (:c m)) (* ty (:d m)))]
;; (Matrix. a b c d tx' ty'))))
(defn scale
"Apply scale transformation to the matrix."
([m v] (scale m v v))
([m vx vy] (multiply m (scale-matrix vx vy))))
;; ([m v] (scale m v v))
;; ([m x y]
;; (assoc m
;; :a (* (:a m) x)
;; :c (* (:c m) x)
;; :b (* (:b m) y)
;; :d (* (:d m) y))))
(defn translate
"Apply translate transformation to the matrix."
([m pt]
(multiply m (translate-matrix pt)))
([m x y]
(translate m (gpt/point x y))))
;; ([m pt]
;; (let [pt (gpt/-point pt)]
;; (assoc m
;; :tx (+ (:tx m) (* (:x pt) (:a m)) (* (:y pt) (:b m)))
;; :ty (+ (:ty m) (* (:x pt) (:c m)) (* (:y pt) (:d m))))))
;; ([m x y]
;; (translate m (gpt/point x y))))
(defn ^boolean invertible?
[{:keys [a b c d tx ty] :as m}]

View File

@@ -94,6 +94,12 @@
(Point. (/ (:x p) (:x other))
(/ (:y p) (:y other)))))
(defn negate
[p]
{:pre [(point? p)]}
(let [{:keys [x y]} (-point p)]
(Point. (- x) (- y))))
(defn distance
"Calculate the distance between two points."
[p other]
@@ -161,7 +167,7 @@
(defn transform
"Transform a point applying a matrix transfomation."
[{:keys [x y] :as p} {:keys [a b c d tx ty] :as m}]
(Point. (+ (* x a) (* y c) tx)
(+ (* x b) (* y d) ty)))
[pt {:keys [a b c d tx ty] :as m}]
(let [{:keys [x y]} (point pt)]
(Point. (+ (* x a) (* y c) tx)
(+ (* x b) (* y d) ty))))

View File

@@ -10,6 +10,7 @@
[com.cognitect.transit :as tr]
[uxbox.util.data :refer (parse-int)]
[uxbox.util.geom.point :as gpt]
[uxbox.util.geom.matrix :as gmt]
[uxbox.util.datetime :as dt]))
;; --- Transit Handlers
@@ -34,13 +35,25 @@
(gpt/point (vec value))
(gpt/map->Point value)))))
(def matrix-write-handler
(t/write-handler
(constantly "matrix")
(fn [v] (into {} v))))
(def matrix-read-handler
(t/read-handler
(fn [value]
(gmt/map->Matrix value))))
(def ^:privare +read-handlers+
{"u" uuid
"m" datetime-read-handler
"matrix" matrix-read-handler
"point" point-read-handler})
(def ^:privare +write-handlers+
{dt/DateTime datetime-write-handler
gmt/Matrix matrix-write-handler
gpt/Point point-write-handler})
;; --- Public Api
@@ -52,5 +65,10 @@
(defn encode
[data]
(let [w (t/writer :json {:handlers +write-handlers+})]
(t/write w data)))
(try
(let [w (t/writer :json {:handlers +write-handlers+})]
(t/write w data))
(catch :default e
(println "data:" data)
(throw e))))

View File

@@ -116,7 +116,7 @@
[{:keys [x1 y1 rotation] :as shape}
{:keys [resize-width resize-height easing
element delay duration direction] :as opts}]
(if (= direction :reverse)
#_(if (= direction :reverse)
(let [end (geom/transformation-matrix shape)]
(animate :targets [(str "#shape-" element)]
:transform (str end)
@@ -165,7 +165,7 @@
(defn- run-rotate-interaction
[{:keys [element rotation direction easing delay duration] :as opts}]
(let [shape (get-in @st/state [:shapes element])
#_(let [shape (get-in @st/state [:shapes element])
dom (dom/get-element (str "shape-" element))
mtx1 (geom/transformation-matrix (update shape :rotation + rotation))
mtx2 (geom/transformation-matrix shape)]

View File

@@ -52,15 +52,15 @@
{:pre [(map? shape)]}
(let [show-itx? (and (mx/react itx-flag-ref)
(not (empty? (:interactions shape))))
rect (geom/inner-rect shape)]
rect (geom/shape->rect-shape shape)]
[:g {:id (str "itx-" (:id shape))
:style (when show-itx?
{:cursor "pointer"})}
(factory shape)
(when show-itx?
[:circle {:fill "#78dbbe"
:cx (:x rect)
:cy (:y rect)
:cx (:x1 rect)
:cy (:y1 rect)
:r 5}])]))
;; --- Shapes