mirror of
https://github.com/penpot/penpot.git
synced 2026-03-12 21:36:39 +00:00
Merge branch 'resize-refactor'
This commit is contained in:
@@ -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))
|
||||
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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)))]
|
||||
|
||||
@@ -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)]]
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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]))
|
||||
|
||||
@@ -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))))
|
||||
|
||||
@@ -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]]))
|
||||
|
||||
@@ -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}]
|
||||
|
||||
@@ -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))))
|
||||
|
||||
@@ -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))))
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user