mirror of
https://github.com/penpot/penpot.git
synced 2025-03-18 18:51:29 -05:00
Minor refactor on ruler code.
This commit is contained in:
parent
47f6d531b2
commit
6f4cc4f543
4 changed files with 148 additions and 131 deletions
|
@ -23,6 +23,7 @@
|
|||
[uxbox.main.data.workspace.scroll :as wscroll]
|
||||
[uxbox.main.data.workspace.drawing :as wdrawing]
|
||||
[uxbox.main.data.workspace.selrect :as wselrect]
|
||||
[uxbox.main.data.workspace.ruler :as wruler]
|
||||
[uxbox.util.uuid :as uuid]
|
||||
[uxbox.util.spec :as us]
|
||||
[uxbox.util.forms :as sc]
|
||||
|
@ -39,6 +40,8 @@
|
|||
(def close-drawing-path wdrawing/close-drawing-path)
|
||||
(def select-for-drawing wdrawing/select-for-drawing)
|
||||
(def start-selrect wselrect/start-selrect)
|
||||
(def start-ruler wruler/start-ruler)
|
||||
(def clear-ruler wruler/clear-ruler)
|
||||
|
||||
;; --- Initialize Workspace
|
||||
|
||||
|
|
92
frontend/src/uxbox/main/data/workspace/ruler.cljs
Normal file
92
frontend/src/uxbox/main/data/workspace/ruler.cljs
Normal file
|
@ -0,0 +1,92 @@
|
|||
;; 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) 2015-2017 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns uxbox.main.data.workspace.ruler
|
||||
"Workspace ruler related events. Mostly or all events
|
||||
are related to UI logic."
|
||||
(:require [beicon.core :as rx]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.util.mixins :as mx :include-macros true]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.point :as gpt]))
|
||||
|
||||
;; --- Constants
|
||||
|
||||
(declare stop-ruler?)
|
||||
(declare clear-ruler)
|
||||
(declare update-ruler)
|
||||
|
||||
(def ^:private immanted-zones
|
||||
(let [transform #(vector (- % 7) (+ % 7) %)
|
||||
right (map transform (range 0 181 15))
|
||||
left (map (comp transform -) (range 0 181 15))]
|
||||
(vec (concat right left))))
|
||||
|
||||
(defn- align-position
|
||||
[pos]
|
||||
(let [angle (gpt/angle pos)]
|
||||
(reduce (fn [pos [a1 a2 v]]
|
||||
(if (< a1 angle a2)
|
||||
(reduced (gpt/update-angle pos v))
|
||||
pos))
|
||||
pos
|
||||
immanted-zones)))
|
||||
|
||||
;; --- Start Ruler
|
||||
|
||||
(deftype StartRuler []
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pos (get-in state [:workspace :pointer :viewport])]
|
||||
(assoc-in state [:workspace :ruler] [pos pos])))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stoper (->> (rx/filter #(= ::uev/interrupt %) stream)
|
||||
(rx/take 1))]
|
||||
(->> streams/mouse-position
|
||||
(rx/take-until stoper)
|
||||
(rx/map (juxt :viewport :ctrl))
|
||||
(rx/map (fn [[pt ctrl?]]
|
||||
(update-ruler pt ctrl?)))))))
|
||||
|
||||
(defn start-ruler
|
||||
[]
|
||||
(StartRuler.))
|
||||
|
||||
;; --- Update Ruler
|
||||
|
||||
(deftype UpdateRuler [point ctrl?]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [[start end] (get-in state [:workspace :ruler])]
|
||||
(if-not ctrl?
|
||||
(assoc-in state [:workspace :ruler] [start point])
|
||||
(let [end (-> (gpt/subtract point start)
|
||||
(align-position)
|
||||
(gpt/add start))]
|
||||
(assoc-in state [:workspace :ruler] [start end]))))))
|
||||
|
||||
(defn update-ruler
|
||||
[point ctrl?]
|
||||
{:pre [(gpt/point? point)
|
||||
(boolean? ctrl?)]}
|
||||
(UpdateRuler. point ctrl?))
|
||||
|
||||
;; --- Clear Ruler
|
||||
|
||||
(deftype ClearRuler []
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :workspace dissoc :ruler)))
|
||||
|
||||
(defn clear-ruler
|
||||
[]
|
||||
(ClearRuler.))
|
||||
|
|
@ -262,7 +262,8 @@
|
|||
(canvas page zoom))
|
||||
(if (contains? flags :grid)
|
||||
(grid))]
|
||||
(ruler)
|
||||
(when (contains? flags :ruler)
|
||||
(ruler zoom))
|
||||
(selrect)]])))
|
||||
|
||||
|
||||
|
|
|
@ -6,146 +6,67 @@
|
|||
;; Copyright (c) 2015-2017 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
|
||||
(ns uxbox.main.ui.workspace.ruler
|
||||
(:require [sablono.core :as html :refer-macros [html]]
|
||||
[rum.core :as rum]
|
||||
(:require [lentes.core :as l]
|
||||
[potok.core :as ptk]
|
||||
[beicon.core :as rx]
|
||||
[uxbox.main.constants :as c]
|
||||
[uxbox.main.data.workspace :as udw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.streams :as streams]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.user-events :as uev]
|
||||
[uxbox.util.math :as mth]
|
||||
[uxbox.util.mixins :as mx :include-macros true]
|
||||
[uxbox.util.geom.point :as gpt]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
||||
(def ^:private immanted-zones
|
||||
(let [transform #(vector (- % 7) (+ % 7) %)]
|
||||
(concat
|
||||
(mapv transform (range 0 181 15))
|
||||
(mapv (comp transform -) (range 0 181 15)))))
|
||||
(def ruler-points-ref
|
||||
(-> (l/key :ruler)
|
||||
(l/derive refs/workspace)))
|
||||
|
||||
(defn- resolve-position
|
||||
[own pt]
|
||||
(let [overlay (mx/ref-node own "overlay")
|
||||
brect (.getBoundingClientRect overlay)
|
||||
bpt (gpt/point (.-left brect) (.-top brect))]
|
||||
(gpt/subtract pt bpt)))
|
||||
|
||||
(defn- get-position
|
||||
[own event]
|
||||
(->> (gpt/point (.-clientX event)
|
||||
(.-clientY event))
|
||||
(resolve-position own)))
|
||||
|
||||
(defn- on-mouse-down
|
||||
[own local event]
|
||||
(dom/stop-propagation event)
|
||||
(let [pos (get-position own event)]
|
||||
(reset! local {:active true :pos1 pos :pos2 pos})))
|
||||
|
||||
(defn- on-mouse-up
|
||||
[own local event]
|
||||
(dom/stop-propagation event)
|
||||
(swap! local assoc :active false))
|
||||
|
||||
(defn- align-position
|
||||
[angle pos]
|
||||
(reduce (fn [pos [a1 a2 v]]
|
||||
(if (< a1 angle a2)
|
||||
(reduced (gpt/update-angle pos v))
|
||||
pos))
|
||||
pos
|
||||
immanted-zones))
|
||||
|
||||
(defn- overlay-will-mount
|
||||
[own local]
|
||||
(letfn [(on-value-aligned [pos2]
|
||||
(let [center (:pos1 @local)]
|
||||
(as-> pos2 $
|
||||
(gpt/subtract $ center)
|
||||
(align-position (gpt/angle $) $)
|
||||
(gpt/add $ center)
|
||||
(swap! local assoc :pos2 $))))
|
||||
|
||||
(on-value-simple [pos2]
|
||||
(swap! local assoc :pos2 pos2))
|
||||
|
||||
(on-value [[pos ctrl?]]
|
||||
(if ctrl?
|
||||
(on-value-aligned pos)
|
||||
(on-value-simple pos)))]
|
||||
|
||||
(let [stream (->> streams/window-mouse-position
|
||||
(rx/filter #(:active @local))
|
||||
(rx/map #(resolve-position own %))
|
||||
(rx/with-latest vector streams/mouse-position-ctrl))
|
||||
sub (rx/on-value stream on-value)]
|
||||
(assoc own ::sub sub))))
|
||||
|
||||
(defn- overlay-will-unmount
|
||||
[own]
|
||||
(let [subscription (::sub own)]
|
||||
(rx/cancel! subscription)
|
||||
(dissoc own ::sub)))
|
||||
|
||||
(declare overlay-line-render)
|
||||
|
||||
(defn- overlay-render
|
||||
[own local]
|
||||
(let [p1 (:pos1 @local)
|
||||
p2 (:pos2 @local)]
|
||||
(html
|
||||
[:svg {:on-mouse-down #(on-mouse-down own local %)
|
||||
:on-mouse-up #(on-mouse-up own local %)
|
||||
:ref "overlay"}
|
||||
[:rect {:style {:fill "transparent"
|
||||
:stroke "transparent"
|
||||
:cursor "cell"}
|
||||
:width c/viewport-width
|
||||
:height c/viewport-height}]
|
||||
(if (and p1 p2)
|
||||
(overlay-line-render own p1 p2))])))
|
||||
|
||||
(def overlay
|
||||
(mx/component
|
||||
{:render #(overlay-render % (:rum/local %))
|
||||
:will-mount #(overlay-will-mount % (:rum/local %))
|
||||
:will-unmount overlay-will-unmount
|
||||
:name "overlay"
|
||||
:mixins [mx/static (mx/local) mx/reactive]}))
|
||||
|
||||
(defn- overlay-line-render
|
||||
[own center pt]
|
||||
(let [distance (-> (gpt/distance
|
||||
(gpt/divide pt @refs/selected-zoom)
|
||||
(gpt/divide center @refs/selected-zoom))
|
||||
(mth/precision 4))
|
||||
(mx/defc ruler-line
|
||||
{:mixins [mx/static]}
|
||||
[zoom [center pt]]
|
||||
(let [distance (-> (gpt/distance (gpt/divide pt zoom)
|
||||
(gpt/divide center zoom))
|
||||
(mth/precision 2))
|
||||
angle (-> (gpt/angle pt center)
|
||||
(mth/precision 4))
|
||||
{x1 :x y1 :y} center
|
||||
{x2 :x y2 :y} pt]
|
||||
(html
|
||||
[:g
|
||||
[:line {:x1 x1 :y1 y1
|
||||
:x2 x2 :y2 y2
|
||||
:style {:cursor "cell"}
|
||||
:stroke-width "1"
|
||||
:stroke "red"}]
|
||||
[:text
|
||||
{:transform (str "translate(" (+ x2 15) "," (- y2 10) ")")}
|
||||
[:tspan {:x "0" :dy="1.2em"}
|
||||
(str distance " px")]
|
||||
[:tspan {:x "0" :y "20" :dy="1.2em"}
|
||||
(str angle "°")]]])))
|
||||
(mth/precision 2))]
|
||||
[:g
|
||||
[:line {:x1 (:x center)
|
||||
:y1 (:y center)
|
||||
:x2 (:x pt)
|
||||
:y2 (:y pt)
|
||||
:style {:cursor "cell"}
|
||||
:stroke-width "1"
|
||||
:stroke "red"}]
|
||||
[:text
|
||||
{:transform (str "translate(" (+ (:x pt) 15) "," (- (:y pt) 10) ")")}
|
||||
[:tspan {:x "0"}
|
||||
(str distance " px")]
|
||||
[:tspan {:x "0" :y "20"}
|
||||
(str angle "°")]]]))
|
||||
|
||||
(defn- ruler-render
|
||||
[own]
|
||||
(let [flags (mx/react refs/flags)]
|
||||
(when (contains? flags :ruler)
|
||||
(overlay))))
|
||||
|
||||
(def ruler
|
||||
(mx/component
|
||||
{:render ruler-render
|
||||
:name "ruler"
|
||||
:mixins [mx/static mx/reactive (mx/local)]}))
|
||||
(mx/defc ruler
|
||||
{:mixins [mx/static mx/reactive]
|
||||
:will-unmount (fn [own]
|
||||
(st/emit! ::uev/interrupt
|
||||
(udw/clear-ruler))
|
||||
own)}
|
||||
[zoom]
|
||||
(letfn [(on-mouse-down [event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! ::uev/interrupt
|
||||
(udw/start-ruler)))
|
||||
(on-mouse-up [event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! ::uev/interrupt))]
|
||||
[:svg {:on-mouse-down on-mouse-down
|
||||
:on-mouse-up on-mouse-up}
|
||||
[:rect {:style {:fill "transparent"
|
||||
:stroke "transparent"
|
||||
:cursor "cell"}
|
||||
:width c/viewport-width
|
||||
:height c/viewport-height}]
|
||||
(when-let [points (mx/react ruler-points-ref)]
|
||||
(ruler-line zoom points))]))
|
||||
|
|
Loading…
Add table
Reference in a new issue