diff --git a/frontend/src/app/main/data/workspace/viewport.cljs b/frontend/src/app/main/data/workspace/viewport.cljs index 190440811e..97e88bc29a 100644 --- a/frontend/src/app/main/data/workspace/viewport.cljs +++ b/frontend/src/app/main/data/workspace/viewport.cljs @@ -10,6 +10,7 @@ [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.align :as gal] + [app.common.geom.point :as gpt] [app.common.geom.rect :as gpr] [app.common.geom.shapes :as gsh] [app.common.math :as mth] @@ -83,6 +84,25 @@ (fn [local] (setup state local))))))) +(defn calculate-centered-viewbox + "Updates the viewbox coordinates for a given center position" + [local position] + (let [vbox (:vbox local) + nw (/ (:width vbox) 2) + nh (/ (:height vbox) 2) + nx (- (:x position) nw) + ny (- (:y position) nh)] + (update local :vbox assoc :x nx :y ny))) + +(defn update-viewport-position-center + [position] + (assert (gpt/point? position) "expected a point instance for `position` param") + + (ptk/reify ::update-viewport-position-center + ptk/UpdateEvent + (update [_ state] + (update state :workspace-local calculate-centered-viewbox position)))) + (defn update-viewport-position [{:keys [x y] :or {x identity y identity}}] diff --git a/frontend/src/app/main/data/workspace/zoom.cljs b/frontend/src/app/main/data/workspace/zoom.cljs index f799549cd4..843ea5f3f9 100644 --- a/frontend/src/app/main/data/workspace/zoom.cljs +++ b/frontend/src/app/main/data/workspace/zoom.cljs @@ -20,7 +20,7 @@ [beicon.v2.core :as rx] [potok.v2.core :as ptk])) -(defn- impl-update-zoom +(defn impl-update-zoom [{:keys [vbox] :as local} center zoom] (let [new-zoom (if (fn? zoom) (zoom (:zoom local)) zoom) old-zoom (:zoom local) diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs index bb8f0fc2fe..2955543540 100644 --- a/frontend/src/app/main/ui/comments.cljs +++ b/frontend/src/app/main/ui/comments.cljs @@ -17,6 +17,7 @@ [app.main.data.comments :as dcm] [app.main.data.modal :as modal] [app.main.data.workspace.comments :as dwcm] + [app.main.data.workspace.viewport :as dwv] [app.main.data.workspace.zoom :as dwz] [app.main.refs :as refs] [app.main.store :as st] @@ -1097,15 +1098,35 @@ groups)) (group-bubbles zoom remaining visited (cons [current] groups))))))) -(defn- calculate-zoom-scale-to-ungroup-bubbles - "Calculate the minimum zoom scale needed for a group of bubbles to avoid overlap among them" - [zoom threads] +(defn- inside-vbox? + "Checks if a bubble or a bubble group is inside a viewbox" + [thread-group wl] + (let [vbox (:vbox wl) + positions (mapv :position thread-group) + position (gpt/center-points positions) + pos-x (:x position) + pos-y (:y position) + x1 (:x vbox) + y1 (:y vbox) + x2 (+ x1 (:width vbox)) + y2 (+ y1 (:height vbox))] + (and (> x2 pos-x x1) (> y2 pos-y y1)))) + +(defn- calculate-zoom-scale + "Calculates the zoom level needed to ungroup the largest number of bubbles while + keeping them all visible in the viewbox." + [position zoom threads wl] (let [num-threads (count threads) - num-grouped-threads (count (group-bubbles zoom threads)) - zoom-scale-step 1.75] - (if (= num-threads num-grouped-threads) + grouped-threads (group-bubbles zoom threads) + num-grouped-threads (count grouped-threads) + zoom-scale-step 1.75 + scaled-zoom (* zoom zoom-scale-step) + zoomed-wl (dwz/impl-update-zoom wl position scaled-zoom) + outside-vbox? (complement inside-vbox?)] + (if (or (= num-threads num-grouped-threads) + (some #(outside-vbox? % zoomed-wl) grouped-threads)) zoom - (calculate-zoom-scale-to-ungroup-bubbles (* zoom zoom-scale-step) threads)))) + (calculate-zoom-scale position scaled-zoom threads zoomed-wl)))) (mf/defc comment-floating-group* {::mf/wrap [mf/memo]} @@ -1126,11 +1147,14 @@ on-click (mf/use-fn - (mf/deps thread-group position) + (mf/deps thread-group position zoom) (fn [] - (let [updated-zoom (calculate-zoom-scale-to-ungroup-bubbles zoom thread-group) + (let [wl (deref refs/workspace-local) + centered-wl (dwv/calculate-centered-viewbox wl position) + updated-zoom (calculate-zoom-scale position zoom thread-group centered-wl) scale-zoom (/ updated-zoom zoom)] - (st/emit! (dwz/set-zoom position scale-zoom)))))] + (st/emit! (dwv/update-viewport-position-center position) + (dwz/set-zoom position scale-zoom)))))] [:div {:style {:top (dm/str pos-y "px") :left (dm/str pos-x "px")}