0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-17 10:11:22 -05:00

Merge branch 'alignment'

This commit is contained in:
Andrey Antukh 2016-04-10 18:51:41 +03:00
commit 574d78871a
No known key found for this signature in database
GPG key ID: 4DFEBCB8316A8B95
31 changed files with 666 additions and 318 deletions

View file

@ -25,5 +25,8 @@ var TopLevel = {
"value": function() {},
"identifier": function() {},
"getBoundingClientRect": function() {},
"getBBox": function() {}
"getBBox": function() {},
"addEventListener": function() {},
"postMessage": function() {},
"data": function() {}
};

View file

@ -7,7 +7,7 @@
(ra/start-figwheel!
{:figwheel-options {:css-dirs ["resources/public/css"]}
:build-ids ["dev"]
:build-ids ["dev" "worker"]
:all-builds
[{:id "dev"
:figwheel {:on-jsload "uxbox.ui/init"}
@ -20,10 +20,24 @@
"https://test.uxbox.io/api"}
:warnings {:ns-var-clash false}
:pretty-print true
:language-in :ecmascript5
:language-in :ecmascript6
:language-out :ecmascript5
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js"
:verbose true}}
{:id "worker"
:source-paths ["src" "vendor"]
:compiler {:main 'uxbox.worker
:asset-path "js"
:parallel-build false
:optimizations :simple
:warnings {:ns-var-clash false}
:pretty-print true
:static-fns true
:language-in :ecmascript6
:language-out :ecmascript5
:output-to "resources/public/js/worker.js"
:verbose true}}]})
(ra/cljs-repl)
(ra/cljs-repl "dev")

View file

@ -1,2 +1,2 @@
#!/bin/sh
lein trampoline run -m clojure.main scripts/watch.clj
lein trampoline run -m clojure.main scripts/watch-tests.clj

22
src/uxbox/constants.cljs Normal file
View file

@ -0,0 +1,22 @@
;; 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-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.constants)
(def ^:const grid-x-axis 10)
(def ^:const grid-y-axis 10)
(def ^:const viewport-width 4000)
(def ^:const viewport-height 4000)
(def ^:const canvas-start-x 1200)
(def ^:const canvas-start-y 1200)
(def ^:const canvas-scroll-padding 50)
(def ^:const canvas-start-scroll-x (- canvas-start-x canvas-scroll-padding))
(def ^:const canvas-start-scroll-y (- canvas-start-y canvas-scroll-padding))

View file

@ -94,10 +94,17 @@
(let [shape (get-in state [:shapes-by-id id])]
(stsh/dissoc-shape state shape)))))
(defn update-shape
"Just updates in place the shape."
[{:keys [id] :as shape}]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(update-in state [:shapes-by-id id] merge shape))))
(defn move-shape
"Mark a shape selected for drawing in the canvas."
"Move shape using relative position (delta)."
[sid delta]
{:pre [(gpt/point? delta)]}
(reify
udp/IPageUpdate
rs/UpdateEvent
@ -338,3 +345,144 @@
(-apply-update [_ state]
(stsh/drop-shape state sid tid loc))))
(defn select-shape
"Mark a shape selected for drawing in the canvas."
[id]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(let [selected (get-in state [:workspace :selected])]
(if (contains? selected id)
(update-in state [:workspace :selected] disj id)
(update-in state [:workspace :selected] conj id))))))
(defn select-shapes
"Select shapes that matches the select rect."
[selrect]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(let [pageid (get-in state [:workspace :page])
xf (comp
(filter #(= (:page %) pageid))
(remove :hidden)
(remove :blocked)
(map sh/outer-rect')
(filter #(sh/contained-in? % selrect))
(map :id))]
(->> (into #{} xf (vals (:shapes-by-id state)))
(assoc-in state [:workspace :selected]))))))
;; --- Events (implicit) (for selected)
(defn deselect-all
"Mark a shape selected for drawing in the canvas."
[]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(assoc-in state [:workspace :selected] #{}))))
(defn group-selected
[]
(letfn [(update-shapes-on-page [state pid selected group]
(as-> (get-in state [:pages-by-id pid :shapes]) $
(remove selected $)
(into [group] $)
(assoc-in state [:pages-by-id pid :shapes] $)))
(update-shapes-on-index [state shapes group]
(reduce (fn [state {:keys [id] :as shape}]
(as-> shape $
(assoc $ :group group)
(assoc-in state [:shapes-by-id id] $)))
state
shapes))
(valid-selection? [shapes]
(let [groups (into #{} (map :group shapes))]
(= 1 (count groups))))]
(reify
udp/IPageUpdate
rs/UpdateEvent
(-apply-update [_ state]
(let [shapes-by-id (get state :shapes-by-id)
sid (random-uuid)
pid (get-in state [:workspace :page])
selected (get-in state [:workspace :selected])
selected' (map #(get shapes-by-id %) selected)
group {:type :builtin/group
:name (str "Group " (rand-int 1000))
:items (into [] selected)
:id sid
:page pid}]
(if (valid-selection? selected')
(as-> state $
(update-shapes-on-index $ selected' sid)
(update-shapes-on-page $ pid selected sid)
(update $ :shapes-by-id assoc sid group)
(update $ :workspace assoc :selected #{}))
state))))))
;; TODO: maybe split in two separate events
(defn duplicate-selected
[]
(reify
udp/IPageUpdate
rs/UpdateEvent
(-apply-update [_ state]
(let [selected (get-in state [:workspace :selected])]
(stsh/duplicate-shapes state selected)))))
(defn delete-selected
"Deselect all and remove all selected shapes."
[]
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(let [selected (get-in state [:workspace :selected])]
(rx/from-coll
(into [(deselect-all)] (map #(delete-shape %) selected)))))))
(defn move-selected
"Move a minimal position unit the selected shapes."
([dir] (move-selected dir 1))
([dir n]
{:pre [(contains? #{:up :down :right :left} dir)]}
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(let [selected (get-in state [:workspace :selected])
delta (case dir
:up (gpt/point 0 (- n))
:down (gpt/point 0 n)
:right (gpt/point n 0)
:left (gpt/point (- n) 0))]
(rx/from-coll
(map #(move-shape % delta) selected)))))))
(defn update-selected-shapes-fill
"Update the fill related attributed on
selected shapes."
[opts]
(sc/validate! +shape-fill-attrs-schema+ opts)
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(rx/from-coll
(->> (get-in state [:workspace :selected])
(map #(update-fill-attrs % opts)))))))
(defn update-selected-shapes-stroke
"Update the fill related attributed on
selected shapes."
[opts]
(sc/validate! +shape-stroke-attrs-schema+ opts)
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(rx/from-coll
(->> (get-in state [:workspace :selected])
(map #(update-stroke-attrs % opts)))))))

View file

@ -0,0 +1,32 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.data.worker
"Worker related api and initialization events."
(:require [beicon.core :as rx]
[uxbox.rstore :as rs]
[uxbox.constants :as c]
[uxbox.util.workers :as uw]))
(defonce worker (uw/init "/js/worker.js"))
;; --- Worker Initialization
(defrecord InitializeWorker [id]
rs/EffectEvent
(-apply-effect [_ state]
(let [page (get-in state [:pages-by-id id])
opts (:options page)
message {:cmd :grid/init
:width c/viewport-width
:height c/viewport-height
:x-axis (:grid/x-axis opts c/grid-x-axis)
:y-axis (:grid/y-axis opts c/grid-y-axis)}]
(uw/send! worker message))))
(defn initialize
[id]
(InitializeWorker. id))

View file

@ -10,39 +10,45 @@
[beicon.core :as rx]
[uxbox.shapes :as sh]
[uxbox.rstore :as rs]
[uxbox.router :as r]
[uxbox.state :as st]
[uxbox.state.shapes :as stsh]
[uxbox.schema :as sc]
[uxbox.xforms :as xf]
[uxbox.shapes :as sh]
[uxbox.data.pages :as udp]
[uxbox.data.shapes :as uds]
[uxbox.data.worker :as wrk]
[uxbox.util.datetime :as dt]
[uxbox.util.geom.point :as gpt]
[uxbox.util.data :refer (index-of)]))
[uxbox.util.geom.point :as gpt]))
;; --- Events (concrete)
;; --- Workspace Initialization
(defrecord InitializeWorkspace [project page]
rs/UpdateEvent
(-apply-update [_ state]
(if (:workspace state)
(update state :workspace merge
{:project project
:page page
:selected #{}
:drawing nil})
(assoc state :workspace
{:project project
:zoom 1
:page page
:flags #{:layers :element-options}
:selected #{}
:drawing nil})))
rs/WatchEvent
(-apply-watch [_ state s]
(if (get-in state [:pages-by-id page])
(rx/of (wrk/initialize page))
(->> (rx/filter udp/pages-fetched? s)
(rx/take 1)
(rx/map #(wrk/initialize page))))))
(defn initialize
"Initialize the workspace state."
[project page]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(if (:workspace state)
(update state :workspace merge
{:project project
:page page
:selected #{}
:drawing nil})
(assoc state :workspace
{:project project
:zoom 1
:page page
:flags #{:layers :element-options}
:selected #{}
:drawing nil})))))
(InitializeWorkspace. project page))
(defn toggle-flag
"Toggle the enabled flag of the specified tool."
@ -65,146 +71,6 @@
(assoc-in state [:workspace :drawing] shape)
(update-in state [:workspace] dissoc :drawing)))))
(defn select-shape
"Mark a shape selected for drawing in the canvas."
[id]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(let [selected (get-in state [:workspace :selected])]
(if (contains? selected id)
(update-in state [:workspace :selected] disj id)
(update-in state [:workspace :selected] conj id))))))
(defn select-shapes
"Select shapes that matches the select rect."
[selrect]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(let [pageid (get-in state [:workspace :page])
xf (comp
(filter #(= (:page %) pageid))
(remove :hidden)
(remove :blocked)
(map sh/outer-rect')
(filter #(sh/contained-in? % selrect))
(map :id))]
(->> (into #{} xf (vals (:shapes-by-id state)))
(assoc-in state [:workspace :selected]))))))
;; --- Events (implicit) (for selected)
(defn deselect-all
"Mark a shape selected for drawing in the canvas."
[]
(reify
rs/UpdateEvent
(-apply-update [_ state]
(assoc-in state [:workspace :selected] #{}))))
(defn group-selected
[]
(letfn [(update-shapes-on-page [state pid selected group]
(as-> (get-in state [:pages-by-id pid :shapes]) $
(remove selected $)
(into [group] $)
(assoc-in state [:pages-by-id pid :shapes] $)))
(update-shapes-on-index [state shapes group]
(reduce (fn [state {:keys [id] :as shape}]
(as-> shape $
(assoc $ :group group)
(assoc-in state [:shapes-by-id id] $)))
state
shapes))
(valid-selection? [shapes]
(let [groups (into #{} (map :group shapes))]
(= 1 (count groups))))]
(reify
udp/IPageUpdate
rs/UpdateEvent
(-apply-update [_ state]
(let [shapes-by-id (get state :shapes-by-id)
sid (random-uuid)
pid (get-in state [:workspace :page])
selected (get-in state [:workspace :selected])
selected' (map #(get shapes-by-id %) selected)
group {:type :builtin/group
:name (str "Group " (rand-int 1000))
:items (into [] selected)
:id sid
:page pid}]
(if (valid-selection? selected')
(as-> state $
(update-shapes-on-index $ selected' sid)
(update-shapes-on-page $ pid selected sid)
(update $ :shapes-by-id assoc sid group)
(update $ :workspace assoc :selected #{}))
state))))))
;; TODO: maybe split in two separate events
(defn duplicate-selected
[]
(reify
udp/IPageUpdate
rs/UpdateEvent
(-apply-update [_ state]
(let [selected (get-in state [:workspace :selected])]
(stsh/duplicate-shapes state selected)))))
(defn delete-selected
"Deselect all and remove all selected shapes."
[]
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(let [selected (get-in state [:workspace :selected])]
(rx/from-coll
(into [(deselect-all)] (map #(uds/delete-shape %) selected)))))))
(defn move-selected
"Move a minimal position unit the selected shapes."
([dir] (move-selected dir 1))
([dir n]
{:pre [(contains? #{:up :down :right :left} dir)]}
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(let [selected (get-in state [:workspace :selected])
delta (case dir
:up (gpt/point 0 (- n))
:down (gpt/point 0 n)
:right (gpt/point n 0)
:left (gpt/point (- n) 0))]
(rx/from-coll
(map #(uds/move-shape % delta) selected)))))))
(defn update-selected-shapes-fill
"Update the fill related attributed on
selected shapes."
[opts]
(sc/validate! uds/+shape-fill-attrs-schema+ opts)
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(rx/from-coll
(->> (get-in state [:workspace :selected])
(map #(uds/update-fill-attrs % opts)))))))
(defn update-selected-shapes-stroke
"Update the fill related attributed on
selected shapes."
[opts]
(sc/validate! uds/+shape-stroke-attrs-schema+ opts)
(reify
rs/WatchEvent
(-apply-watch [_ state s]
(rx/from-coll
(->> (get-in state [:workspace :selected])
(map #(uds/update-stroke-attrs % opts)))))))
;; --- Copy to Clipboard
(defrecord CopyToClipboard []

View file

@ -13,7 +13,7 @@
[hodgepodge.core :refer (local-storage)]
[promesa.core :as p :include-macros true]
[beicon.core :as rx]
[uxbox.transit :as t]
[uxbox.util.transit :as t]
[uxbox.state :as ust])
(:import [goog.Uri QueryData]))

View file

@ -211,7 +211,7 @@
[shape _]
(throw (ex-info "Not implemented (size)" (select-keys shape [:type]))))
;; Move
;; Move (with deltas)
(defmethod move ::rect
[shape {dx :x dy :y}]

View file

@ -20,20 +20,20 @@
(declare handlers)
(defmethod uusc/render-component :default ;; :builtin/icon
[own shape]
(let [{:keys [id x y width height group]} shape
selected (rum/react uusc/selected-shapes-l)
selected? (contains? selected id)
on-mouse-down #(uusi/on-mouse-down % shape selected)
on-mouse-up #(uusi/on-mouse-up % shape)]
(html
[:g.shape {:class (when selected? "selected")
:on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up}
(uusc/render-shape shape #(uusc/shape %))
(when (and selected? (= (count selected) 1))
(handlers shape))])))
;; (defmethod uusc/render-component :default ;; :builtin/icon
;; [own shape]
;; (let [{:keys [id x y width height group]} shape
;; selected (rum/react uusc/selected-shapes-l)
;; selected? (contains? selected id)
;; on-mouse-down #(uusi/on-mouse-down % shape selected)
;; on-mouse-up #(uusi/on-mouse-up % shape)]
;; (html
;; [:g.shape {:class (when selected? "selected")
;; :on-mouse-down on-mouse-down
;; :on-mouse-up on-mouse-up}
;; (uusc/render-shape shape #(uusc/shape %))
;; (when (and selected? (= (count selected) 1))
;; (handlers shape))])))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Circle Handlers

View file

@ -7,6 +7,7 @@
[uxbox.state :as st]
[uxbox.shapes :as ush]
[uxbox.data.workspace :as dw]
[uxbox.data.shapes :as uds]
[uxbox.ui.core :as uuc]
[uxbox.ui.mixins :as mx]
[uxbox.ui.keyboard :as kbd]
@ -28,16 +29,16 @@
(and (not selected?) (empty? selected))
(do
(dom/stop-propagation event)
(uuc/acquire-action! "ui.shape.move")
(rs/emit! (dw/select-shape id)))
(rs/emit! (uds/select-shape id))
(uuc/acquire-action! "ui.shape.move"))
(and (not selected?) (not (empty? selected)))
(do
(dom/stop-propagation event)
(if (kbd/shift? event)
(rs/emit! (dw/select-shape id))
(rs/emit! (dw/deselect-all)
(dw/select-shape id))))
(rs/emit! (uds/select-shape id))
(rs/emit! (uds/deselect-all)
(uds/select-shape id))))
:else
(do

View file

@ -7,7 +7,7 @@
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.shapes :as ush]
[uxbox.data.shapes :as ds]
[uxbox.data.shapes :as uds]
[uxbox.data.workspace :as dw]
[uxbox.ui.core :as uuc]
[uxbox.ui.mixins :as mx]
@ -34,15 +34,15 @@
(do
(dom/stop-propagation event)
(uuc/acquire-action! "ui.shape.move")
(rs/emit! (dw/select-shape id)))
(rs/emit! (uds/select-shape id)))
(and (not selected?) (not (empty? selected)))
(do
(dom/stop-propagation event)
(if (kbd/shift? event)
(rs/emit! (dw/select-shape id))
(rs/emit! (dw/deselect-all)
(dw/select-shape id))))
(rs/emit! (uds/select-shape id))
(rs/emit! (uds/deselect-all)
(uds/select-shape id))))
:else
(do
@ -80,7 +80,7 @@
(on-input [ev]
(let [content (dom/event->inner-text ev)
sid (:id (first (:rum/props own)))]
(rs/emit! (ds/update-text sid {:content content}))))]
(rs/emit! (uds/update-text sid {:content content}))))]
(let [dom (mx/get-ref-dom own "main")
dom2 (mx/get-ref-dom own "container")
key1 (events/listen dom EventType.DBLCLICK on-double-click)

View file

@ -1,7 +1,15 @@
;; 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-2016 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.ui.workspace
(:require [sablono.core :as html :refer-macros [html]]
[rum.core :as rum]
[beicon.core :as rx]
[uxbox.constants :as c]
[uxbox.rstore :as rs]
[uxbox.data.workspace :as dw]
[uxbox.data.pages :as udp]
@ -42,8 +50,8 @@
dom (mx/get-ref-dom own "workspace-canvas")]
;; Set initial scroll position
(set! (.-scrollLeft dom) (* wb/canvas-start-scroll-x @wb/zoom-l))
(set! (.-scrollTop dom) (* wb/canvas-start-scroll-y @wb/zoom-l))
(set! (.-scrollLeft dom) (* c/canvas-start-scroll-x @wb/zoom-l))
(set! (.-scrollTop dom) (* c/canvas-start-scroll-y @wb/zoom-l))
(assoc own ::sub1 sub1 ::sub2 sub2)))
@ -89,8 +97,8 @@
(rs/emit! (dw/decrease-zoom)))
(let [dom (mx/get-ref-dom own "workspace-canvas")]
(set! (.-scrollLeft dom) (* wb/canvas-start-scroll-x @wb/zoom-l))
(set! (.-scrollTop dom) (* wb/canvas-start-scroll-y @wb/zoom-l)))))
(set! (.-scrollLeft dom) (* c/canvas-start-scroll-x @wb/zoom-l))
(set! (.-scrollTop dom) (* c/canvas-start-scroll-y @wb/zoom-l)))))
(defn- workspace-render
[own projectid]

View file

@ -0,0 +1,37 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.ui.workspace.align
"Shape alignmen impl."
(:require [beicon.core :as rx]
[lentes.core :as l]
[uxbox.state :as st]
[uxbox.shapes :as sh]
[uxbox.data.worker :refer (worker)]
[uxbox.ui.workspace.base :as wb]
[uxbox.util.geom.point :as gpt]
[uxbox.util.workers :as uw]))
(defn- move
[shape p1]
(let [dx (- (:x2 shape) (:x1 shape))
dy (- (:y2 shape) (:y1 shape))
p2 (gpt/add p1 [dx dy])]
(assoc shape
:x1 (:x p1)
:y1 (:y p1)
:x2 (:x p2)
:y2 (:y p2))))
(defn translate
[{:keys [x1 y1] :as shape}]
(let [message {:cmd :grid/align
:point (gpt/point x1 y1)}]
(->> (uw/ask! worker message)
(rx/map (fn [{:keys [point]}]
(if point
(move shape point)
shape))))))

View file

@ -18,9 +18,7 @@
[goog.events :as events])
(:import goog.events.EventType))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Lenses
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Lenses
(def ^:const workspace-l
(as-> (l/in [:workspace]) $
@ -60,9 +58,7 @@
(-> (l/in [:workspace :zoom])
(l/focus-atom st/state)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Scroll Stream
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Scroll Stream
(defonce scroll-b (rx/bus))
@ -75,9 +71,7 @@
(defonce scroll-a
(rx/to-atom scroll-s))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Mouse Position Stream
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Mouse Position Stream
(defonce mouse-b (rx/bus))
(defonce mouse-s
@ -119,16 +113,3 @@
(rx/buffer 2 1)
(rx/map coords-delta)
(rx/share)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Constants
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:const viewport-width 4000)
(def ^:const viewport-height 4000)
(def ^:const canvas-start-x 1200)
(def ^:const canvas-start-y 1200)
(def ^:const canvas-scroll-padding 50)
(def ^:const canvas-start-scroll-x (- canvas-start-x canvas-scroll-padding))
(def ^:const canvas-start-scroll-y (- canvas-start-y canvas-scroll-padding))

View file

@ -11,10 +11,12 @@
[beicon.core :as rx]
[lentes.core :as l]
[goog.events :as events]
[uxbox.constants :as c]
[uxbox.rstore :as rs]
[uxbox.shapes :as sh]
[uxbox.data.projects :as dp]
[uxbox.data.workspace :as dw]
[uxbox.data.shapes :as uds]
[uxbox.util.geom.point :as gpt]
[uxbox.util.dom :as dom]
[uxbox.util.data :refer (parse-int)]
@ -57,8 +59,8 @@
(let [workspace (rum/react uuwb/workspace-l)
flags (:flags workspace)]
(html
[:svg.page-canvas {:x uuwb/canvas-start-x
:y uuwb/canvas-start-y
[:svg.page-canvas {:x c/canvas-start-x
:y c/canvas-start-y
:ref (str "canvas" id)
:width width
:height height}
@ -69,9 +71,7 @@
(for [item (reverse (:shapes page))]
(-> (uus/shape item)
(rum/with-key (str item))))
(draw-area)]]
(when (contains? flags :grid)
(grid))])))
(draw-area)]]])))
(def canvas
(mx/component
@ -87,12 +87,13 @@
[own]
(let [workspace (rum/react uuwb/workspace-l)
page (rum/react uuwb/page-l)
flags (:flags workspace)
drawing? (:drawing workspace)
zoom (or (:zoom workspace) 1)]
(letfn [(on-mouse-down [event]
(dom/stop-propagation event)
(when-not (empty? (:selected workspace))
(rs/emit! (dw/deselect-all)))
(rs/emit! (uds/deselect-all)))
(if-let [shape (:drawing workspace)]
(uuc/acquire-action! "ui.shape.draw")
(uuc/acquire-action! "ui.selrect")))
@ -101,17 +102,19 @@
(uuc/release-action! "ui.shape"
"ui.selrect"))]
(html
[:svg.viewport {:width (* uuwb/viewport-width zoom)
:height (* uuwb/viewport-height zoom)
[:svg.viewport {:width (* c/viewport-width zoom)
:height (* c/viewport-height zoom)
:ref "viewport"
:class (when drawing? "drawing")
:on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up}
[:g.zoom {:transform (str "scale(" zoom ", " zoom ")")}
(if page
(canvas page))]
(ruler)
(selrect)]))))
(canvas page))
(if (contains? flags :grid)
(grid))]
(ruler)
(selrect)]))))
(defn- viewport-did-mount
[own]

View file

@ -14,6 +14,7 @@
[uxbox.state :as st]
[uxbox.library :as library]
[uxbox.data.workspace :as dw]
[uxbox.data.shapes :as uds]
[uxbox.util.lens :as ul]
[uxbox.util.data :refer (read-string)]
[uxbox.util.color :refer (hex->rgb)]
@ -48,8 +49,8 @@
[color event]
(dom/prevent-default event)
(if (kbd/shift? event)
(rs/emit! (dw/update-selected-shapes-stroke {:color color}))
(rs/emit! (dw/update-selected-shapes-fill {:color color}))))
(rs/emit! (uds/update-selected-shapes-stroke {:color color}))
(rs/emit! (uds/update-selected-shapes-fill {:color color}))))
(defn- colorpalette-render
[own]

View file

@ -9,21 +9,29 @@
(:require [sablono.core :as html :refer-macros [html]]
[rum.core :as rum]
[cuerdas.core :as str]
[uxbox.constants :as c]
[uxbox.ui.mixins :as mx]
[uxbox.ui.workspace.base :as wb]))
;; --- Grid (Component)
(declare ticks-range)
(declare vertical-line)
(declare horizontal-line)
(defn- grid-render
[own]
(let [{:keys [width height options]} (deref wb/page-l)
(let [options (:options @wb/page-l)
color (:grid/color options "#cccccc")
x-ticks (ticks-range width (:grid/x-axis options 10))
y-ticks (ticks-range height (:grid/y-axis options 10))
width c/viewport-width
height c/viewport-height
x-ticks (range (- 0 c/canvas-start-x)
(- width c/canvas-start-x)
(:grid/x-axis options 10))
y-ticks (range (- 0 c/canvas-start-x)
(- height c/canvas-start-x)
(:grid/y-axis options 10))
path (as-> [] $
(reduce (partial vertical-line height) $ x-ticks)
(reduce (partial horizontal-line width) $ y-ticks))]
@ -41,16 +49,10 @@
(defn- horizontal-line
[width acc value]
(let [pos (+ value wb/canvas-start-y)]
(let [pos (+ value c/canvas-start-y)]
(conj acc (str/format "M %s %s L %s %s" 0 pos width pos))))
(defn- vertical-line
[height acc value]
(let [pos (+ value wb/canvas-start-y)]
(let [pos (+ value c/canvas-start-y)]
(conj acc (str/format "M %s %s L %s %s" pos 0 pos height))))
(defn- ticks-range
[size step]
(range (- 0 wb/canvas-start-y)
(- size wb/canvas-start-y)
step))

View file

@ -8,16 +8,40 @@
(ns uxbox.ui.workspace.movement
"Shape movement in workspace logic."
(:require [beicon.core :as rx]
[lentes.core :as l]
[uxbox.constants :as c]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.shapes :as sh]
[uxbox.ui.core :as uuc]
[uxbox.ui.workspace.base :as wb]
[uxbox.ui.workspace.align :as align]
[uxbox.data.shapes :as uds]
[uxbox.util.geom.point :as gpt]))
(declare initialize)
(declare handle-movement)
;; --- Lenses
(declare translate-to-viewport)
(defn- resolve-selected
[state]
(let [selected (get-in state [:workspace :selected])
xf (comp
(map #(get-in state [:shapes-by-id %]))
(map translate-to-viewport))]
(into #{} xf selected)))
(def ^:const ^:private selected-shapes-l
(-> (l/getter resolve-selected)
(l/focus-atom st/state)))
(def ^:const ^:privae page-options-l
(-> (l/key :options)
(l/focus-atom wb/page-l)))
;; --- Public Api
(defn watch-move-actions
@ -28,24 +52,63 @@
;; --- Implementation
(def coords
(gpt/point c/canvas-start-x
c/canvas-start-y))
(defn- translate-to-viewport
[shape]
(let [dx (- (:x2 shape) (:x1 shape))
dy (- (:y2 shape) (:y1 shape))
p1 (gpt/point (:x1 shape) (:y1 shape))
p2 (gpt/add p1 coords)
p3 (gpt/add p2 [dx dy])]
(assoc shape
:x1 (:x p2)
:y1 (:y p2)
:x2 (:x p3)
:y2 (:y p3))))
(defn- translate-to-canvas
[shape]
(let [dx (- (:x2 shape) (:x1 shape))
dy (- (:y2 shape) (:y1 shape))
p1 (gpt/point (:x1 shape) (:y1 shape))
p2 (gpt/subtract p1 coords)
p3 (gpt/add p2 [dx dy])]
(assoc shape
:x1 (:x p2)
:y1 (:y p2)
:x2 (:x p3)
:y2 (:y p3))))
(defn- initialize
[]
(let [stoper (->> uuc/actions-s
(let [shapes @selected-shapes-l
options @page-options-l
stoper (->> uuc/actions-s
(rx/map :type)
(rx/filter empty?)
(rx/take 1))]
(as-> wb/mouse-delta-s $
(rx/take-until stoper $)
(rx/on-value $ handle-movement))))
(rx/scan (fn [acc delta]
(let [xf (map #(sh/move % delta))]
(into [] xf acc))) shapes $)
(rx/mapcat (fn [items]
(if (:grid/align options)
(->> (apply rx/of items)
(rx/mapcat align/translate)
(rx/reduce conj []))
(rx/of items))) $)
(rx/map (fn [items]
(mapv translate-to-canvas items)) $)
(rx/subscribe $ handle-movement))))
(defn- handle-movement
[delta]
(let [pageid (get-in @st/state [:workspace :page])
selected (get-in @st/state [:workspace :selected])
shapes (->> (vals @wb/shapes-by-id-l)
(filter #(= (:page %) pageid))
(filter (comp selected :id)))
delta (gpt/divide delta @wb/zoom-l)]
(doseq [{:keys [id group]} shapes]
(rs/emit! (uds/move-shape id delta)))))
(doseq [shape delta]
(rs/emit! (uds/update-shape shape))))

View file

@ -9,6 +9,7 @@
(:require [sablono.core :as html :refer-macros [html]]
[rum.core :as rum]
[beicon.core :as rx]
[uxbox.constants :as c]
[uxbox.rstore :as rs]
[uxbox.util.math :as mth]
[uxbox.ui.workspace.base :as wb]
@ -104,8 +105,8 @@
[:rect {:style {:fill "transparent"
:stroke "transparent"
:cursor "cell"}
:width wb/viewport-width
:height wb/viewport-height}]
:width c/viewport-width
:height c/viewport-height}]
(if (and p1 p2)
(overlay-line-render own p1 p2))])))

View file

@ -10,6 +10,7 @@
[rum.core :as rum]
[cuerdas.core :as str]
[beicon.core :as rx]
[uxbox.constants :as c]
[uxbox.state :as s]
[uxbox.util.dom :as dom]
[uxbox.ui.workspace.base :as wb]
@ -24,8 +25,8 @@
(defn mid-ticks-mod [zoom] (/ 50 zoom))
(def ^:const +ticks+
(concat (range (- (/ wb/viewport-width 1)) 0 step-size)
(range 0 (/ wb/viewport-width 1) step-size)))
(concat (range (- (/ c/viewport-width 1)) 0 step-size)
(range 0 (/ c/viewport-width 1) step-size)))
(def ^:const rule-padding 20)
@ -35,8 +36,8 @@
mid-ticks-mod (mid-ticks-mod zoom)
pos (+ (* value zoom)
rule-padding
(* wb/canvas-start-x zoom)
wb/canvas-scroll-padding)]
(* c/canvas-start-x zoom)
c/canvas-scroll-padding)]
(cond
(< (mod value big-ticks-mod) step-size)
(conj acc (str/format "M %s %s L %s %s" pos 5 pos step-padding))
@ -52,8 +53,8 @@
(let [big-ticks-mod (big-ticks-mod zoom)
mid-ticks-mod (mid-ticks-mod zoom)
pos (+ (* value zoom)
(* wb/canvas-start-x zoom)
wb/canvas-scroll-padding)]
(* c/canvas-start-x zoom)
c/canvas-scroll-padding)]
(cond
(< (mod value big-ticks-mod) step-size)
(conj acc (str/format "M %s %s L %s %s" 5 pos step-padding pos))
@ -71,8 +72,8 @@
(let [big-ticks-mod (big-ticks-mod zoom)
pos (+ (* value zoom)
rule-padding
(* wb/canvas-start-x zoom)
wb/canvas-scroll-padding)]
(* c/canvas-start-x zoom)
c/canvas-scroll-padding)]
(when (< (mod value big-ticks-mod) step-size)
(html
[:text {:x (+ pos 2)
@ -88,9 +89,9 @@
[zoom value]
(let [big-ticks-mod (big-ticks-mod zoom)
pos (+ (* value zoom)
(* wb/canvas-start-x zoom)
;; wb/canvas-start-x
wb/canvas-scroll-padding)]
(* c/canvas-start-x zoom)
;; c/canvas-start-x
c/canvas-scroll-padding)]
(when (< (mod value big-ticks-mod) step-size)
(html
[:text {:y (- pos 3)
@ -145,10 +146,10 @@
[own zoom]
(let [scroll (rum/react wb/scroll-a)
scroll-x (:x scroll)
translate-x (- (- wb/canvas-scroll-padding) (:x scroll))]
translate-x (- (- c/canvas-scroll-padding) (:x scroll))]
(html
[:svg.horizontal-rule
{:width wb/viewport-width
{:width c/viewport-width
:height 20}
[:g {:transform (str "translate(" translate-x ", 0)")}
(horizontal-rule-ticks zoom)]])))
@ -165,11 +166,11 @@
[own zoom]
(let [scroll (rum/react wb/scroll-a)
scroll-y (:y scroll)
translate-y (- (- wb/canvas-scroll-padding) (:y scroll))]
translate-y (- (- c/canvas-scroll-padding) (:y scroll))]
(html
[:svg.vertical-rule
{:width 20
:height wb/viewport-height}
:height c/viewport-height}
[:g {:transform (str "translate(0, " translate-y ")")}
(vertical-rule-ticks zoom)]

View file

@ -9,6 +9,7 @@
(:require-macros [uxbox.util.syntax :refer [define-once]])
(:require [beicon.core :as rx]
[lentes.core :as l]
[uxbox.constants :as c]
[uxbox.rstore :as rs]
[uxbox.state :as ust]
[uxbox.data.shapes :as uds]

View file

@ -10,9 +10,11 @@
(:require [sablono.core :as html :refer-macros [html]]
[rum.core :as rum]
[beicon.core :as rx]
[uxbox.constants :as c]
[uxbox.rstore :as rs]
[uxbox.shapes :as sh]
[uxbox.data.workspace :as dw]
[uxbox.data.shapes :as uds]
[uxbox.ui.core :as uuc]
[uxbox.ui.mixins :as mx]
[uxbox.ui.workspace.base :as wb]))
@ -78,8 +80,8 @@
"Translate the given rect to the canvas coordinates system."
[rect]
(let [zoom @wb/zoom-l
startx (* wb/canvas-start-x zoom)
starty (* wb/canvas-start-y zoom)]
startx (* c/canvas-start-x zoom)
starty (* c/canvas-start-y zoom)]
(assoc rect
:x (- (:x rect) startx)
:y (- (:y rect) starty)
@ -94,7 +96,7 @@
(on-complete []
(rs/emit! (-> (selrect->rect @position)
(translate-to-canvas)
(dw/select-shapes)))
(uds/select-shapes)))
(reset! position nil))
(init []

View file

@ -9,6 +9,7 @@
(:require [sablono.core :as html :refer-macros [html]]
[lentes.core :as l]
[rum.core :as rum]
[uxbox.constants :as c]
[uxbox.rstore :as rs]
[uxbox.data.pages :as udp]
[uxbox.ui.icons :as i]
@ -16,7 +17,8 @@
[uxbox.ui.lightbox :as lightbox]
[uxbox.ui.colorpicker :as uucp]
[uxbox.ui.workspace.base :as wb]
[uxbox.util.dom :as dom]))
[uxbox.util.dom :as dom]
[uxbox.util.data :refer (parse-int)]))
;; --- Lentes
@ -33,7 +35,8 @@
opts (merge (:options page)
(deref local))]
(letfn [(on-field-change [field event]
(let [value (dom/event->value event)]
(let [value (dom/event->value event)
value (parse-int value)]
(swap! local assoc field value)))
(on-color-change [color]
(swap! local assoc :grid/color color))
@ -42,6 +45,7 @@
(dom/checked?))]
(swap! local assoc :grid/align checked?)))
(on-submit [event]
(dom/prevent-default event)
(let [page (assoc page :options opts)]
(rs/emit! (udp/update-page-metadata page))
(lightbox/close!)))]
@ -52,14 +56,14 @@
[:input#grid-x.input-text
{:placeholder "X px"
:type "number"
:value (:grid/x-axis opts "2")
:value (:grid/x-axis opts c/grid-x-axis)
:on-change (partial on-field-change :grid/x-axis)
:min 1 ;;TODO check this value
:min 1
:max 100}]
[:input#grid-y.input-text
{:placeholder "Y px"
:type "number"
:value (:grid/y-axis opts "2")
:value (:grid/y-axis opts c/grid-y-axis)
:on-change (partial on-field-change :grid/y-axis)
:min 1
:max 100}]]

View file

@ -11,6 +11,7 @@
[uxbox.rstore :as rs]
[uxbox.ui.lightbox :as lightbox]
[uxbox.data.workspace :as dw]
[uxbox.data.shapes :as uds]
[uxbox.data.history :as udh])
(:import goog.events.EventType
goog.events.KeyCodes
@ -28,15 +29,15 @@
:ctrl+shift+l #(rs/emit! (dw/toggle-flag :layers))
:ctrl+0 #(rs/emit! (dw/reset-zoom))
:ctrl+r #(rs/emit! (dw/toggle-flag :ruler))
:ctrl+d #(rs/emit! (dw/duplicate-selected))
:ctrl+d #(rs/emit! (uds/duplicate-selected))
:ctrl+c #(rs/emit! (dw/copy-to-clipboard))
:ctrl+v #(rs/emit! (dw/paste-from-clipboard))
:ctrl+z #(rs/emit! (udh/backwards-to-previous-version))
:ctrl+shift+z #(rs/emit! (udh/forward-to-next-version))
:ctrl+shift+v #(lightbox/open! :clipboard)
:esc #(rs/emit! (dw/deselect-all))
:backspace #(rs/emit! (dw/delete-selected))
:delete #(rs/emit! (dw/delete-selected))
:esc #(rs/emit! (uds/deselect-all))
:backspace #(rs/emit! (uds/delete-selected))
:delete #(rs/emit! (uds/delete-selected))
:shift+up #(move-selected :up :fast)
:shift+down #(move-selected :down :fast)
:shift+right #(move-selected :right :fast)
@ -78,8 +79,8 @@
(defn- move-selected
[dir speed]
(case speed
:std (rs/emit! (dw/move-selected dir 1))
:fast (rs/emit! (dw/move-selected dir 20))))
:std (rs/emit! (uds/move-selected dir 1))
:fast (rs/emit! (uds/move-selected dir 20))))
;; --- Mixin

View file

@ -49,18 +49,18 @@
nil
(.-ctrlKey event)
(rs/emit! (udw/select-shape id))
(rs/emit! (uds/select-shape id))
(> (count selected) 1)
(rs/emit! (udw/deselect-all)
(udw/select-shape id))
(rs/emit! (uds/deselect-all)
(uds/select-shape id))
(contains? selected id)
(rs/emit! (udw/select-shape id))
(rs/emit! (uds/select-shape id))
:else
(rs/emit! (udw/deselect-all)
(udw/select-shape id)))))
(rs/emit! (uds/deselect-all)
(uds/select-shape id)))))
(defn- toggle-visibility
[selected item event]
@ -71,7 +71,7 @@
(rs/emit! (uds/show-shape id))
(rs/emit! (uds/hide-shape id)))
(when (contains? selected id)
(rs/emit! (udw/select-shape id)))))
(rs/emit! (uds/select-shape id)))))
(defn- toggle-blocking
[item event]
@ -289,9 +289,9 @@
shapes-by-id (rum/react wb/shapes-by-id-l)
page (rum/react (focus-page (:page workspace)))
close #(rs/emit! (udw/toggle-flag :layers))
duplicate #(rs/emit! (udw/duplicate-selected))
group #(rs/emit! (udw/group-selected))
delete #(rs/emit! (udw/delete-selected))
duplicate #(rs/emit! (uds/duplicate-selected))
group #(rs/emit! (uds/group-selected))
delete #(rs/emit! (uds/delete-selected))
dragel (volatile! nil)]
(html
[:div#layers.tool-window

View file

@ -4,38 +4,47 @@
;;
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.transit
(ns uxbox.util.transit
"A lightweight abstraction for transit serialization."
(:refer-clojure :exclude [do])
(:require [cognitect.transit :as t]
[com.cognitect.transit :as tr]
[uxbox.util.data :refer (parse-int)]
[uxbox.util.geom.point :as gpt]
[uxbox.util.datetime :as dt]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Read/Write Transit handlers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Transit Handlers
(def ^:private datetime-write-handler
(reify
Object
(tag [_ v] "m")
(rep [_ v] (dt/format v :offset))
(stringRep [this v] (str (dt/format v :offset)))))
(def datetime-write-handler
(t/write-handler (constantly "m")
#(str (dt/format % :offset))))
(defn- datetime-read-handler
[v]
(dt/datetime (parse-int v)))
(def datetime-read-handler
(t/read-handler
#(dt/datetime (parse-int %))))
(def point-write-handler
(t/write-handler
(constantly "point")
(fn [v]
(let [ret #js []]
(.push ret (:x v))
(.push ret (:y v))
ret))))
(def point-read-handler
(t/read-handler
#(gpt/point (js->clj %))))
(def ^:privare +read-handlers+
{"u" uuid
"m" datetime-read-handler})
"m" datetime-read-handler
"point" point-read-handler})
(def ^:privare +write-handlers+
{dt/DateTime datetime-write-handler})
{dt/DateTime datetime-write-handler
gpt/Point point-write-handler})
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Public Api
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Public Api
(defn decode
[data]

View file

@ -0,0 +1,62 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.util.workers
"A lightweight layer on top of webworkers api."
(:require [beicon.core :as rx]
[uxbox.util.transit :as t]))
;; --- Implementation
(defprotocol IWorker
(-ask [_ msg] "Send and receive message as rx stream.")
(-send [_ msg] "Send message and forget."))
(deftype WebWorker [stream wrk]
IWorker
(-ask [this message]
(let [sender (random-uuid)
data (assoc message :sender sender)
data (t/encode data)]
(.postMessage wrk data)
(->> stream
(rx/filter #(= (:reply-to %) sender))
(rx/take 1))))
(-send [this message]
(let [sender (random-uuid)
data (assoc message :sender sender)
data (t/encode data)]
(.postMessage wrk data)
(->> stream
(rx/filter #(= (:reply-to %) sender))))))
;; --- Public Api
(defn init
"Return a initialized webworker instance."
[path]
(let [wrk (js/Worker. path)
bus (rx/bus)]
(.addEventListener wrk "message"
(fn [event]
(let [data (.-data event)
data (t/decode data)]
(rx/push! bus data))))
(.addEventListener wrk "error"
(fn [event]
(rx/error! bus event)))
(WebWorker. (rx/map identity bus) wrk)))
(defn ask!
[wrk message]
(-ask wrk message))
(defn send!
[wrk message]
(-send wrk message))

21
src/uxbox/worker.cljs Normal file
View file

@ -0,0 +1,21 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.worker
(:require [beicon.core :as rx]
[uxbox.util.transit :as t]
[uxbox.worker.core :as wrk]
[uxbox.worker.align]))
(enable-console-print!)
(defn- on-message
[event]
(let [message (t/decode (.-data event))]
(wrk/handler message)))
(defonce _
(.addEventListener js/self "message" on-message))

View file

@ -0,0 +1,34 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.worker.align
"Workspace aligment indexes worker."
(:require [beicon.core :as rx]
[kdtree :as kd]
[uxbox.worker.core :as wrk]
[uxbox.util.geom.point :as gpt]))
(defonce state (volatile! nil))
(defmethod wrk/handler :grid/init
[{:keys [width height x-axis y-axis] :as opts}]
(println ":grid/init" opts)
(let [points (into-array
(for [x (range 0 width (or x-axis 10))
y (range 0 height (or y-axis 10))]
#js [x y]))
tree (kd/create2d points)]
(vreset! state tree)))
(defmethod wrk/handler :grid/align
[{:keys [sender point] :as message}]
(println "request" point)
(let [point #js [(:x point) (:y point)]
results (js->clj (.nearest @state point 1))
[[x y] d] (first results)
result (gpt/point x y)]
(println "result:" result)
(wrk/reply! sender {:point (gpt/point x y)})))

View file

@ -0,0 +1,31 @@
;; 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) 2016 Andrey Antukh <niwi@niwi.nz>
(ns uxbox.worker.core
(:require [uxbox.util.transit :as t]))
(enable-console-print!)
;; --- Handler
(defmulti handler :cmd)
(defmethod handler :default
[message]
(println "Unexpected message:" message))
;; --- Helpers
(defn worker?
"Check if the code is executed in webworker context."
[]
(undefined? (.-document js/self)))
(defn reply!
[sender message]
(let [message (assoc message :reply-to sender)]
(println "replying " message)
(.postMessage js/self (t/encode message))))