From 6f4cc4f543e0dffe4716f4afa455ee89ae51e5b5 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 22 Feb 2017 17:56:00 +0100 Subject: [PATCH] Minor refactor on ruler code. --- frontend/src/uxbox/main/data/workspace.cljs | 3 + .../src/uxbox/main/data/workspace/ruler.cljs | 92 +++++++++ .../src/uxbox/main/ui/workspace/canvas.cljs | 3 +- .../src/uxbox/main/ui/workspace/ruler.cljs | 181 +++++------------- 4 files changed, 148 insertions(+), 131 deletions(-) create mode 100644 frontend/src/uxbox/main/data/workspace/ruler.cljs diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 837b937c2..74865546c 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -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 diff --git a/frontend/src/uxbox/main/data/workspace/ruler.cljs b/frontend/src/uxbox/main/data/workspace/ruler.cljs new file mode 100644 index 000000000..bc80123bd --- /dev/null +++ b/frontend/src/uxbox/main/data/workspace/ruler.cljs @@ -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 + +(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.)) + diff --git a/frontend/src/uxbox/main/ui/workspace/canvas.cljs b/frontend/src/uxbox/main/ui/workspace/canvas.cljs index 5a7022db6..bcf7a1ef0 100644 --- a/frontend/src/uxbox/main/ui/workspace/canvas.cljs +++ b/frontend/src/uxbox/main/ui/workspace/canvas.cljs @@ -262,7 +262,8 @@ (canvas page zoom)) (if (contains? flags :grid) (grid))] - (ruler) + (when (contains? flags :ruler) + (ruler zoom)) (selrect)]]))) diff --git a/frontend/src/uxbox/main/ui/workspace/ruler.cljs b/frontend/src/uxbox/main/ui/workspace/ruler.cljs index 17eec921d..0cd2f2a35 100644 --- a/frontend/src/uxbox/main/ui/workspace/ruler.cljs +++ b/frontend/src/uxbox/main/ui/workspace/ruler.cljs @@ -6,146 +6,67 @@ ;; Copyright (c) 2015-2017 Juan de la Cruz (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))]))