mirror of
https://github.com/penpot/penpot.git
synced 2025-05-11 15:46:38 +02:00
✨ Fix problems with extreme values
This commit is contained in:
parent
999af63118
commit
ed9400912c
59 changed files with 359 additions and 340 deletions
|
@ -108,10 +108,13 @@
|
|||
(= v base))
|
||||
|
||||
(defn translate-matrix
|
||||
[{x :x y :y :as pt}]
|
||||
([{x :x y :y :as pt}]
|
||||
(assert (gpt/point? pt))
|
||||
(Matrix. 1 0 0 1 x y))
|
||||
|
||||
([x y]
|
||||
(translate-matrix (gpt/point x y))))
|
||||
|
||||
(defn scale-matrix
|
||||
([pt center]
|
||||
(multiply (translate-matrix center)
|
||||
|
|
|
@ -132,9 +132,8 @@
|
|||
(assert (point? other))
|
||||
(let [dx (- x ox)
|
||||
dy (- y oy)]
|
||||
(-> (mth/sqrt (+ (mth/pow dx 2)
|
||||
(mth/pow dy 2)))
|
||||
(mth/precision 6))))
|
||||
(mth/sqrt (+ (mth/pow dx 2)
|
||||
(mth/pow dy 2)))))
|
||||
|
||||
(defn length
|
||||
[{x :x y :y :as p}]
|
||||
|
@ -168,8 +167,7 @@
|
|||
(* y oy))
|
||||
(* length-p length-other))
|
||||
a (mth/acos (if (< a -1) -1 (if (> a 1) 1 a)))
|
||||
d (-> (mth/degrees a)
|
||||
(mth/precision 6))]
|
||||
d (mth/degrees a)]
|
||||
(if (mth/nan? d) 0 d)))))
|
||||
|
||||
(defn angle-sign [v1 v2]
|
||||
|
@ -195,7 +193,9 @@
|
|||
|
||||
(defn round
|
||||
"Change the precision of the point coordinates."
|
||||
([point] (round point 0))
|
||||
([point]
|
||||
(round point 0))
|
||||
|
||||
([{:keys [x y] :as p} decimals]
|
||||
(assert (point? p))
|
||||
(assert (number? decimals))
|
||||
|
|
|
@ -106,12 +106,12 @@
|
|||
:width (- x2 x1)
|
||||
:height (- y2 y1)
|
||||
:type :rect}))
|
||||
{frame-x1 :x1 frame-x2 :x2 frame-y1 :y1 frame-y2 :y2} bounds
|
||||
{bound-x1 :x1 bound-x2 :x2 bound-y1 :y1 bound-y2 :y2} bounds
|
||||
{sr-x1 :x1 sr-x2 :x2 sr-y1 :y1 sr-y2 :y2} selrect]
|
||||
{:left (make-selrect frame-x1 sr-y1 (- sr-x1 2) sr-y2)
|
||||
:top (make-selrect sr-x1 frame-y1 sr-x2 (- sr-y1 2))
|
||||
:right (make-selrect (+ sr-x2 2) sr-y1 frame-x2 sr-y2)
|
||||
:bottom (make-selrect sr-x1 (+ sr-y2 2) sr-x2 frame-y2)}))
|
||||
{:left (make-selrect bound-x1 sr-y1 sr-x1 sr-y2)
|
||||
:top (make-selrect sr-x1 bound-y1 sr-x2 sr-y1)
|
||||
:right (make-selrect sr-x2 sr-y1 bound-x2 sr-y2)
|
||||
:bottom (make-selrect sr-x1 sr-y2 sr-x2 bound-y2)}))
|
||||
|
||||
(defn distance-selrect [selrect other]
|
||||
(let [{:keys [x1 y1]} other
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
(ns app.common.geom.shapes.common
|
||||
(:require
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.math :as mth]))
|
||||
[app.common.geom.point :as gpt]))
|
||||
|
||||
(defn center-rect
|
||||
[{:keys [x y width height]}]
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.common.geom.shapes.rect
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.math :as mth]))
|
||||
|
||||
(defn rect->points [{:keys [x y width height]}]
|
||||
|
@ -130,10 +129,3 @@
|
|||
(>= (:y1 sr2) (:y1 sr1))
|
||||
(<= (:y2 sr2) (:y2 sr1))))
|
||||
|
||||
(defn round-selrect
|
||||
[selrect]
|
||||
(-> selrect
|
||||
(update :x mth/round)
|
||||
(update :y mth/round)
|
||||
(update :width mth/round)
|
||||
(update :height mth/round)))
|
||||
|
|
|
@ -249,8 +249,8 @@
|
|||
|
||||
;; This rectangle is the new data for the current rectangle. We want to change our rectangle
|
||||
;; to have this width, height, x, y
|
||||
new-width (max 1 (:width points-temp-dim))
|
||||
new-height (max 1 (:height points-temp-dim))
|
||||
new-width (max 0.01 (:width points-temp-dim))
|
||||
new-height (max 0.01 (:height points-temp-dim))
|
||||
selrect (gco/make-centered-selrect center new-width new-height)
|
||||
|
||||
rect-points (gpr/rect->points selrect)
|
||||
|
@ -263,7 +263,7 @@
|
|||
(defn- apply-transform
|
||||
"Given a new set of points transformed, set up the rectangle so it keeps
|
||||
its properties. We adjust de x,y,width,height and create a custom transform"
|
||||
[shape transform-mtx round-coords?]
|
||||
[shape transform-mtx]
|
||||
|
||||
(let [points' (:points shape)
|
||||
points (gco/transform-points points' transform-mtx)
|
||||
|
@ -276,8 +276,8 @@
|
|||
[(gpr/points->selrect points) nil nil]
|
||||
(adjust-rotated-transform shape points))
|
||||
|
||||
selrect (cond-> selrect
|
||||
round-coords? gpr/round-selrect)
|
||||
;;selrect (cond-> selrect
|
||||
;; round-coords? gpr/round-selrect)
|
||||
|
||||
;; Redondear los points?
|
||||
base-rotation (or (:rotation shape) 0)
|
||||
|
@ -345,7 +345,7 @@
|
|||
;; need to remove the flip flags
|
||||
(assoc :flip-x false)
|
||||
(assoc :flip-y false)
|
||||
(apply-transform (gmt/matrix) true))))
|
||||
(apply-transform (gmt/matrix)))))
|
||||
|
||||
(defn update-mask-selrect
|
||||
[masked-group children]
|
||||
|
@ -525,7 +525,6 @@
|
|||
(d/parse-double)
|
||||
(* (get-in modifiers [:resize-vector :x] 1))
|
||||
(* (get-in modifiers [:resize-vector-2 :x] 1))
|
||||
(mth/precision 2)
|
||||
(str))]
|
||||
(attrs/merge attrs {:font-size font-size})))]
|
||||
(update shape :content #(txt/transform-nodes
|
||||
|
@ -535,16 +534,13 @@
|
|||
shape))
|
||||
|
||||
(defn apply-modifiers
|
||||
[shape modifiers round-coords?]
|
||||
[shape modifiers]
|
||||
(let [center (gco/center-shape shape)
|
||||
transform (modifiers->transform center modifiers)]
|
||||
(apply-transform shape transform round-coords?)))
|
||||
(apply-transform shape transform)))
|
||||
|
||||
(defn transform-shape
|
||||
([shape]
|
||||
(transform-shape shape nil))
|
||||
|
||||
([shape {:keys [round-coords?] :or {round-coords? true}}]
|
||||
[shape]
|
||||
(let [modifiers (:modifiers shape)]
|
||||
(cond
|
||||
(nil? modifiers)
|
||||
|
@ -559,11 +555,11 @@
|
|||
(cond-> shape
|
||||
(not (empty-modifiers? modifiers))
|
||||
(-> (set-flip modifiers)
|
||||
(apply-modifiers modifiers round-coords?)
|
||||
(apply-modifiers modifiers)
|
||||
(apply-text-resize modifiers))
|
||||
|
||||
:always
|
||||
(dissoc :modifiers)))))))
|
||||
(dissoc :modifiers))))))
|
||||
|
||||
(defn transform-selrect
|
||||
[selrect {:keys [displacement resize-transform-inverse resize-vector resize-origin resize-vector-2 resize-origin-2]}]
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
|
||||
(defn precision
|
||||
[v n]
|
||||
(when (and (number? v) (number? n))
|
||||
(when (and (number? v) (integer? n))
|
||||
(let [d (pow 10 n)]
|
||||
(/ (round (* v d)) d))))
|
||||
|
||||
|
@ -165,3 +165,7 @@
|
|||
[v0 v1 t]
|
||||
(+ (* (- 1 t) v0)
|
||||
(* t v1)))
|
||||
|
||||
(defn max-abs
|
||||
[a b]
|
||||
(max (abs a) (abs b)))
|
||||
|
|
|
@ -91,8 +91,8 @@
|
|||
(def empty-selrect
|
||||
{:x 0 :y 0
|
||||
:x1 0 :y1 0
|
||||
:x2 1 :y2 1
|
||||
:width 1 :height 1})
|
||||
:x2 0.01 :y2 0.01
|
||||
:width 0.01 :height 0.01})
|
||||
|
||||
(defn make-minimal-shape
|
||||
[type]
|
||||
|
@ -111,16 +111,16 @@
|
|||
(not= :path (:type shape))
|
||||
(assoc :x 0
|
||||
:y 0
|
||||
:width 1
|
||||
:height 1
|
||||
:width 0.01
|
||||
:height 0.01
|
||||
:selrect {:x 0
|
||||
:y 0
|
||||
:x1 0
|
||||
:y1 0
|
||||
:x2 1
|
||||
:y2 1
|
||||
:width 1
|
||||
:height 1}))))
|
||||
:x2 0.01
|
||||
:y2 0.01
|
||||
:width 0.01
|
||||
:height 0.01}))))
|
||||
|
||||
(defn make-minimal-group
|
||||
[frame-id selection-rect group-name]
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :refer [close?]]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages :refer [make-minimal-shape]]
|
||||
[clojure.test :as t]))
|
||||
|
||||
|
@ -52,7 +52,7 @@
|
|||
(t/testing "Shape without modifiers should stay the same"
|
||||
(t/are [type]
|
||||
(let [shape-before (create-test-shape type)
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(= shape-before shape-after))
|
||||
|
||||
:rect :path))
|
||||
|
@ -61,7 +61,7 @@
|
|||
(t/are [type]
|
||||
(let [modifiers {:displacement (gmt/translate-matrix (gpt/point 10 -10))}]
|
||||
(let [shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/is (not= shape-before shape-after))
|
||||
|
||||
(t/is (close? (get-in shape-before [:selrect :x])
|
||||
|
@ -82,7 +82,7 @@
|
|||
(t/are [type]
|
||||
(let [modifiers {:displacement (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/are [prop]
|
||||
(t/is (close? (get-in shape-before [:selrect prop])
|
||||
(get-in shape-after [:selrect prop])))
|
||||
|
@ -95,7 +95,7 @@
|
|||
:resize-vector (gpt/point 2 2)
|
||||
:resize-transform (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/is (not= shape-before shape-after))
|
||||
|
||||
(t/is (close? (get-in shape-before [:selrect :x])
|
||||
|
@ -117,7 +117,7 @@
|
|||
:resize-vector (gpt/point 1 1)
|
||||
:resize-transform (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/are [prop]
|
||||
(t/is (close? (get-in shape-before [:selrect prop])
|
||||
(get-in shape-after [:selrect prop])))
|
||||
|
@ -130,7 +130,7 @@
|
|||
:resize-vector (gpt/point 0 0)
|
||||
:resize-transform (gmt/matrix)}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/is (> (get-in shape-before [:selrect :width])
|
||||
(get-in shape-after [:selrect :width])))
|
||||
(t/is (> (get-in shape-after [:selrect :width]) 0))
|
||||
|
@ -144,7 +144,7 @@
|
|||
(t/are [type]
|
||||
(let [modifiers {:rotation 30}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
|
||||
(t/is (not= shape-before shape-after))
|
||||
|
||||
|
@ -168,7 +168,7 @@
|
|||
(t/are [type]
|
||||
(let [modifiers {:rotation 0}
|
||||
shape-before (create-test-shape type {:modifiers modifiers})
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(t/are [prop]
|
||||
(t/is (close? (get-in shape-before [:selrect prop])
|
||||
(get-in shape-after [:selrect prop])))
|
||||
|
@ -180,7 +180,7 @@
|
|||
(let [modifiers {:displacement (gmt/matrix)}
|
||||
shape-before (-> (create-test-shape type {:modifiers modifiers})
|
||||
(assoc :selrect selrect))
|
||||
shape-after (gsh/transform-shape shape-before {:round-coords? false})]
|
||||
shape-after (gsh/transform-shape shape-before)]
|
||||
(= (:selrect shape-before)
|
||||
(:selrect shape-after)))
|
||||
|
||||
|
|
|
@ -241,12 +241,13 @@ $height-palette-max: 80px;
|
|||
position: relative;
|
||||
|
||||
.viewport-overlays {
|
||||
cursor: initial;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
cursor: initial;
|
||||
|
||||
.pixel-overlay {
|
||||
height: 100%;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns app.main.data.workspace.comments
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.common.spec :as us]
|
||||
[app.main.data.comments :as dcm]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -78,8 +77,8 @@
|
|||
(fn [{:keys [vbox zoom] :as local}]
|
||||
(let [pw (/ 160 zoom)
|
||||
ph (/ 160 zoom)
|
||||
nw (mth/round (- (/ (:width vbox) 2) pw))
|
||||
nh (mth/round (- (/ (:height vbox) 2) ph))
|
||||
nw (- (/ (:width vbox) 2) pw)
|
||||
nh (- (/ (:height vbox) 2) ph)
|
||||
nx (- (:x position) nw)
|
||||
ny (- (:y position) nh)]
|
||||
(update local :vbox assoc :x nx :y ny)))))))
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
shapev (gpt/point width height)
|
||||
deltav (gpt/to-vec initial point)
|
||||
scalev (-> (gpt/divide (gpt/add shapev deltav) shapev)
|
||||
(update :x truncate-zero 1)
|
||||
(update :y truncate-zero 1))
|
||||
(update :x truncate-zero 0.01)
|
||||
(update :y truncate-zero 0.01))
|
||||
scalev (if lock?
|
||||
(let [v (max (:x scalev) (:y scalev))]
|
||||
(gpt/point v v))
|
||||
|
@ -45,9 +45,7 @@
|
|||
(defn move-drawing
|
||||
[{:keys [x y]}]
|
||||
(fn [state]
|
||||
(let [x (mth/precision x 0)
|
||||
y (mth/precision y 0)]
|
||||
(update-in state [:workspace-drawing :object] gsh/absolute-move (gpt/point x y)))))
|
||||
(update-in state [:workspace-drawing :object] gsh/absolute-move (gpt/point x y))))
|
||||
|
||||
(defn handle-drawing-box []
|
||||
(ptk/reify ::handle-drawing-box
|
||||
|
@ -72,7 +70,7 @@
|
|||
|
||||
shape (-> state
|
||||
(get-in [:workspace-drawing :object])
|
||||
(gsh/setup {:x (:x initial) :y (:y initial) :width 1 :height 1})
|
||||
(gsh/setup {:x (:x initial) :y (:y initial) :width 0.01 :height 0.01})
|
||||
(assoc :frame-id fid)
|
||||
(assoc :initialized? true)
|
||||
(assoc :click-draw? true))]
|
||||
|
@ -85,7 +83,7 @@
|
|||
(rx/map move-drawing))
|
||||
|
||||
(->> ms/mouse-position
|
||||
(rx/filter #(> (gpt/distance % initial) 2))
|
||||
(rx/filter #(> (gpt/distance % initial) (/ 2 zoom)))
|
||||
(rx/with-latest vector ms/mouse-position-shift)
|
||||
(rx/switch-map
|
||||
(fn [[point :as current]]
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
|
||||
(ns app.main.data.workspace.drawing.common
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.worker :as uw]
|
||||
|
@ -29,27 +30,30 @@
|
|||
(rx/concat
|
||||
(when (:initialized? shape)
|
||||
(let [page-id (:current-page-id state)
|
||||
shape-click-width (case (:type shape)
|
||||
:text 3
|
||||
20)
|
||||
shape-click-height (case (:type shape)
|
||||
:text 16
|
||||
20)
|
||||
shape (if (:click-draw? shape)
|
||||
(-> shape
|
||||
(assoc-in [:modifiers :resize-vector]
|
||||
(gpt/point shape-click-width shape-click-height))
|
||||
(assoc-in [:modifiers :resize-origin]
|
||||
(gpt/point (:x shape) (:y shape))))
|
||||
shape)
|
||||
|
||||
shape (cond-> shape
|
||||
(= (:type shape) :text) (assoc :grow-type
|
||||
(if (:click-draw? shape) :auto-width :fixed)))
|
||||
click-draw? (:click-draw? shape)
|
||||
text? (= :text (:type shape))
|
||||
|
||||
shape (-> shape
|
||||
(gsh/transform-shape)
|
||||
(dissoc :initialized? :click-draw?))]
|
||||
min-side (min 100
|
||||
(mth/floor (get-in state [:workspace-local :vbox :width]))
|
||||
(mth/floor (get-in state [:workspace-local :vbox :height])))
|
||||
|
||||
shape
|
||||
(cond-> shape
|
||||
(and click-draw? (not text?))
|
||||
(-> (assoc :width min-side :height min-side)
|
||||
(assoc-in [:modifiers :displacement]
|
||||
(gmt/translate-matrix (- (/ min-side 2)) (- (/ min-side 2)))))
|
||||
|
||||
(and click-draw? text?)
|
||||
(assoc :height 17 :width 4 :grow-type :auto-width)
|
||||
|
||||
click-draw?
|
||||
(gsh/setup-selrect)
|
||||
|
||||
:always
|
||||
(-> (gsh/transform-shape)
|
||||
(dissoc :initialized? :click-draw?)))]
|
||||
;; Add & select the created shape to the workspace
|
||||
(rx/concat
|
||||
(if (= :text (:type shape))
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages.changes-builder :as pcb]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :refer [max-safe-int min-safe-int]]
|
||||
|
|
|
@ -495,12 +495,13 @@
|
|||
(watch [_ state stream]
|
||||
(let [initial (deref ms/mouse-position)
|
||||
selected (wsh/lookup-selected state {:omit-blocked? true})
|
||||
stopper (rx/filter ms/mouse-up? stream)]
|
||||
stopper (rx/filter ms/mouse-up? stream)
|
||||
zoom (get-in state [:workspace-local :zoom] 1)]
|
||||
(when-not (empty? selected)
|
||||
(->> ms/mouse-position
|
||||
(rx/map #(gpt/to-vec initial %))
|
||||
(rx/map #(gpt/length %))
|
||||
(rx/filter #(> % 1))
|
||||
(rx/filter #(> % (/ 10 zoom)))
|
||||
(rx/take 1)
|
||||
(rx/with-latest vector ms/mouse-position-alt)
|
||||
(rx/mapcat
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
(def ^:const snap-accuracy 10)
|
||||
(def ^:const snap-path-accuracy 10)
|
||||
(def ^:const snap-distance-accuracy 10)
|
||||
(def ^:const snap-distance-accuracy 20)
|
||||
|
||||
(defn- remove-from-snap-points
|
||||
[remove-snap?]
|
||||
|
@ -82,13 +82,13 @@
|
|||
;; Otherwise the root frame is the common
|
||||
:else zero)))
|
||||
|
||||
(defn get-snap-points [page-id frame-id remove-snap? point coord]
|
||||
(defn get-snap-points [page-id frame-id remove-snap? zoom point coord]
|
||||
(let [value (get point coord)]
|
||||
(->> (uw/ask! {:cmd :snaps/range-query
|
||||
:page-id page-id
|
||||
:frame-id frame-id
|
||||
:axis coord
|
||||
:ranges [[(- value 0.5) (+ value 0.5)]]})
|
||||
:ranges [[(- value (/ 0.5 zoom)) (+ value (/ 0.5 zoom))]]})
|
||||
(rx/take 1)
|
||||
(rx/map (remove-from-snap-points remove-snap?))
|
||||
(rx/map flatten-to-points))))
|
||||
|
@ -238,6 +238,18 @@
|
|||
(rx/map #(or % (gpt/point 0 0)))
|
||||
(rx/map #(gpt/add point %)))))
|
||||
|
||||
(defn combine-snaps-points
|
||||
([] nil)
|
||||
([p1] p1)
|
||||
([p1 p2]
|
||||
(cond
|
||||
(nil? p2) p1
|
||||
(nil? p1) p2
|
||||
|
||||
:else
|
||||
(gpt/point (mth/max-abs (:x p1) (:x p2))
|
||||
(mth/max-abs (:y p1) (:y p2))))))
|
||||
|
||||
(defn closest-snap-move
|
||||
[page-id shapes objects layout zoom focus movev]
|
||||
(let [frame-id (snap-frame-id shapes)
|
||||
|
@ -256,7 +268,7 @@
|
|||
(->> (rx/merge (closest-snap page-id frame-id shapes-points remove-snap? zoom)
|
||||
(when (contains? layout :dynamic-alignment)
|
||||
(closest-distance-snap page-id shapes objects zoom movev)))
|
||||
(rx/reduce gpt/min)
|
||||
(rx/reduce combine-snaps-points)
|
||||
(rx/map #(or % (gpt/point 0 0))))))
|
||||
|
||||
|
||||
|
@ -360,8 +372,8 @@
|
|||
dy (if (not= 0 (:y snap-delta))
|
||||
(- (+ (:y snap-pos) (:y snap-delta)) (:y position))
|
||||
0)]
|
||||
(-> position
|
||||
(update :x + dx)
|
||||
(update :y + dy)))
|
||||
|
||||
(cond-> position
|
||||
(<= (mth/abs dx) snap-accuracy) (update :x + dx)
|
||||
(<= (mth/abs dy) snap-accuracy) (update :y + dy)))
|
||||
position))
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
(ns app.main.ui.components.editable-select
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as math]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.icons :as i]
|
||||
|
@ -29,8 +29,8 @@
|
|||
max-val (get params :max)
|
||||
|
||||
num? (fn [val] (and (number? val)
|
||||
(not (math/nan? val))
|
||||
(math/finite? val)))
|
||||
(not (mth/nan? val))
|
||||
(mth/finite? val)))
|
||||
|
||||
emit-blur? (mf/use-ref nil)
|
||||
font-size-wrapper-ref (mf/use-ref)
|
||||
|
@ -58,8 +58,7 @@
|
|||
handle-change-input
|
||||
(fn [event]
|
||||
(let [value (-> event dom/get-target dom/get-value)
|
||||
value (-> (or (d/parse-double value) value)
|
||||
(math/precision 2))]
|
||||
value (or (d/parse-double value) value)]
|
||||
(set-value value)))
|
||||
|
||||
on-node-load
|
||||
|
@ -89,8 +88,7 @@
|
|||
(when (or up? down?)
|
||||
(dom/prevent-default event)
|
||||
(let [value (-> event dom/get-target dom/get-value)
|
||||
value (-> (or (d/parse-double value) value)
|
||||
(math/precision 2))
|
||||
value (or (d/parse-double value) value)
|
||||
|
||||
increment (cond
|
||||
(kbd/shift? event)
|
||||
|
@ -102,8 +100,7 @@
|
|||
:else
|
||||
(if up? 1 -1))
|
||||
|
||||
new-value (-> (+ value increment)
|
||||
(math/precision 2))
|
||||
new-value (+ value increment)
|
||||
|
||||
new-value (cond
|
||||
(and (num? min-val) (< new-value min-val)) min-val
|
||||
|
@ -135,7 +132,7 @@
|
|||
(let [wrapper-node (mf/ref-val font-size-wrapper-ref)
|
||||
node (dom/get-element-by-class "checked-element is-selected" wrapper-node)
|
||||
nodes (dom/get-elements-by-class "checked-element-value" wrapper-node)
|
||||
closest (fn [a b] (first (sort-by #(math/abs (- % b)) a)))
|
||||
closest (fn [a b] (first (sort-by #(mth/abs (- % b)) a)))
|
||||
closest-value (str (closest options value))]
|
||||
(when (:is-open? @state)
|
||||
(if (some? node)
|
||||
|
|
|
@ -6,23 +6,22 @@
|
|||
|
||||
(ns app.main.ui.components.numeric-input
|
||||
(:require
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as math]
|
||||
[app.common.spec :as us]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.object :as obj]
|
||||
[app.util.simple-math :as sm]
|
||||
[app.util.strings :as ust]
|
||||
[goog.events :as events]
|
||||
[rumext.alpha :as mf])
|
||||
(:import goog.events.EventType))
|
||||
|
||||
(defn num? [val]
|
||||
(and (number? val)
|
||||
(not (math/nan? val))
|
||||
(math/finite? val)))
|
||||
(not (mth/nan? val))
|
||||
(mth/finite? val)))
|
||||
|
||||
(mf/defc numeric-input
|
||||
{::mf/wrap-props false
|
||||
|
@ -37,7 +36,6 @@
|
|||
on-blur (obj/get props "onBlur")
|
||||
title (obj/get props "title")
|
||||
default-val (obj/get props "default" 0)
|
||||
precision (obj/get props "precision")
|
||||
|
||||
;; We need a ref pointing to the input dom element, but the user
|
||||
;; of this component may provide one (that is forwarded here).
|
||||
|
@ -85,10 +83,6 @@
|
|||
(sm/expr-eval value))]
|
||||
(when (num? new-value)
|
||||
(-> new-value
|
||||
(cond-> (number? precision)
|
||||
(math/precision precision))
|
||||
(cond-> (nil? precision)
|
||||
(math/round))
|
||||
(cljs.core/max us/min-safe-int)
|
||||
(cljs.core/min us/max-safe-int)
|
||||
(cond->
|
||||
|
@ -103,9 +97,7 @@
|
|||
(mf/deps ref)
|
||||
(fn [new-value]
|
||||
(let [input-node (mf/ref-val ref)]
|
||||
(dom/set-value! input-node (if (some? precision)
|
||||
(ust/format-precision new-value precision)
|
||||
(str new-value))))))
|
||||
(dom/set-value! input-node (fmt/format-number new-value)))))
|
||||
|
||||
apply-value
|
||||
(mf/use-callback
|
||||
|
@ -193,17 +185,17 @@
|
|||
(obj/set! "className" "input-text")
|
||||
(obj/set! "type" "text")
|
||||
(obj/set! "ref" ref)
|
||||
(obj/set! "defaultValue" value-str)
|
||||
(obj/set! "defaultValue" (fmt/format-number value))
|
||||
(obj/set! "title" title)
|
||||
(obj/set! "onWheel" handle-mouse-wheel)
|
||||
(obj/set! "onKeyDown" handle-key-down)
|
||||
(obj/set! "onBlur" handle-blur))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps value-str)
|
||||
(mf/deps value)
|
||||
(fn []
|
||||
(when-let [input-node (mf/ref-val ref)]
|
||||
(dom/set-value! input-node value-str))))
|
||||
(dom/set-value! input-node (fmt/format-number value)))))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps handle-blur)
|
||||
|
|
36
frontend/src/app/main/ui/formats.cljs
Normal file
36
frontend/src/app/main/ui/formats.cljs
Normal file
|
@ -0,0 +1,36 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; 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) UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.formats
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.math :as mth]))
|
||||
|
||||
(defn format-percent
|
||||
([value]
|
||||
(format-percent value nil))
|
||||
([value {:keys [precision] :or {precision 2}}]
|
||||
(let [percent-val (mth/precision (* value 100) precision)]
|
||||
(dm/str percent-val "%"))))
|
||||
|
||||
(defn format-number
|
||||
([value]
|
||||
(format-number value nil))
|
||||
([value {:keys [precision] :or {precision 2}}]
|
||||
(let [value (mth/precision value precision)]
|
||||
(dm/str value))))
|
||||
|
||||
(defn format-pixels
|
||||
([value]
|
||||
(format-pixels value nil))
|
||||
([value {:keys [precision] :or {precision 2}}]
|
||||
(let [value (mth/precision value precision)]
|
||||
(dm/str value "px"))))
|
||||
|
||||
(defn format-int
|
||||
[value]
|
||||
(let [value (mth/precision value 0)]
|
||||
(dm/str value)))
|
|
@ -12,6 +12,7 @@
|
|||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
;; ------------------------------------------------
|
||||
|
@ -97,7 +98,7 @@
|
|||
|
||||
(mf/defc size-display [{:keys [selrect zoom]}]
|
||||
(let [{:keys [x y width height]} selrect
|
||||
size-label (dm/str (mth/round width) " x " (mth/round height))
|
||||
size-label (dm/str (fmt/format-number width) " x " (fmt/format-number height))
|
||||
|
||||
rect-height (/ size-display-height zoom)
|
||||
rect-width (/ (if (<= (count size-label) 9)
|
||||
|
@ -164,7 +165,7 @@
|
|||
:height distance-pill-height
|
||||
:style {:fill distance-text-color
|
||||
:font-size font-size}}
|
||||
distance]]))
|
||||
(fmt/format-pixels distance)]]))
|
||||
|
||||
(mf/defc selection-rect [{:keys [selrect zoom]}]
|
||||
(let [{:keys [x y width height]} selrect
|
||||
|
@ -214,7 +215,7 @@
|
|||
{:x center-x
|
||||
:y center-y
|
||||
:zoom zoom
|
||||
:distance (dm/str (mth/round distance) "px")
|
||||
:distance distance
|
||||
:bounds bounds}]])))))
|
||||
|
||||
(mf/defc selection-guides [{:keys [bounds selrect zoom]}]
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
base #js {:textDecoration text-decoration
|
||||
:textTransform text-transform
|
||||
:lineHeight (or line-height "inherit")
|
||||
:color (if show-text? text-color "transparent")
|
||||
:color (if show-text? text-color "red")
|
||||
:caretColor (or text-color "black")
|
||||
:overflowWrap "initial"}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns app.main.ui.viewer.handoff.attributes.common
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.color-bullet :refer [color-bullet color-name]]
|
||||
[app.main.ui.components.copy-button :refer [copy-button]]
|
||||
|
@ -50,9 +49,9 @@
|
|||
(if (:gradient color)
|
||||
[:& color-name {:color color}]
|
||||
(case format
|
||||
:rgba (let [[r g b a] (->> (uc/hex->rgba (:color color) (:opacity color)) (map #(mth/precision % 2)))]
|
||||
:rgba (let [[r g b a] (uc/hex->rgba (:color color) (:opacity color))]
|
||||
[:div (str/fmt "%s, %s, %s, %s" r g b a)])
|
||||
:hsla (let [[h s l a] (->> (uc/hex->hsla (:color color) (:opacity color)) (map #(mth/precision % 2)))]
|
||||
:hsla (let [[h s l a] (uc/hex->hsla (:color color) (:opacity color))]
|
||||
[:div (str/fmt "%s, %s, %s, %s" h s l a)])
|
||||
[:*
|
||||
[:& color-name {:color color}]
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns app.main.ui.viewer.handoff.attributes.layout
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.common.spec.radius :as ctr]
|
||||
[app.main.ui.components.copy-button :refer [copy-button]]
|
||||
[app.util.code-gen :as cg]
|
||||
|
@ -39,46 +38,46 @@
|
|||
[:*
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.layout.width")]
|
||||
[:div.attributes-value (mth/precision width 2) "px"]
|
||||
[:div.attributes-value width "px"]
|
||||
[:& copy-button {:data (copy-data selrect :width)}]]
|
||||
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.layout.height")]
|
||||
[:div.attributes-value (mth/precision height 2) "px"]
|
||||
[:div.attributes-value height "px"]
|
||||
[:& copy-button {:data (copy-data selrect :height)}]]
|
||||
|
||||
(when (not= (:x shape) 0)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.layout.left")]
|
||||
[:div.attributes-value (mth/precision x 2) "px"]
|
||||
[:div.attributes-value x "px"]
|
||||
[:& copy-button {:data (copy-data selrect :x)}]])
|
||||
|
||||
(when (not= (:y shape) 0)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.layout.top")]
|
||||
[:div.attributes-value (mth/precision y 2) "px"]
|
||||
[:div.attributes-value y "px"]
|
||||
[:& copy-button {:data (copy-data selrect :y)}]])
|
||||
|
||||
(when (ctr/radius-1? shape)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.layout.radius")]
|
||||
[:div.attributes-value (mth/precision (:rx shape 0) 2) "px"]
|
||||
[:div.attributes-value (:rx shape 0) "px"]
|
||||
[:& copy-button {:data (copy-data shape :rx)}]])
|
||||
|
||||
(when (ctr/radius-4? shape)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.layout.radius")]
|
||||
[:div.attributes-value
|
||||
(mth/precision (:r1 shape) 2) ", "
|
||||
(mth/precision (:r2 shape) 2) ", "
|
||||
(mth/precision (:r3 shape) 2) ", "
|
||||
(mth/precision (:r4 shape) 2) "px"]
|
||||
(:r1 shape) ", "
|
||||
(:r2 shape) ", "
|
||||
(:r3 shape) ", "
|
||||
(:r4 shape) "px"]
|
||||
[:& copy-button {:data (copy-data shape :r1)}]])
|
||||
|
||||
(when (not= (:rotation shape 0) 0)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.layout.rotation")]
|
||||
[:div.attributes-value (mth/precision (:rotation shape) 2) "deg"]
|
||||
[:div.attributes-value (:rotation shape) "deg"]
|
||||
[:& copy-button {:data (copy-data shape :rotation)}]])]))
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.viewer.handoff.attributes.stroke
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.main.ui.components.copy-button :refer [copy-button]]
|
||||
[app.main.ui.viewer.handoff.attributes.common :refer [color-row]]
|
||||
[app.util.code-gen :as cg]
|
||||
|
@ -67,7 +66,7 @@
|
|||
stroke-alignment (or stroke-alignment :center)]
|
||||
[:div.attributes-stroke-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.stroke.width")]
|
||||
[:div.attributes-value (mth/precision (:stroke-width shape) 2) "px"]
|
||||
[:div.attributes-value (:stroke-width shape) "px"]
|
||||
[:div.attributes-value (->> stroke-style d/name (str "handoff.attributes.stroke.style.") (t locale))]
|
||||
[:div.attributes-label (->> stroke-alignment d/name (str "handoff.attributes.stroke.alignment.") (t locale))]
|
||||
[:& copy-button {:data (copy-stroke-data shape)}]])]))
|
||||
|
|
|
@ -6,16 +6,12 @@
|
|||
|
||||
(ns app.main.ui.viewer.handoff.attributes.svg
|
||||
(:require
|
||||
#_[app.common.math :as mth]
|
||||
#_[app.main.ui.icons :as i]
|
||||
#_[app.util.code-gen :as cg]
|
||||
[app.common.data :as d]
|
||||
[app.main.ui.components.copy-button :refer [copy-button]]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
|
||||
(defn map->css [attr]
|
||||
(->> attr
|
||||
(map (fn [[attr-key attr-value]] (str (d/name attr-key) ":" attr-value)))
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
(ns app.main.ui.viewer.header
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.viewer :as dv]
|
||||
[app.main.data.viewer.shortcuts :as sc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.viewer.comments :refer [comments-menu]]
|
||||
[app.main.ui.viewer.interactions :refer [flows-menu interactions-menu]]
|
||||
|
@ -32,7 +32,7 @@
|
|||
:as props}]
|
||||
(let [show-dropdown? (mf/use-state false)]
|
||||
[:div.zoom-widget {:on-click #(reset! show-dropdown? true)}
|
||||
[:span.label {} (str (mth/round (* 100 zoom)) "%")]
|
||||
[:span.label (fmt/format-percent zoom)]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close #(reset! show-dropdown? false)}
|
||||
|
@ -43,7 +43,7 @@
|
|||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(on-decrease))} "-"]
|
||||
[:p.zoom-size {} (str (mth/round (* 100 zoom)) "%")]
|
||||
[:p.zoom-size (fmt/format-percent zoom)]
|
||||
[:button {:on-click (fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns app.main.ui.workspace.colorpalette
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.workspace.colors :as mdc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
|
@ -57,7 +56,7 @@
|
|||
(let [state (mf/use-state {:show-menu false})
|
||||
|
||||
width (:width @state 0)
|
||||
visible (mth/round (/ width 66))
|
||||
visible (/ width 66)
|
||||
|
||||
offset (:offset @state 0)
|
||||
max-offset (- (count current-colors)
|
||||
|
@ -75,7 +74,7 @@
|
|||
(swap! state update :offset
|
||||
(fn [offset]
|
||||
(if (pos? offset)
|
||||
(max (- offset (mth/round (/ visible 2))) 0)
|
||||
(max (- offset (/ visible 2)) 0)
|
||||
offset)))))
|
||||
|
||||
on-right-arrow-click
|
||||
|
@ -85,7 +84,7 @@
|
|||
(swap! state update :offset
|
||||
(fn [offset]
|
||||
(if (< offset max-offset)
|
||||
(min max-offset (+ offset (mth/round (/ visible 2))))
|
||||
(min max-offset (+ offset (/ visible 2)))
|
||||
offset)))))
|
||||
|
||||
on-scroll
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
(ns app.main.ui.workspace.colorpicker.color-inputs
|
||||
(:require
|
||||
[app.common.math :as math]
|
||||
[app.common.math :as mth]
|
||||
[app.util.color :as uc]
|
||||
[app.util.dom :as dom]
|
||||
[rumext.alpha :as mf]))
|
||||
|
@ -52,7 +52,7 @@
|
|||
on-change-property
|
||||
(fn [property max-value]
|
||||
(fn [e]
|
||||
(let [val (-> e dom/get-target-val (math/clamp 0 max-value))
|
||||
(let [val (-> e dom/get-target-val (mth/clamp 0 max-value))
|
||||
val (if (#{:s} property) (/ val 100) val)]
|
||||
(when (not (nil? val))
|
||||
(if (#{:r :g :b} property)
|
||||
|
@ -72,7 +72,7 @@
|
|||
|
||||
on-change-opacity
|
||||
(fn [e]
|
||||
(when-let [new-alpha (-> e dom/get-target-val (math/clamp 0 100) (/ 100))]
|
||||
(when-let [new-alpha (-> e dom/get-target-val (mth/clamp 0 100) (/ 100))]
|
||||
(on-change {:alpha new-alpha})))]
|
||||
|
||||
|
||||
|
@ -86,9 +86,9 @@
|
|||
(when (and property-val property-ref)
|
||||
(when-let [node (mf/ref-val property-ref)]
|
||||
(case ref-key
|
||||
(:s :alpha) (dom/set-value! node (math/round (* property-val 100)))
|
||||
(:s :alpha) (dom/set-value! node (* property-val 100))
|
||||
:hex (dom/set-value! node property-val)
|
||||
(dom/set-value! node (math/round property-val)))))))))
|
||||
(dom/set-value! node property-val))))))))
|
||||
|
||||
[:div.color-values
|
||||
{:class (when disable-opacity "disable-opacity")}
|
||||
|
@ -156,7 +156,7 @@
|
|||
:min 0
|
||||
:step 1
|
||||
:max 100
|
||||
:default-value (if (= alpha :multiple) "" (math/precision alpha 2))
|
||||
:default-value (if (= alpha :multiple) "" alpha)
|
||||
:on-change on-change-opacity}])
|
||||
|
||||
[:label.hex-label {:for "hex-value"} "HEX"]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
(ns app.main.ui.workspace.colorpicker.harmony
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.math :as math]
|
||||
[app.common.math :as mth]
|
||||
[app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]]
|
||||
[app.util.color :as uc]
|
||||
[app.util.dom :as dom]
|
||||
|
@ -28,9 +28,9 @@
|
|||
(.clearRect ctx 0 0 width height)
|
||||
|
||||
(doseq [degrees (range 0 360 step)]
|
||||
(let [degrees-rad (math/radians degrees)
|
||||
x (* radius (math/cos (- degrees-rad)))
|
||||
y (* radius (math/sin (- degrees-rad)))]
|
||||
(let [degrees-rad (mth/radians degrees)
|
||||
x (* radius (mth/cos (- degrees-rad)))
|
||||
y (* radius (mth/sin (- degrees-rad)))]
|
||||
(obj/set! ctx "strokeStyle" (str/format "hsl(%s, 100%, 50%)" degrees))
|
||||
(.beginPath ctx)
|
||||
(.moveTo ctx cx cy)
|
||||
|
@ -43,15 +43,15 @@
|
|||
(obj/set! ctx "fillStyle" grd)
|
||||
|
||||
(.beginPath ctx)
|
||||
(.arc ctx cx cy radius 0 (* 2 math/PI) true)
|
||||
(.arc ctx cx cy radius 0 (* 2 mth/PI) true)
|
||||
(.closePath ctx)
|
||||
(.fill ctx))))
|
||||
|
||||
(defn color->point
|
||||
[canvas-side hue saturation]
|
||||
(let [hue-rad (math/radians (- hue))
|
||||
comp-x (* saturation (math/cos hue-rad))
|
||||
comp-y (* saturation (math/sin hue-rad))
|
||||
(let [hue-rad (mth/radians (- hue))
|
||||
comp-x (* saturation (mth/cos hue-rad))
|
||||
comp-y (* saturation (mth/sin hue-rad))
|
||||
x (+ (/ canvas-side 2) (* comp-x (/ canvas-side 2)))
|
||||
y (+ (/ canvas-side 2) (* comp-y (/ canvas-side 2)))]
|
||||
(gpt/point x y)))
|
||||
|
@ -68,15 +68,15 @@
|
|||
calculate-pos (fn [ev]
|
||||
(let [{:keys [left right top bottom]} (-> ev dom/get-target dom/get-bounding-rect)
|
||||
{:keys [x y]} (-> ev dom/get-client-position)
|
||||
px (math/clamp (/ (- x left) (- right left)) 0 1)
|
||||
py (math/clamp (/ (- y top) (- bottom top)) 0 1)
|
||||
px (mth/clamp (/ (- x left) (- right left)) 0 1)
|
||||
py (mth/clamp (/ (- y top) (- bottom top)) 0 1)
|
||||
|
||||
px (- (* 2 px) 1)
|
||||
py (- (* 2 py) 1)
|
||||
|
||||
angle (math/degrees (math/atan2 px py))
|
||||
new-hue (math/precision (mod (- angle 90 ) 360) 2)
|
||||
new-saturation (math/clamp (math/distance [px py] [0 0]) 0 1)
|
||||
angle (mth/degrees (mth/atan2 px py))
|
||||
new-hue (mod (- angle 90 ) 360)
|
||||
new-saturation (mth/clamp (mth/distance [px py] [0 0]) 0 1)
|
||||
hex (uc/hsv->hex [new-hue new-saturation value])
|
||||
[r g b] (uc/hex->rgb hex)]
|
||||
(on-change {:hex hex
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
(ns app.main.ui.workspace.colorpicker.ramp
|
||||
(:require
|
||||
[app.common.math :as math]
|
||||
[app.common.math :as mth]
|
||||
[app.main.ui.components.color-bullet :refer [color-bullet]]
|
||||
[app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]]
|
||||
[app.util.color :as uc]
|
||||
|
@ -19,8 +19,8 @@
|
|||
(fn [ev]
|
||||
(let [{:keys [left right top bottom]} (-> ev dom/get-target dom/get-bounding-rect)
|
||||
{:keys [x y]} (-> ev dom/get-client-position)
|
||||
px (math/clamp (/ (- x left) (- right left)) 0 1)
|
||||
py (* 255 (- 1 (math/clamp (/ (- y top) (- bottom top)) 0 1)))]
|
||||
px (mth/clamp (/ (- x left) (- right left)) 0 1)
|
||||
py (* 255 (- 1 (mth/clamp (/ (- y top) (- bottom top)) 0 1)))]
|
||||
(on-change px py)))
|
||||
|
||||
handle-start-drag
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
(ns app.main.ui.workspace.colorpicker.slider-selector
|
||||
(:require
|
||||
[app.common.math :as math]
|
||||
[app.common.math :as mth]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.object :as obj]
|
||||
[rumext.alpha :as mf]))
|
||||
|
@ -41,13 +41,13 @@
|
|||
(let [{:keys [left right top bottom]} (-> ev dom/get-target dom/get-bounding-rect)
|
||||
{:keys [x y]} (-> ev dom/get-client-position)
|
||||
unit-value (if vertical?
|
||||
(math/clamp (/ (- bottom y) (- bottom top)) 0 1)
|
||||
(math/clamp (/ (- x left) (- right left)) 0 1))
|
||||
(mth/clamp (/ (- bottom y) (- bottom top)) 0 1)
|
||||
(mth/clamp (/ (- x left) (- right left)) 0 1))
|
||||
unit-value (if reverse?
|
||||
(math/abs (- unit-value 1.0))
|
||||
(mth/abs (- unit-value 1.0))
|
||||
unit-value)
|
||||
value (+ min-value (* unit-value (- max-value min-value)))]
|
||||
(on-change (math/precision value 2)))))]
|
||||
(on-change value))))]
|
||||
|
||||
[:div.slider-selector
|
||||
{:class (str (if vertical? "vertical " "") class)
|
||||
|
@ -60,7 +60,7 @@
|
|||
(- max-value min-value)) 100)
|
||||
|
||||
value-percent (if reverse?
|
||||
(math/abs (- value-percent 100))
|
||||
(mth/abs (- value-percent 100))
|
||||
value-percent)
|
||||
value-percent-str (str value-percent "%")
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.workspace.header
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.config :as cf]
|
||||
[app.main.data.events :as ev]
|
||||
[app.main.data.messages :as dm]
|
||||
|
@ -18,6 +17,7 @@
|
|||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.main.ui.hooks.resize :as r]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.workspace.presence :refer [active-sessions]]
|
||||
|
@ -71,7 +71,7 @@
|
|||
:as props}]
|
||||
(let [show-dropdown? (mf/use-state false)]
|
||||
[:div.zoom-widget {:on-click #(reset! show-dropdown? true)}
|
||||
[:span.label {} (str (mth/round (* 100 zoom)) "%")]
|
||||
[:span.label (fmt/format-percent zoom {:precision 0})]
|
||||
[:span.icon i/arrow-down]
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close #(reset! show-dropdown? false)}
|
||||
|
@ -82,7 +82,7 @@
|
|||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(on-decrease))} "-"]
|
||||
[:p.zoom-size {} (str (mth/round (* 100 zoom)) "%")]
|
||||
[:p.zoom-size {} (fmt/format-percent zoom {:precision 0})]
|
||||
[:button {:on-click (fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.workspace.left-toolbar
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.math :as mth]
|
||||
[app.common.media :as cm]
|
||||
[app.main.data.events :as ev]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -40,8 +39,8 @@
|
|||
;; We don't want to add a ref because that redraws the component
|
||||
;; for everychange. Better direct access on the callback.
|
||||
(let [vbox (deref refs/vbox)
|
||||
x (mth/round (+ (:x vbox) (/ (:width vbox) 2)))
|
||||
y (mth/round (+ (:y vbox) (/ (:height vbox) 2)))
|
||||
x (+ (:x vbox) (/ (:width vbox) 2))
|
||||
y (+ (:y vbox) (/ (:height vbox) 2))
|
||||
params {:file-id (:id file)
|
||||
:blobs (seq blobs)
|
||||
:position (gpt/point x y)}]
|
||||
|
|
|
@ -49,12 +49,12 @@
|
|||
[:div.input-wrapper
|
||||
[:span
|
||||
[:p.nudge-subtitle (tr "modals.small-nudge")]
|
||||
[:> numeric-input {:min 1
|
||||
[:> numeric-input {:min 0.01
|
||||
:value (:small nudge)
|
||||
:on-change update-small}]]]
|
||||
[:div.input-wrapper
|
||||
[:span
|
||||
[:p.nudge-subtitle (tr "modals.big-nudge")]
|
||||
[:> numeric-input {:min 1
|
||||
[:> numeric-input {:min 0.01
|
||||
:value (:big nudge)
|
||||
:on-change update-big}]]]]]]))
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
:style {:cursor (cond
|
||||
(= edit-mode :draw) cur/pen-node
|
||||
(= edit-mode :move) cur/pointer-node)
|
||||
:stroke-width 0
|
||||
:fill "none"}}]]))
|
||||
|
||||
(mf/defc path-handler [{:keys [index prefix point handler zoom selected? hover? edit-mode snap-angle?]}]
|
||||
|
@ -147,7 +148,8 @@
|
|||
:on-mouse-enter on-enter
|
||||
:on-mouse-leave on-leave
|
||||
:style {:cursor (when (= edit-mode :move) cur/pointer-move)
|
||||
:fill "none"}}]])))
|
||||
:fill "none"
|
||||
:stroke-width 0}}]])))
|
||||
|
||||
(mf/defc path-preview [{:keys [zoom command from]}]
|
||||
[:g.preview {:style {:pointer-events "none"}}
|
||||
|
|
|
@ -209,7 +209,7 @@
|
|||
;; and updates the selrect accordingly
|
||||
[:*
|
||||
[:g.text-shape {:ref on-change-node
|
||||
:opacity (when show-svg-text? 0)
|
||||
:opacity (when show-svg-text? 0.2)
|
||||
:pointer-events "none"}
|
||||
|
||||
;; The `:key` prop here is mandatory because the
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
(ns app.main.ui.workspace.sidebar.options.menus.frame-grid
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.workspace.grid :as dw]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
|
@ -71,8 +70,7 @@
|
|||
(let [{:keys [margin gutter item-length]} (:params grid)
|
||||
frame-length (if (= :column (:type grid)) frame-width frame-height)
|
||||
item-length (if (nil? size)
|
||||
(-> (gg/calculate-default-item-length frame-length margin gutter)
|
||||
(mth/precision 2))
|
||||
(gg/calculate-default-item-length frame-length margin gutter)
|
||||
item-length)]
|
||||
(-> grid
|
||||
(update :params assoc :size size :item-length item-length)
|
||||
|
@ -140,7 +138,7 @@
|
|||
|
||||
(if (= type :square)
|
||||
[:div.input-element.pixels {:title (tr "workspace.options.size")}
|
||||
[:> numeric-input {:min 1
|
||||
[:> numeric-input {:min 0.01
|
||||
:value (or (:size params) "")
|
||||
:no-validate true
|
||||
:on-change (handle-change :params :size)}]]
|
||||
|
@ -162,7 +160,7 @@
|
|||
(when (= :square type)
|
||||
[:& input-row {:label (tr "workspace.options.grid.params.size")
|
||||
:class "pixels"
|
||||
:min 1
|
||||
:min 0.01
|
||||
:value (:size params)
|
||||
:on-change (handle-change :params :size)}])
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.workspace.sidebar.options.menus.layer
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.numeric-input :refer [numeric-input]]
|
||||
|
@ -23,8 +22,7 @@
|
|||
""
|
||||
(str (-> opacity
|
||||
(d/coalesce 1)
|
||||
(* 100)
|
||||
(mth/round)))))
|
||||
(* 100)))))
|
||||
|
||||
(defn select-all [event]
|
||||
(dom/select-text! (dom/get-target event)))
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as math]
|
||||
[app.common.spec.radius :as ctr]
|
||||
[app.main.data.workspace :as udw]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
|
@ -46,9 +45,7 @@
|
|||
(let [value (attr values)]
|
||||
(if (= value :multiple)
|
||||
""
|
||||
(str (-> value
|
||||
(d/coalesce 0)
|
||||
(math/precision 2))))))
|
||||
(str (-> value (d/coalesce 0))))))
|
||||
|
||||
(declare +size-presets+)
|
||||
|
||||
|
@ -239,7 +236,7 @@
|
|||
[:div.row-flex
|
||||
[:span.element-set-subtitle (tr "workspace.options.size")]
|
||||
[:div.input-element.width {:title (tr "workspace.options.width")}
|
||||
[:> numeric-input {:min 1
|
||||
[:> numeric-input {:min 0.01
|
||||
:no-validate true
|
||||
:placeholder "--"
|
||||
:on-click select-all
|
||||
|
@ -247,7 +244,7 @@
|
|||
:value (attr->string :width values)}]]
|
||||
|
||||
[:div.input-element.height {:title (tr "workspace.options.height")}
|
||||
[:> numeric-input {:min 1
|
||||
[:> numeric-input {:min 0.01
|
||||
:no-validate true
|
||||
:placeholder "--"
|
||||
:on-click select-all
|
||||
|
@ -271,15 +268,13 @@
|
|||
:placeholder "--"
|
||||
:on-click select-all
|
||||
:on-change on-pos-x-change
|
||||
:value (attr->string :x values)
|
||||
:precision 2}]]
|
||||
:value (attr->string :x values)}]]
|
||||
[:div.input-element.Yaxis {:title (tr "workspace.options.y")}
|
||||
[:> numeric-input {:no-validate true
|
||||
:placeholder "--"
|
||||
:on-click select-all
|
||||
:on-change on-pos-y-change
|
||||
:value (attr->string :y values)
|
||||
:precision 2}]]])
|
||||
:value (attr->string :y values)}]]])
|
||||
|
||||
;; ROTATION
|
||||
(when (options :rotation)
|
||||
|
|
|
@ -386,7 +386,6 @@
|
|||
{:min -200
|
||||
:max 200
|
||||
:step 0.1
|
||||
:precision 2
|
||||
:value (attr->string line-height)
|
||||
:placeholder (tr "settings.multiple")
|
||||
:on-change #(handle-change % :line-height)
|
||||
|
@ -400,7 +399,6 @@
|
|||
{:min -200
|
||||
:max 200
|
||||
:step 0.1
|
||||
:precision 2
|
||||
:value (attr->string letter-spacing)
|
||||
:placeholder (tr "settings.multiple")
|
||||
:on-change #(handle-change % :letter-spacing)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.workspace.sidebar.options.rows.color-row
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as math]
|
||||
[app.common.pages :as cp]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -54,8 +53,7 @@
|
|||
""
|
||||
(str (-> opacity
|
||||
(d/coalesce 1)
|
||||
(* 100)
|
||||
(math/round)))))
|
||||
(* 100)))))
|
||||
|
||||
(defn remove-multiple [v]
|
||||
(if (= v :multiple) nil v))
|
||||
|
|
|
@ -97,7 +97,6 @@
|
|||
[:> numeric-input
|
||||
{:min 0
|
||||
:value (-> (:stroke-width stroke) width->string)
|
||||
:precision 2
|
||||
:placeholder (tr "settings.multiple")
|
||||
:on-change (on-stroke-width-change index)
|
||||
:on-click select-all
|
||||
|
|
|
@ -345,6 +345,7 @@
|
|||
:zoom zoom
|
||||
:transform transform
|
||||
:selected selected
|
||||
:selected-shapes selected-shapes
|
||||
:page-id page-id}])
|
||||
|
||||
(when show-cursor-tooltip?
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.workspace.viewport.frame-grid
|
||||
(:require
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.refs :as refs]
|
||||
[app.util.geom.grid :as gg]
|
||||
|
@ -58,10 +57,10 @@
|
|||
[:g.grid
|
||||
(for [{:keys [x y width height] :as area} (gg/grid-areas frame grid)]
|
||||
[:rect {:key (str key "-" x "-" y)
|
||||
:x (mth/round x)
|
||||
:y (mth/round y)
|
||||
:width (- (mth/round (+ x width)) (mth/round x))
|
||||
:height (- (mth/round (+ y height)) (mth/round y))
|
||||
:x x
|
||||
:y y
|
||||
:width (- (+ x width) x)
|
||||
:height (- (+ y height) y)
|
||||
:style style}])]))
|
||||
|
||||
(mf/defc grid-display-frame
|
||||
|
|
|
@ -281,9 +281,7 @@
|
|||
(fn [point]
|
||||
(let [point (gpt/transform point transform-inverse)
|
||||
start-x (/ (- (:x point) x) width)
|
||||
start-y (/ (- (:y point) y) height)
|
||||
start-x (mth/precision start-x 2)
|
||||
start-y (mth/precision start-y 2)]
|
||||
start-y (/ (- (:y point) y) height)]
|
||||
(change! {:start-x start-x :start-y start-y}))))
|
||||
|
||||
on-change-finish
|
||||
|
@ -292,9 +290,7 @@
|
|||
(fn [point]
|
||||
(let [point (gpt/transform point transform-inverse)
|
||||
end-x (/ (- (:x point) x) width)
|
||||
end-y (/ (- (:y point) y) height)
|
||||
end-x (mth/precision end-x 2)
|
||||
end-y (mth/precision end-y 2)]
|
||||
end-y (/ (- (:y point) y) height)]
|
||||
(change! {:end-x end-x :end-y end-y}))))
|
||||
|
||||
on-change-width
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
[app.common.colors :as colors]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -102,7 +101,6 @@
|
|||
(+ start-pos delta))
|
||||
|
||||
;; TODO: Change when pixel-grid flag exists
|
||||
new-position (mth/round new-position)
|
||||
new-frame-id (:id (get-hover-frame))]
|
||||
(swap! state assoc
|
||||
:new-position new-position
|
||||
|
@ -366,7 +364,7 @@
|
|||
:style {:font-size (/ rules/font-size zoom)
|
||||
:font-family rules/font-family
|
||||
:fill colors/black}}
|
||||
(str (mth/round pos))]]))])))
|
||||
(str pos)]]))])))
|
||||
|
||||
(mf/defc new-guide-area
|
||||
[{:keys [vbox zoom axis get-hover-frame disabled-guides?]}]
|
||||
|
|
|
@ -146,12 +146,12 @@
|
|||
|
||||
:else
|
||||
(connect-to-point orig-shape
|
||||
{:x (+ (:x2 (:selrect orig-shape)) 100)
|
||||
:y (+ (- (:y1 (:selrect orig-shape)) 50)
|
||||
{:x (+ (:x2 (:selrect orig-shape)) (/ 100 zoom))
|
||||
:y (+ (- (:y1 (:selrect orig-shape)) (/ 50 zoom))
|
||||
(/ (* level 32) zoom))}))
|
||||
|
||||
orig-dx (if (= orig-pos :right) 100 -100)
|
||||
dest-dx (if (= dest-pos :right) 100 -100)
|
||||
orig-dx (/ (if (= orig-pos :right) 100 -100) zoom)
|
||||
dest-dx (/ (if (= dest-pos :right) 100 -100) zoom)
|
||||
|
||||
path ["M" orig-x orig-y "C" (+ orig-x orig-dx) orig-y (+ dest-x dest-dx) dest-y dest-x dest-y]
|
||||
pdata (str/join " " path)
|
||||
|
@ -182,7 +182,8 @@
|
|||
:d pdata}]
|
||||
|
||||
(when dest-shape
|
||||
[:& outline {:shape dest-shape
|
||||
[:& outline {:zoom zoom
|
||||
:shape dest-shape
|
||||
:color "var(--color-primary)"}])
|
||||
|
||||
[:& interaction-marker {:index index
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.util.object :as obj]
|
||||
[rumext.alpha :as mf]))
|
||||
|
@ -131,9 +132,9 @@
|
|||
|
||||
|
||||
(let [{:keys [start end]} (get-rule-params vbox axis)
|
||||
minv (max (mth/round start) -100000)
|
||||
minv (max start -100000)
|
||||
minv (* (mth/ceil (/ minv step)) step)
|
||||
maxv (min (mth/round end) 100000)
|
||||
maxv (min end 100000)
|
||||
maxv (* (mth/floor (/ maxv step)) step)]
|
||||
|
||||
(for [step-val (range minv (inc maxv) step)]
|
||||
|
@ -149,7 +150,7 @@
|
|||
:style {:font-size (/ font-size zoom)
|
||||
:font-family font-family
|
||||
:fill colors/gray-30}}
|
||||
(str (mth/round step-val))]
|
||||
(fmt/format-number step-val)]
|
||||
|
||||
[:line {:key (str "line-" (d/name axis) "-" step-val)
|
||||
:x1 line-x1
|
||||
|
@ -184,7 +185,7 @@
|
|||
:style {:font-size (/ font-size zoom)
|
||||
:font-family font-family
|
||||
:fill selection-area-color}}
|
||||
(str (mth/round (:x1 selection-rect)))]
|
||||
(fmt/format-number (:x1 selection-rect))]
|
||||
|
||||
[:rect {:x (:x2 selection-rect)
|
||||
:y (:y vbox)
|
||||
|
@ -200,7 +201,7 @@
|
|||
:style {:font-size (/ font-size zoom)
|
||||
:font-family font-family
|
||||
:fill selection-area-color}}
|
||||
(str (mth/round (:x2 selection-rect)))]]
|
||||
(fmt/format-number (:x2 selection-rect))]]
|
||||
|
||||
(let [center-x (+ (:x vbox) (/ rule-area-half-size zoom))
|
||||
center-y (- (+ (:y selection-rect) (/ (:height selection-rect) 2)) (/ rule-area-half-size zoom))]
|
||||
|
@ -234,7 +235,7 @@
|
|||
:style {:font-size (/ font-size zoom)
|
||||
:font-family font-family
|
||||
:fill selection-area-color}}
|
||||
(str (mth/round (:y2 selection-rect)))]
|
||||
(fmt/format-number (:y2 selection-rect))]
|
||||
|
||||
[:text {:x (+ center-x (/ (:height selection-rect) 2) )
|
||||
:y center-y
|
||||
|
@ -243,7 +244,7 @@
|
|||
:style {:font-size (/ font-size zoom)
|
||||
:font-family font-family
|
||||
:fill selection-area-color}}
|
||||
(str (mth/round (:y1 selection-rect)))]])])
|
||||
(fmt/format-number (:y1 selection-rect))]])])
|
||||
|
||||
(mf/defc rules
|
||||
{::mf/wrap-props false
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
(let [viewport (mf/ref-val viewport-ref)
|
||||
start-pt (mf/ref-val start-ref)
|
||||
current-pt (dom/get-client-position event)
|
||||
current-pt-viewport (utils/translate-point-to-viewport-raw viewport zoom current-pt)
|
||||
current-pt-viewport (utils/translate-point-to-viewport viewport zoom current-pt)
|
||||
y-delta (/ (* (mf/ref-val height-factor-ref) (- (:y current-pt) (:y start-pt))) zoom)
|
||||
x-delta (/ (* (mf/ref-val width-factor-ref) (- (:x current-pt) (:x start-pt))) zoom)
|
||||
new-v-scrollbar-y (-> current-pt-viewport
|
||||
|
@ -156,8 +156,9 @@
|
|||
(fn [event axis]
|
||||
(let [viewport (mf/ref-val viewport-ref)
|
||||
start-pt (dom/get-client-position event)
|
||||
new-v-scrollbar-y (-> (utils/translate-point-to-viewport-raw viewport zoom start-pt) :y)
|
||||
new-h-scrollbar-x (-> (utils/translate-point-to-viewport-raw viewport zoom start-pt) :x)
|
||||
viewport-point (utils/translate-point-to-viewport viewport zoom start-pt)
|
||||
new-h-scrollbar-x (:x viewport-point)
|
||||
new-v-scrollbar-y (:y viewport-point)
|
||||
v-scrollbar-y-padding (- v-scrollbar-y new-v-scrollbar-y)
|
||||
h-scrollbar-x-padding (- h-scrollbar-x new-h-scrollbar-x)
|
||||
vbox-rect {:x vbox-x
|
||||
|
@ -206,7 +207,7 @@
|
|||
:x v-scrollbar-x
|
||||
:y v-scrollbar-y
|
||||
:style {:stroke "white"
|
||||
:stroke-width 0.15}}]])
|
||||
:stroke-width (/ 0.15 zoom)}}]])
|
||||
(when show-h-scroll?
|
||||
[:g.h-scroll
|
||||
[:rect {:on-mouse-move #(on-mouse-move % :x)
|
||||
|
@ -220,4 +221,4 @@
|
|||
:x h-scrollbar-x
|
||||
:y h-scrollbar-y
|
||||
:style {:stroke "white"
|
||||
:stroke-width 0.15}}]])]))
|
||||
:stroke-width (/ 0.15 zoom)}}]])]))
|
||||
|
|
|
@ -67,38 +67,18 @@
|
|||
:position :top-left
|
||||
:props {:cx x :cy y}}
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :top-left
|
||||
:props {:cx x :cy y :align align}})
|
||||
|
||||
{:type :rotation
|
||||
:position :top-right
|
||||
:props {:cx (+ x width) :cy y}}
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :top-right
|
||||
:props {:cx (+ x width) :cy y :align align}})
|
||||
|
||||
{:type :rotation
|
||||
:position :bottom-right
|
||||
:props {:cx (+ x width) :cy (+ y height)}}
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :bottom-right
|
||||
:props {:cx (+ x width) :cy (+ y height) :align align}})
|
||||
|
||||
{:type :rotation
|
||||
:position :bottom-left
|
||||
:props {:cx x :cy (+ y height)}}
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :bottom-left
|
||||
:props {:cx x :cy (+ y height) :align align}})
|
||||
|
||||
(when min-side-top?
|
||||
{:type :resize-side
|
||||
:position :top
|
||||
|
@ -117,7 +97,30 @@
|
|||
(when min-side-side?
|
||||
{:type :resize-side
|
||||
:position :left
|
||||
:props {:x x :y (+ y height) :length height :angle 270 :align align}})]
|
||||
:props {:x x :y (+ y height) :length height :angle 270 :align align}})
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :top-left
|
||||
:props {:cx x :cy y :align align}})
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :top-right
|
||||
:props {:cx (+ x width) :cy y :align align}})
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :bottom-right
|
||||
:props {:cx (+ x width) :cy (+ y height) :align align}})
|
||||
|
||||
(when show-resize-point?
|
||||
{:type :resize-point
|
||||
:position :bottom-left
|
||||
:props {:cx x :cy (+ y height) :align align}})
|
||||
|
||||
|
||||
]
|
||||
|
||||
(filterv (comp not nil?)))))
|
||||
|
||||
|
@ -136,6 +139,8 @@
|
|||
:width size
|
||||
:height size
|
||||
:fill (if (debug? :rotation-handler) "blue" "none")
|
||||
:stroke (if (debug? :rotation-handler) "blue" "none")
|
||||
:stroke-width 0
|
||||
:transform transform
|
||||
:on-mouse-down on-rotate}]))
|
||||
|
||||
|
@ -168,6 +173,8 @@
|
|||
:height resize-point-circle-radius
|
||||
:transform (when rotation (str/fmt "rotate(%s, %s, %s)" rotation cx' cy'))
|
||||
:style {:fill (if (debug? :resize-handler) "red" "none")
|
||||
:stroke (if (debug? :resize-handler) "red" "none")
|
||||
:stroke-width 0
|
||||
:cursor cursor}
|
||||
:on-mouse-down #(on-resize {:x cx' :y cy'} %)}])
|
||||
|
||||
|
@ -176,7 +183,10 @@
|
|||
:cx cx'
|
||||
:cy cy'
|
||||
:style {:fill (if (debug? :resize-handler) "red" "none")
|
||||
:cursor cursor}}])]))
|
||||
:stroke (if (debug? :resize-handler) "red" "none")
|
||||
:stroke-width 0
|
||||
:cursor cursor}}]
|
||||
)]))
|
||||
|
||||
(mf/defc resize-side-handler
|
||||
"The side handler is always rendered horizontally and then rotated"
|
||||
|
@ -202,6 +212,8 @@
|
|||
(gmt/rotate-matrix angle (gpt/point x y)))
|
||||
:on-mouse-down #(on-resize res-point %)
|
||||
:style {:fill (if (debug? :resize-handler) "yellow" "none")
|
||||
:stroke (if (debug? :resize-handler) "yellow" "none")
|
||||
:stroke-width 0
|
||||
:cursor (if (#{:left :right} position)
|
||||
(cur/resize-ew rotation)
|
||||
(cur/resize-ns rotation)) }}]))
|
||||
|
@ -292,7 +304,7 @@
|
|||
:pointer-events "visible"
|
||||
:style {:stroke color
|
||||
:stroke-width (/ 0.5 zoom)
|
||||
:stroke-opacity "1"
|
||||
:stroke-opacity 1
|
||||
:fill "none"}}]]))
|
||||
|
||||
(mf/defc multiple-handlers
|
||||
|
@ -344,7 +356,7 @@
|
|||
(mf/defc single-handlers
|
||||
[{:keys [shape zoom color disable-handlers] :as props}]
|
||||
(let [shape-id (:id shape)
|
||||
shape (geom/transform-shape shape {:round-coords? false})
|
||||
shape (geom/transform-shape shape)
|
||||
|
||||
on-resize
|
||||
(fn [current-position _initial-position event]
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[app.common.math :as mth]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.ui.formats :as fmt]
|
||||
[app.main.worker :as uw]
|
||||
[beicon.core :as rx]
|
||||
[clojure.set :as set]
|
||||
|
@ -54,7 +55,7 @@
|
|||
(get sr2 (if (= :x coord) :x1 :y1)))
|
||||
|
||||
distance (- to-c from-c)
|
||||
distance-str (-> distance (mth/precision 0) str)
|
||||
distance-str (str distance)
|
||||
half-point (half-point coord sr1 sr2)
|
||||
width (-> distance-str
|
||||
count
|
||||
|
@ -81,7 +82,7 @@
|
|||
:font-size (/ pill-text-font-size zoom)
|
||||
:fill "var(--color-white)"
|
||||
:text-anchor "middle"}
|
||||
(mth/precision distance 0)]])
|
||||
(fmt/format-number distance)]])
|
||||
|
||||
(let [p1 [(+ from-c (/ segment-gap zoom)) (+ half-point (/ segment-gap-side zoom))]
|
||||
p2 [(+ from-c (/ segment-gap zoom)) (- half-point (/ segment-gap-side zoom))]
|
||||
|
@ -110,7 +111,7 @@
|
|||
sr2 (:selrect sh2)
|
||||
c1 (if (= coord :x) :x1 :y1)
|
||||
c2 (if (= coord :x) :x2 :y2)
|
||||
dist (mth/precision (- (c1 sr2) (c2 sr1)) 0)]
|
||||
dist (- (c1 sr2) (c2 sr1))]
|
||||
[dist [sh1 sh2]]))
|
||||
|
||||
(defn overlap? [coord sh1 sh2]
|
||||
|
@ -134,8 +135,7 @@
|
|||
(-> (if (<= (coord sr) (coord selrect))
|
||||
(gsh/distance-selrect sr selrect)
|
||||
(gsh/distance-selrect selrect sr))
|
||||
coord
|
||||
(mth/precision 0))))
|
||||
coord)))
|
||||
|
||||
get-shapes-match
|
||||
(fn [pred? shapes]
|
||||
|
@ -149,9 +149,9 @@
|
|||
check-in-set
|
||||
(fn [value number-set]
|
||||
(->> number-set
|
||||
(some #(<= (mth/abs (- value %)) 1))))
|
||||
(some #(<= (mth/abs (- value %)) 0.01))))
|
||||
|
||||
;; Left/Top shapes and right/bottom shapes (depends on `coord` parameter
|
||||
;; Left/Top shapes and right/bottom shapes (depends on `coord` parameter)
|
||||
|
||||
;; Gets the distance to the current selection
|
||||
distances-xf (comp (map distance-to-selrect) (filter pos?))
|
||||
|
@ -195,6 +195,7 @@
|
|||
(map #(vector selrect (:selrect %))))
|
||||
|
||||
segments-to-display (d/concat-set other-shapes-segments selection-segments)]
|
||||
|
||||
segments-to-display))
|
||||
|
||||
(mf/defc shape-distance
|
||||
|
@ -217,8 +218,9 @@
|
|||
container-selrec (or (:selrect frame)
|
||||
(gsh/rect->selrect @refs/vbox))
|
||||
areas (gsh/selrect->areas container-selrec selrect)
|
||||
|
||||
query-side (fn [side]
|
||||
(let [rect (gsh/pad-selrec (areas side))]
|
||||
(let [rect (get areas side)]
|
||||
(if (and (> (:width rect) 0) (> (:height rect) 0))
|
||||
(->> (uw/ask! {:cmd :selection/query
|
||||
:page-id page-id
|
||||
|
@ -264,15 +266,10 @@
|
|||
(let [page-id (unchecked-get props "page-id")
|
||||
zoom (unchecked-get props "zoom")
|
||||
selected (unchecked-get props "selected")
|
||||
selected-shapes (mf/deref (refs/objects-by-id selected))
|
||||
selected-shapes (unchecked-get props "selected-shapes")
|
||||
frame-id (-> selected-shapes first :frame-id)
|
||||
frame (mf/deref (refs/object-by-id frame-id))
|
||||
local (mf/deref refs/workspace-local)
|
||||
|
||||
update-shape (fn [shape] (-> shape
|
||||
(update :modifiers merge (:modifiers local))
|
||||
gsh/transform-shape))
|
||||
selrect (->> selected-shapes (map update-shape) gsh/selection-rect)]
|
||||
selrect (gsh/selection-rect selected-shapes)]
|
||||
[:g.distance
|
||||
[:& shape-distance
|
||||
{:selrect selrect
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.spec :as us]
|
||||
[app.main.snap :as snap]
|
||||
|
@ -28,8 +27,6 @@
|
|||
(mf/defc snap-point
|
||||
[{:keys [point zoom]}]
|
||||
(let [{:keys [x y]} point
|
||||
x (mth/round x)
|
||||
y (mth/round y)
|
||||
cross-width (/ 3 zoom)]
|
||||
[:g
|
||||
[:line {:x1 (- x cross-width)
|
||||
|
@ -45,15 +42,15 @@
|
|||
|
||||
(mf/defc snap-line
|
||||
[{:keys [snap point zoom]}]
|
||||
[:line {:x1 (mth/round (:x snap))
|
||||
:y1 (mth/round (:y snap))
|
||||
:x2 (mth/round (:x point))
|
||||
:y2 (mth/round (:y point))
|
||||
[:line {:x1 (:x snap)
|
||||
:y1 (:y snap)
|
||||
:x2 (:x point)
|
||||
:y2 (:y point)
|
||||
:style {:stroke line-color :stroke-width (str (/ line-width zoom))}
|
||||
:opacity line-opacity}])
|
||||
|
||||
(defn get-snap
|
||||
[coord {:keys [shapes page-id remove-snap? modifiers]}]
|
||||
[coord {:keys [shapes page-id remove-snap? zoom modifiers]}]
|
||||
(let [shape (if (> (count shapes) 1)
|
||||
(->> shapes (map gsh/transform-shape) gsh/selection-rect (gsh/setup {:type :rect}))
|
||||
(->> shapes (first)))
|
||||
|
@ -69,7 +66,7 @@
|
|||
(->> (sp/shape-snap-points shape)
|
||||
(map #(vector frame-id %)))))
|
||||
(rx/flat-map (fn [[frame-id point]]
|
||||
(->> (snap/get-snap-points page-id frame-id remove-snap? point coord)
|
||||
(->> (snap/get-snap-points page-id frame-id remove-snap? zoom point coord)
|
||||
(rx/map #(vector point % coord)))))
|
||||
(rx/reduce conj []))))
|
||||
|
||||
|
@ -119,12 +116,19 @@
|
|||
(mf/use-effect
|
||||
(fn []
|
||||
(let [sub (->> subject
|
||||
(rx/switch-map #(rx/combine-latest (get-snap :x %)
|
||||
(get-snap :y %)))
|
||||
(rx/map (fn [result]
|
||||
(rx/switch-map
|
||||
(fn [props]
|
||||
(->> (get-snap :y props)
|
||||
(rx/combine-latest (get-snap :x props)))))
|
||||
|
||||
(rx/map
|
||||
(fn [result]
|
||||
(apply d/concat-vec (seq result))))
|
||||
(rx/subs #(let [rs (filter (fn [[_ snaps _]] (> (count snaps) 0)) %)]
|
||||
(reset! state rs))))]
|
||||
|
||||
(rx/subs
|
||||
(fn [data]
|
||||
(let [rs (filter (fn [[_ snaps _]] (> (count snaps) 0)) data)]
|
||||
(reset! state rs)))))]
|
||||
|
||||
;; On unmount callback
|
||||
#(rx/dispose! sub))))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
(ns app.main.ui.workspace.viewport.thumbnail-renderer
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.workspace.persistence :as dwp]
|
||||
[app.main.store :as st]
|
||||
[app.util.dom :as dom]
|
||||
|
@ -21,6 +22,10 @@
|
|||
(let [thumbnail-img (mf/use-ref nil)
|
||||
thumbnail-canvas (mf/use-ref nil)
|
||||
|
||||
{:keys [width height]} shape
|
||||
fixed-width (mth/clamp width 250 2000)
|
||||
fixed-height (/ (* height fixed-width) width)
|
||||
|
||||
on-dom-rendered
|
||||
(mf/use-callback
|
||||
(mf/deps (:id shape))
|
||||
|
@ -71,23 +76,23 @@
|
|||
_ (.rect canvas-context 0 0 canvas-width canvas-height)
|
||||
_ (set! (.-fillStyle canvas-context) background)
|
||||
_ (.fill canvas-context)
|
||||
_ (.drawImage canvas-context img-node 0 0)
|
||||
_ (.drawImage canvas-context img-node 0 0 canvas-width canvas-height)
|
||||
|
||||
data (.toDataURL canvas-node "image/jpeg" 0.8)]
|
||||
data (.toDataURL canvas-node "image/jpg" 1)]
|
||||
(on-thumbnail-data data))))]
|
||||
|
||||
[:div.frame-renderer {:ref on-dom-rendered
|
||||
:style {:display "none"}}
|
||||
[:img.thumbnail-img
|
||||
{:ref thumbnail-img
|
||||
:width (:width shape)
|
||||
:height (:height shape)
|
||||
:width width
|
||||
:height height
|
||||
:on-load on-image-load}]
|
||||
|
||||
[:canvas.thumbnail-canvas
|
||||
{:ref thumbnail-canvas
|
||||
:width (:width shape)
|
||||
:height (:height shape)}]]))
|
||||
:width fixed-width
|
||||
:height fixed-height}]]))
|
||||
|
||||
(mf/defc frame-renderer
|
||||
"Component in charge of creating thumbnails and storing them"
|
||||
|
|
|
@ -163,7 +163,7 @@
|
|||
(:width vbox 0)
|
||||
(:height vbox 0)]))
|
||||
|
||||
(defn translate-point-to-viewport-raw [viewport zoom pt]
|
||||
(defn translate-point-to-viewport [viewport zoom pt]
|
||||
(let [vbox (.. ^js viewport -viewBox -baseVal)
|
||||
brect (dom/get-bounding-rect viewport)
|
||||
brect (gpt/point (d/parse-integer (:left brect))
|
||||
|
@ -174,10 +174,6 @@
|
|||
(gpt/divide zoom)
|
||||
(gpt/add box))))
|
||||
|
||||
(defn translate-point-to-viewport [viewport zoom pt]
|
||||
(-> (translate-point-to-viewport-raw viewport zoom pt)
|
||||
(gpt/round 0)))
|
||||
|
||||
(defn get-cursor [cursor]
|
||||
(case cursor
|
||||
:hand cur/hand
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
:pattern-units "userSpaceOnUse"}
|
||||
[:path {:d "M 1 0 L 0 0 0 1"
|
||||
:style {:fill "none"
|
||||
:stroke "var(--color-info)"
|
||||
:stroke-opacity "0.2"
|
||||
:stroke "var(--color-gray-20)"
|
||||
:stroke-opacity "1"
|
||||
:stroke-width (str (/ 1 zoom))}}]]]
|
||||
[:rect {:x (:x vbox)
|
||||
:y (:y vbox)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.util.code-gen
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.common.text :as txt]
|
||||
[app.util.color :as uc]
|
||||
[cuerdas.core :as str]))
|
||||
|
@ -109,7 +108,7 @@
|
|||
(every? #(or (nil? %) (= % 0)) value)
|
||||
(or (nil? value) (= value 0))))
|
||||
|
||||
default-format (fn [value] (str (mth/precision value 2) "px"))
|
||||
default-format (fn [value] (str value "px"))
|
||||
format-property (fn [prop]
|
||||
(let [css-prop (or (prop to-prop) (name prop))
|
||||
format-fn (or (prop format) default-format)
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.path :as upg]
|
||||
[app.common.math :as mth]
|
||||
[app.common.path.commands :as upc]
|
||||
[clojure.set :as set]))
|
||||
|
||||
|
@ -402,9 +401,7 @@
|
|||
(rest segments))))))
|
||||
|
||||
(defn calculate-merge-points [group-segments points]
|
||||
(let [index-merge-point (fn [group] (vector group (-> (gpt/center-points group)
|
||||
(update :x mth/round)
|
||||
(update :y mth/round))))
|
||||
(let [index-merge-point (fn [group] (vector group (gpt/center-points group)))
|
||||
index-group (fn [point] (vector point (d/seek #(contains? % point) group-segments)))
|
||||
|
||||
group->merge-point (into {} (map index-merge-point) group-segments)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
"Performance profiling for react components."
|
||||
(:require-macros [app.util.perf])
|
||||
(:require
|
||||
[app.common.math :as math]
|
||||
[app.common.math :as mth]
|
||||
[rumext.alpha :as mf]
|
||||
[goog.functions :as f]
|
||||
["react" :as react]
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns debug
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.math :as mth]
|
||||
[app.common.pages.helpers :as cph]
|
||||
[app.common.transit :as t]
|
||||
[app.common.uuid :as uuid]
|
||||
|
@ -130,7 +129,7 @@
|
|||
ts (/ 1000 (* (- cur @last)))
|
||||
val (+ @avg (* (- ts @avg) 0.1))]
|
||||
|
||||
(obj/set! node "innerText" (mth/precision val 0))
|
||||
(obj/set! node "innerText" val)
|
||||
(vreset! last cur)
|
||||
(vreset! avg val)
|
||||
(do-thing)))))]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue