diff --git a/frontend/deps.edn b/frontend/deps.edn index bffc02ba1..7e87cafce 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -8,9 +8,9 @@ metosin/reitit-core {:mvn/version "0.5.17"} funcool/beicon {:mvn/version "2021.07.05-1"} - funcool/okulary {:mvn/version "2020.04.14-0"} + funcool/okulary {:mvn/version "2022.04.01-10"} funcool/potok {:mvn/version "2021.09.20-0"} - funcool/rumext {:mvn/version "2022.03.28-131"} + funcool/rumext {:mvn/version "2022.03.31-133"} funcool/tubax {:mvn/version "2021.05.20-0"} instaparse/instaparse {:mvn/version "1.4.10"} diff --git a/frontend/src/app/main/data/workspace/state_helpers.cljs b/frontend/src/app/main/data/workspace/state_helpers.cljs index 708c3d1d3..4da32f002 100644 --- a/frontend/src/app/main/data/workspace/state_helpers.cljs +++ b/frontend/src/app/main/data/workspace/state_helpers.cljs @@ -20,39 +20,45 @@ ([state] (lookup-page-objects state (:current-page-id state))) ([state page-id] - (get-in state [:workspace-data :pages-index page-id :objects]))) + (dm/get-in state [:workspace-data :pages-index page-id :objects]))) (defn lookup-page-options ([state] (lookup-page-options state (:current-page-id state))) ([state page-id] - (get-in state [:workspace-data :pages-index page-id :options]))) + (dm/get-in state [:workspace-data :pages-index page-id :options]))) (defn lookup-component-objects ([state component-id] - (get-in state [:workspace-data :components component-id :objects]))) + (dm/get-in state [:workspace-data :components component-id :objects]))) (defn lookup-local-components ([state] - (get-in state [:workspace-data :components]))) + (dm/get-in state [:workspace-data :components]))) + +(defn process-selected-shapes + ([objects selected] + (process-selected-shapes objects selected nil)) + + ([objects selected {:keys [omit-blocked?] :or {omit-blocked? false}}] + (letfn [(selectable? [id] + (and (contains? objects id) + (or (not omit-blocked?) + (not (get-in objects [id :blocked] false)))))] + (let [selected (->> selected (cph/clean-loops objects))] + (into (d/ordered-set) + (filter selectable?) + selected))))) -;; TODO: improve performance of this (defn lookup-selected ([state] (lookup-selected state nil)) ([state options] (lookup-selected state (:current-page-id state) options)) - ([state page-id {:keys [omit-blocked?] :or {omit-blocked? false}}] + ([state page-id options] (let [objects (lookup-page-objects state page-id) - selected (->> (dm/get-in state [:workspace-local :selected]) - (cph/clean-loops objects)) - selectable? (fn [id] - (and (contains? objects id) - (or (not omit-blocked?) - (not (get-in objects [id :blocked] false)))))] - (into (d/ordered-set) - (filter selectable?) - selected)))) + selected (dm/get-in state [:workspace-local :selected])] + (process-selected-shapes objects selected options)))) (defn lookup-shapes ([state ids] @@ -79,7 +85,7 @@ [state file-id] (if (= file-id (:current-file-id state)) (get state :workspace-data) - (get-in state [:workspace-libraries file-id :data]))) + (dm/get-in state [:workspace-libraries file-id :data]))) (defn get-libraries "Retrieve all libraries, including the local file." diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 14a4a9259..accbc9e13 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -102,8 +102,22 @@ (l/derived :workspace-drawing st/state)) ;; TODO: rename to workspace-selected (?) +;; Don't use directly from components, this is a proxy to improve performance of selected-shapes +(def ^:private selected-shapes-data + (l/derived + (fn [state] + (let [objects (wsh/lookup-page-objects state) + selected (dm/get-in state [:workspace-local :selected])] + {:objects objects :selected selected})) + st/state (fn [v1 v2] + (and (identical? (:objects v1) (:objects v2)) + (= (:selected v1) (:selected v2)))))) + (def selected-shapes - (l/derived wsh/lookup-selected st/state =)) + (l/derived + (fn [{:keys [objects selected]}] + (wsh/process-selected-shapes objects selected)) + selected-shapes-data)) (defn make-selected-ref [id] @@ -258,7 +272,7 @@ (defn objects-by-id [ids] - (l/derived #(wsh/lookup-shapes % ids) st/state =)) + (l/derived #(into [] (keep (d/getf %)) ids) workspace-page-objects)) (defn- set-content-modifiers [state] (fn [id shape] diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index d45dd9149..adff4aa4c 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -18,7 +18,6 @@ [app.main.ui.shapes.rect :as rect] [app.main.ui.shapes.text.fontfaces :as ff] [app.main.ui.workspace.shapes.bool :as bool] - [app.main.ui.workspace.shapes.bounding-box :refer [bounding-box]] [app.main.ui.workspace.shapes.common :as common] [app.main.ui.workspace.shapes.frame :as frame] [app.main.ui.workspace.shapes.group :as group] @@ -26,7 +25,6 @@ [app.main.ui.workspace.shapes.svg-raw :as svg-raw] [app.main.ui.workspace.shapes.text :as text] [app.util.object :as obj] - [debug :refer [debug?]] [rumext.alpha :as mf])) (declare shape-wrapper) @@ -87,10 +85,7 @@ ;; Only used when drawing a new frame. :frame [:> frame-wrapper opts] - nil) - - (when (debug? :bounding-boxes) - [:> bounding-box opts])]))) + nil)]))) (def group-wrapper (group/group-wrapper-factory shape-wrapper)) (def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper)) diff --git a/frontend/src/app/main/ui/workspace/shapes/bounding_box.cljs b/frontend/src/app/main/ui/workspace/shapes/bounding_box.cljs deleted file mode 100644 index 7e05a7881..000000000 --- a/frontend/src/app/main/ui/workspace/shapes/bounding_box.cljs +++ /dev/null @@ -1,90 +0,0 @@ -;; 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.workspace.shapes.bounding-box - (:require - ["randomcolor" :as rdcolor] - [app.common.geom.shapes :as gsh] - [app.main.refs :as refs] - [cuerdas.core :as str] - [rumext.alpha :as mf])) - -(defn fixed - [num] - (when num (.toFixed num 2))) - -(mf/defc cross-point [{:keys [point zoom color]}] - (let [width (/ 5 zoom)] - [:g.point - [:line {:x1 (- (:x point) width) :y1 (- (:y point) width) - :x2 (+ (:x point) width) :y2 (+ (:y point) width) - :stroke color - :stroke-width "1px" - :stroke-opacity 0.5}] - - [:line {:x1 (+ (:x point) width) :y1 (- (:y point) width) - :x2 (- (:x point) width) :y2 (+ (:y point) width) - :stroke color - :stroke-width "1px" - :stroke-opacity 0.5}]])) - -(mf/defc render-rect [{{:keys [x y width height]} :rect :keys [color transform]}] - [:rect {:x x - :y y - :width width - :height height - :transform (or transform "none") - :style {:stroke color - :fill "none" - :stroke-width "1px" - :pointer-events "none"}}]) - -(mf/defc render-rect-points [{:keys [points color]}] - (for [[p1 p2] (map vector points (concat (rest points) [(first points)]))] - [:line {:x1 (:x p1) - :y1 (:y p1) - :x2 (:x p2) - :y2 (:y p2) - :style {:stroke color - :stroke-width "1px"}}])) - -(mf/defc bounding-box - {::mf/wrap-props false} - [props] - (let [shape (unchecked-get props "shape") - bounding-box (gsh/points->selrect (-> shape :points)) - shape-center (gsh/center-shape shape) - line-color (rdcolor #js {:seed (str (:id shape))}) - zoom (mf/deref refs/selected-zoom)] - - [:g.bounding-box - [:text {:x (:x bounding-box) - :y (- (:y bounding-box) 5) - :font-size 10 - :fill line-color - :stroke "var(--color-white)" - :stroke-width 0.1} - (str/format "%s - (%s, %s)" (str/slice (str (:id shape)) 0 8) (fixed (:x bounding-box)) (fixed (:y bounding-box)))] - - [:g.center - [:& cross-point {:point shape-center - :zoom zoom - :color line-color}]] - - [:g.points - (for [point (:points shape)] - [:& cross-point {:point point - :zoom zoom - :color line-color}]) - #_[:& render-rect-points {:points (:points shape) - :color line-color}]] - - [:g.selrect - [:& render-rect {:rect (:selrect shape) - ;; :transform (gsh/transform-matrix shape) - :color line-color}] - #_[:& render-rect {:rect bounding-box - :color line-color}]]])) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index a6b92c6d4..1c1b4854f 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -6,6 +6,7 @@ (ns app.util.dom (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.logging :as log] @@ -231,20 +232,20 @@ (.-innerText el))) (defn query - ([^string query] - (query globals/document query)) + ([^string selector] + (query globals/document selector)) - ([^js el ^string query] + ([^js el ^string selector] (when (some? el) - (.querySelector el query)))) + (.querySelector el selector)))) (defn query-all - ([^string query] - (query-all globals/document query)) + ([^string selector] + (query-all globals/document selector)) - ([^js el ^string query] + ([^js el ^string selector] (when (some? el) - (.querySelectorAll el query)))) + (.querySelectorAll el selector)))) (defn get-client-position [^js event] @@ -535,3 +536,13 @@ (and (some? node) (some? candidate) (.contains node candidate))) + +(defn seq-nodes + [root-node] + (letfn [(branch? [node] + (d/not-empty? (get-children node))) + + (get-children [node] + (seq (.-children node)))] + (->> root-node + (tree-seq branch? get-children)))) diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 23cb8670f..1cbd600bf 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -18,6 +18,7 @@ [app.main.data.workspace.path.shortcuts] [app.main.data.workspace.shortcuts] [app.main.store :as st] + [app.util.dom :as dom] [app.util.object :as obj] [app.util.timers :as timers] [beicon.core :as rx] @@ -340,3 +341,9 @@ (.log js/console "%c Viewer" style) (print-shortcuts app.main.data.viewer.shortcuts/shortcuts))) nil) + +(defn ^:export nodeStats + [] + (let [root-node (dom/query ".viewport .render-shapes") + num-nodes (->> (dom/seq-nodes root-node) count)] + #js {:number num-nodes}))