Fix problems with extreme values

This commit is contained in:
alonso.torres 2022-03-02 15:50:06 +01:00
parent 999af63118
commit ed9400912c
59 changed files with 359 additions and 340 deletions

View file

@ -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)

View file

@ -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))

View file

@ -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

View file

@ -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]}]

View file

@ -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)))

View file

@ -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]}]

View file

@ -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)))

View file

@ -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]

View file

@ -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)))

View file

@ -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%;

View file

@ -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)))))))

View file

@ -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]]

View file

@ -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))

View file

@ -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]]

View file

@ -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

View file

@ -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))

View file

@ -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)

View file

@ -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)

View 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)))

View file

@ -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]}]

View file

@ -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"}

View file

@ -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}]

View file

@ -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)}]])]))

View file

@ -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)}]])]))

View file

@ -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)))

View file

@ -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)

View file

@ -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

View file

@ -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"]

View file

@ -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

View file

@ -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

View file

@ -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 "%")

View file

@ -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)

View file

@ -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)}]

View file

@ -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}]]]]]]))

View file

@ -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"}}

View file

@ -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

View file

@ -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)}])

View file

@ -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)))

View file

@ -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)

View file

@ -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)

View file

@ -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))

View file

@ -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

View file

@ -345,6 +345,7 @@
:zoom zoom
:transform transform
:selected selected
:selected-shapes selected-shapes
:page-id page-id}])
(when show-cursor-tooltip?

View file

@ -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

View file

@ -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

View file

@ -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?]}]

View file

@ -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

View file

@ -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

View file

@ -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)}}]])]))

View file

@ -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]

View file

@ -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

View file

@ -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))))

View file

@ -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"

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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]

View file

@ -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)))))]