mirror of
https://github.com/penpot/penpot.git
synced 2025-06-08 09:01:37 +02:00
✨ More work on viewpoer sizing handling.
This commit is contained in:
parent
1af87b9140
commit
22975f4f7d
14 changed files with 295 additions and 360 deletions
|
@ -5,7 +5,7 @@
|
||||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
;; defined by the Mozilla Public License, v. 2.0.
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2019-2020 Andrey Antukh <niwi@niwi.nz>
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
(ns uxbox.common.pages
|
(ns uxbox.common.pages
|
||||||
"A common (clj/cljs) functions and specs for pages."
|
"A common (clj/cljs) functions and specs for pages."
|
||||||
|
@ -80,7 +80,8 @@
|
||||||
(remove p? after))))
|
(remove p? after))))
|
||||||
|
|
||||||
(defn select-toplevel-shapes
|
(defn select-toplevel-shapes
|
||||||
[objects]
|
([objects] (select-toplevel-shapes objects nil))
|
||||||
|
([objects {:keys [include-frames?] :or {include-frames? false}}]
|
||||||
(let [lookup #(get objects %)
|
(let [lookup #(get objects %)
|
||||||
root (lookup uuid/zero)
|
root (lookup uuid/zero)
|
||||||
childs (:shapes root)]
|
childs (:shapes root)]
|
||||||
|
@ -94,8 +95,10 @@
|
||||||
(recur (first ids)
|
(recur (first ids)
|
||||||
(rest ids)
|
(rest ids)
|
||||||
(if (= :frame typ)
|
(if (= :frame typ)
|
||||||
(into res (map lookup) (:shapes obj))
|
(if include-frames?
|
||||||
(conj res obj))))))))
|
(d/concat res [obj] (map lookup (:shapes obj)))
|
||||||
|
(d/concat res (map lookup (:shapes obj))))
|
||||||
|
(conj res obj)))))))))
|
||||||
|
|
||||||
(defn select-frames
|
(defn select-frames
|
||||||
[objects]
|
[objects]
|
||||||
|
|
|
@ -30,6 +30,4 @@
|
||||||
|
|
||||||
.dashboard-content {
|
.dashboard-content {
|
||||||
background-color: lighten($color-gray-10, 5%);
|
background-color: lighten($color-gray-10, 5%);
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-viewport {
|
.workspace-viewport {
|
||||||
height: 100%;
|
height: calc(100% - 40px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: none;
|
transition: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -129,8 +129,9 @@
|
||||||
grid-template-columns: 20px 1fr;
|
grid-template-columns: 20px 1fr;
|
||||||
|
|
||||||
.viewport {
|
.viewport {
|
||||||
grid-column: 2 / span 1;
|
grid-column: 1 / span 2;
|
||||||
grid-row: 2 / span 1;
|
grid-row: 1 / span 2;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
&.drawing {
|
&.drawing {
|
||||||
cursor: cell;
|
cursor: cell;
|
||||||
|
@ -156,7 +157,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewport, .page-canvas, .page-layout {
|
.page-canvas, .page-layout {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,18 +66,13 @@
|
||||||
:sitemap-pages
|
:sitemap-pages
|
||||||
:layers
|
:layers
|
||||||
:element-options
|
:element-options
|
||||||
:rules})
|
:rules
|
||||||
|
})
|
||||||
|
|
||||||
(s/def ::options-mode #{:design :prototype})
|
(s/def ::options-mode #{:design :prototype})
|
||||||
|
|
||||||
(def workspace-default
|
(def workspace-default
|
||||||
{:zoom 1
|
{:zoom 1
|
||||||
:size {:x 0
|
|
||||||
:y 0
|
|
||||||
:width c/viewport-width
|
|
||||||
:height c/viewport-width
|
|
||||||
:viewport-width c/viewport-width
|
|
||||||
:viewport-height c/viewport-height}
|
|
||||||
:flags #{}
|
:flags #{}
|
||||||
:selected #{}
|
:selected #{}
|
||||||
:drawing nil
|
:drawing nil
|
||||||
|
@ -196,51 +191,59 @@
|
||||||
|
|
||||||
;; --- Viewport Sizing
|
;; --- Viewport Sizing
|
||||||
|
|
||||||
|
(declare zoom-to-fit-all)
|
||||||
|
|
||||||
|
;; TODO: add-spec
|
||||||
|
|
||||||
(defn initialize-viewport
|
(defn initialize-viewport
|
||||||
[{:keys [width height] :as size}]
|
[{:keys [width height] :as size}]
|
||||||
|
(js/console.log "initialize-viewport" size)
|
||||||
(ptk/reify ::initialize-viewport
|
(ptk/reify ::initialize-viewport
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update state :workspace-local
|
(update state :workspace-local
|
||||||
(fn [local]
|
(fn [local]
|
||||||
(-> local
|
(-> local
|
||||||
(assoc :zoom 1)
|
(assoc :vport size)
|
||||||
(update :size assoc
|
(update :vbox (fn [vbox]
|
||||||
:x 0
|
(if (nil? vbox)
|
||||||
:y 0
|
(assoc size :x 0 :y 0)
|
||||||
:width width
|
vbox)))))))
|
||||||
:height height
|
|
||||||
:viewport-width width
|
|
||||||
:viewport-height height)))))))
|
|
||||||
|
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
#_(rx/of zoom-to-fit-all))))
|
||||||
|
|
||||||
(defn update-viewport-position
|
(defn update-viewport-position
|
||||||
[{:keys [x y] :or {x identity y identity}}]
|
[{:keys [x y] :or {x identity y identity}}]
|
||||||
|
(us/assert fn? x)
|
||||||
|
(us/assert fn? y)
|
||||||
(ptk/reify ::update-viewport-position
|
(ptk/reify ::update-viewport-position
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:workspace-local :size]
|
(update-in state [:workspace-local :vbox]
|
||||||
(fn [size]
|
(fn [vbox]
|
||||||
(-> size
|
(-> vbox
|
||||||
(update :x x)
|
(update :x (comp mth/round x))
|
||||||
(update :y y)))))))
|
(update :y (comp mth/round y))))))))
|
||||||
|
|
||||||
|
;; TODO: add spec
|
||||||
|
|
||||||
(defn update-viewport-size
|
(defn update-viewport-size
|
||||||
[{:keys [width height]}]
|
[{:keys [width height] :as size}]
|
||||||
(ptk/reify ::update-viewport-size
|
(ptk/reify ::update-viewport-size
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update state :workspace-local
|
(update state :workspace-local
|
||||||
(fn [{:keys [size] :as local}]
|
(fn [{:keys [vbox vport] :as local}]
|
||||||
(let [wprop (/ (:viewport-width size) width)
|
(let [wprop (/ (:width vport) width)
|
||||||
hprop (/ (:viewport-height size) height)
|
hprop (/ (:height vport) height)]
|
||||||
size' (-> size
|
(-> local
|
||||||
(assoc :viewport-width width)
|
(assoc :vport size)
|
||||||
(assoc :viewport-height height)
|
(update :vbox (fn [vbox]
|
||||||
|
(-> vbox
|
||||||
(update :width #(/ % wprop))
|
(update :width #(/ % wprop))
|
||||||
(update :height #(/ % hprop)))]
|
(update :height #(/ % hprop))))))))))))
|
||||||
(assoc local :size size')))))))
|
|
||||||
|
|
||||||
;; ---
|
;; ---
|
||||||
|
|
||||||
|
@ -325,19 +328,15 @@
|
||||||
;; --- Zoom Management
|
;; --- Zoom Management
|
||||||
|
|
||||||
(defn- impl-update-zoom
|
(defn- impl-update-zoom
|
||||||
[local zoom]
|
[{:keys [vbox vport] :as local} zoom]
|
||||||
(let [base-width (get-in local [:size :viewport-width])
|
(let [zoom (if (fn? zoom)
|
||||||
base-height (get-in local [:size :viewport-height])
|
|
||||||
|
|
||||||
zoom (if (fn? zoom)
|
|
||||||
(zoom (:zoom local))
|
(zoom (:zoom local))
|
||||||
zoom)
|
zoom)
|
||||||
|
width (/ (:width vport) zoom)
|
||||||
width (/ base-width zoom)
|
height (/ (:height vport) zoom)]
|
||||||
height (/ base-height zoom)]
|
|
||||||
(-> local
|
(-> local
|
||||||
(assoc :zoom zoom)
|
(assoc :zoom zoom)
|
||||||
(update :size assoc :width width :height height))))
|
(update :vbox assoc :width width :height height))))
|
||||||
|
|
||||||
(defn increase-zoom
|
(defn increase-zoom
|
||||||
[center]
|
[center]
|
||||||
|
@ -376,51 +375,45 @@
|
||||||
(update state :workspace-local
|
(update state :workspace-local
|
||||||
#(impl-update-zoom % 2)))))
|
#(impl-update-zoom % 2)))))
|
||||||
|
|
||||||
;; (defn impl-expand-rect
|
(def zoom-to-fit-all
|
||||||
;; [{:keys [x y width height] :as rect} padding]
|
(ptk/reify ::zoom-to-fit-all
|
||||||
;; (assoc rect
|
ptk/UpdateEvent
|
||||||
;; :x (- x padding)
|
(update [_ state]
|
||||||
;; :y (- y padding)
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
;; :width (+ width padding)
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
;; :height (+ height padding)))
|
shapes (cp/select-toplevel-shapes objects {:include-frames? true})
|
||||||
|
srect (geom/shapes->rect-shape shapes)]
|
||||||
|
|
||||||
;; (def zoom-to-selected-shape
|
(if (or (mth/nan? (:width srect))
|
||||||
;; (ptk/reify ::zoom-to-selected-shape
|
(mth/nan? (:height srect)))
|
||||||
;; ptk/UpdateEvent
|
state
|
||||||
;; (update [_ state]
|
(update state :workspace-local
|
||||||
;; (let [page-id (get-in state [:workspace-page :id])
|
(fn [{:keys [vbox vport] :as local}]
|
||||||
;; objects (get-in state [:workspace-data page-id :objects])
|
(let [srect (geom/adjust-to-viewport vport srect {:padding 40})
|
||||||
;; selected (get-in state [:workspace-local :selected])
|
zoom (/ (:width vport) (:width srect))]
|
||||||
;; shapes (map #(get objects %) selected)
|
(-> local
|
||||||
;; rect (geom/selection-rect shapes)
|
(assoc :zoom zoom)
|
||||||
;; rect (impl-expand-rect rect 20)
|
(update :vbox merge srect))))))))))
|
||||||
;; ]
|
|
||||||
;; (update state :workspace-local
|
|
||||||
;; (fn [{:keys [size] :as local}]
|
|
||||||
;; (let [proportion (/ (:viewport-width size) (:viewport-height size))
|
|
||||||
;; width (:width rect)
|
|
||||||
;; height (/ (:width rect) proportion)
|
|
||||||
|
|
||||||
;; [width height] (if (> (:height rect) height)
|
|
||||||
;; [(* width proportion) (:height rect)]
|
|
||||||
;; [width height])
|
|
||||||
|
|
||||||
;; zoom (/ (:viewport-width size) width)]
|
|
||||||
|
|
||||||
;; ;; (js/console.log "proportion=" proportion
|
|
||||||
;; ;; "width=" width
|
|
||||||
;; ;; "height=" height
|
|
||||||
;; ;; "viewport-width=" (:viewport-width size)
|
|
||||||
;; ;; "viewport-height=" (:viewport-height size))
|
|
||||||
;; (-> local
|
|
||||||
;; (assoc :zoom zoom)
|
|
||||||
;; (update :size assoc
|
|
||||||
;; :x (:x rect)
|
|
||||||
;; :y (:y rect)
|
|
||||||
;; :width width
|
|
||||||
;; :height height
|
|
||||||
;; )))))))))
|
|
||||||
|
|
||||||
|
(def zoom-to-selected-shape
|
||||||
|
(ptk/reify ::zoom-to-selected-shape
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [selected (get-in state [:workspace-local :selected])]
|
||||||
|
(if (empty? selected)
|
||||||
|
state
|
||||||
|
(let [page-id (get-in state [:workspace-page :id])
|
||||||
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
|
srect (->> selected
|
||||||
|
(map #(get objects %))
|
||||||
|
(geom/selection-rect))]
|
||||||
|
(update state :workspace-local
|
||||||
|
(fn [{:keys [vbox vport] :as local}]
|
||||||
|
(let [srect (geom/adjust-to-viewport vport srect {:padding 40})
|
||||||
|
zoom (/ (:width vport) (:width srect))]
|
||||||
|
(-> local
|
||||||
|
(assoc :zoom zoom)
|
||||||
|
(update :vbox merge srect)))))))))))
|
||||||
|
|
||||||
;; --- Selection Rect
|
;; --- Selection Rect
|
||||||
|
|
||||||
|
@ -1464,9 +1457,10 @@
|
||||||
"ctrl+g" #(st/emit! create-group)
|
"ctrl+g" #(st/emit! create-group)
|
||||||
"ctrl+shift+g" #(st/emit! remove-group)
|
"ctrl+shift+g" #(st/emit! remove-group)
|
||||||
"shift+0" #(st/emit! zoom-to-50)
|
"shift+0" #(st/emit! zoom-to-50)
|
||||||
"shift+1" #(st/emit! reset-zoom)
|
;; "shift+1" #(st/emit! reset-zoom)
|
||||||
"shift+2" #(st/emit! zoom-to-200)
|
"shift+1" #(st/emit! zoom-to-fit-all)
|
||||||
;; "shift+2" #(st/emit! zoom-to-selected-shape)
|
;; "shift+2" #(st/emit! zoom-to-200)
|
||||||
|
"shift+2" #(st/emit! zoom-to-selected-shape)
|
||||||
"ctrl+d" #(st/emit! duplicate-selected)
|
"ctrl+d" #(st/emit! duplicate-selected)
|
||||||
"ctrl+z" #(st/emit! dwc/undo)
|
"ctrl+z" #(st/emit! dwc/undo)
|
||||||
"ctrl+shift+z" #(st/emit! dwc/redo)
|
"ctrl+shift+z" #(st/emit! dwc/redo)
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
(ns uxbox.main.data.workspace.transforms
|
(ns uxbox.main.data.workspace.transforms
|
||||||
"Events related with shapes transformations"
|
"Events related with shapes transformations"
|
||||||
(:require
|
(:require
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
;; 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/.
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
(ns uxbox.main.exports
|
(ns uxbox.main.exports
|
||||||
"The main logic for SVG export functionality."
|
"The main logic for SVG export functionality."
|
||||||
|
@ -34,13 +37,11 @@
|
||||||
:fill background-color}])
|
:fill background-color}])
|
||||||
|
|
||||||
(defn- calculate-dimensions
|
(defn- calculate-dimensions
|
||||||
[data]
|
[{:keys [objects] :as data} vport]
|
||||||
(let [shapes (vals (:objects data))
|
(let [shapes (cp/select-toplevel-shapes objects {:include-frames? true})]
|
||||||
shape (geom/shapes->rect-shape shapes)
|
(->> (geom/shapes->rect-shape shapes)
|
||||||
width (+ (:x shape) (:width shape) 100)
|
(geom/adjust-to-viewport vport)
|
||||||
height (+ (:y shape) (:height shape) 100)]
|
(geom/fix-invalid-rect-values))))
|
||||||
{:width (if (mth/nan? width) 100 width)
|
|
||||||
:height (if (mth/nan? height) 100 height)}))
|
|
||||||
|
|
||||||
(declare shape-wrapper-factory)
|
(declare shape-wrapper-factory)
|
||||||
|
|
||||||
|
@ -86,14 +87,19 @@
|
||||||
|
|
||||||
(mf/defc page-svg
|
(mf/defc page-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [data] :as props}]
|
[{:keys [data width height] :as props}]
|
||||||
(let [objects (:objects data)
|
(let [objects (:objects data)
|
||||||
dim (calculate-dimensions data)
|
vport {:width width :height height}
|
||||||
|
|
||||||
|
dim (calculate-dimensions data vport)
|
||||||
root (get objects uuid/zero)
|
root (get objects uuid/zero)
|
||||||
shapes (->> (:shapes root)
|
shapes (->> (:shapes root)
|
||||||
(map #(get objects %)))
|
(map #(get objects %)))
|
||||||
|
|
||||||
vbox (str "0 0 " (:width dim 0) " " (:height dim 0))
|
vbox (str (:x dim 0) " "
|
||||||
|
(:y dim 0) " "
|
||||||
|
(:width dim 100) " "
|
||||||
|
(:height dim 100))
|
||||||
|
|
||||||
frame-wrapper
|
frame-wrapper
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
|
@ -104,7 +110,6 @@
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
(mf/deps objects)
|
(mf/deps objects)
|
||||||
#(shape-wrapper-factory objects))]
|
#(shape-wrapper-factory objects))]
|
||||||
|
|
||||||
[:svg {:view-box vbox
|
[:svg {:view-box vbox
|
||||||
:version "1.1"
|
:version "1.1"
|
||||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||||
|
|
|
@ -61,11 +61,14 @@
|
||||||
[:*
|
[:*
|
||||||
[:div.empty-rule-square]
|
[:div.empty-rule-square]
|
||||||
[:& horizontal-rule {:zoom (:zoom local)
|
[:& horizontal-rule {:zoom (:zoom local)
|
||||||
:size (:size local)}]
|
:vbox (:vbox local)
|
||||||
|
:vport (:vport local)}]
|
||||||
[:& vertical-rule {:zoom (:zoom local 1)
|
[:& vertical-rule {:zoom (:zoom local 1)
|
||||||
:size (:size local)}]])
|
:vbox (:vbox local)
|
||||||
|
:vport (:vport local)}]])
|
||||||
|
|
||||||
[:& viewport {:page page
|
[:& viewport {:page page
|
||||||
|
:key (:id page)
|
||||||
:file file
|
:file file
|
||||||
:local local}]]]
|
:local local}]]]
|
||||||
|
|
||||||
|
|
|
@ -10,121 +10,100 @@
|
||||||
(ns uxbox.main.ui.workspace.rules
|
(ns uxbox.main.ui.workspace.rules
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
|
[uxbox.util.math :as mth]
|
||||||
[uxbox.util.object :as obj]))
|
[uxbox.util.object :as obj]))
|
||||||
|
|
||||||
(def STEP-PADDING 20)
|
(defn draw-rule!
|
||||||
|
[dctx {:keys [zoom size start count type] :or {count 200}}]
|
||||||
|
(let [txfm (- (* (- 0 start) zoom) 20)
|
||||||
|
minv (mth/round start)
|
||||||
|
maxv (mth/round (+ start (/ size zoom)))
|
||||||
|
|
||||||
(mf/defc horizontal-rule
|
step (mth/round (/ (mth/abs (- maxv minv)) count))
|
||||||
[{:keys [zoom size]}]
|
step (max (* 1 (* 10 step)) 1)]
|
||||||
(let [canvas (mf/use-ref)
|
|
||||||
{:keys [x viewport-width width]} size]
|
|
||||||
|
|
||||||
(mf/use-layout-effect
|
|
||||||
(mf/deps viewport-width width x zoom)
|
|
||||||
(fn []
|
|
||||||
(let [node (mf/ref-val canvas)
|
|
||||||
dctx (.getContext node "2d")
|
|
||||||
|
|
||||||
btm 1
|
|
||||||
trx (- (* (- 0 x) zoom) 50)
|
|
||||||
|
|
||||||
min-val (js/Math.round x)
|
|
||||||
max-val (js/Math.round (+ x (/ viewport-width zoom)))
|
|
||||||
|
|
||||||
tmp0 (js/Math.abs (- max-val min-val))
|
|
||||||
tmp1 (js/Math.round (/ tmp0 200))
|
|
||||||
btm (max (* btm (* 10 tmp1)) 1)]
|
|
||||||
|
|
||||||
(obj/set! node "width" viewport-width)
|
|
||||||
|
|
||||||
(obj/set! dctx "fillStyle" "#E8E9EA")
|
(obj/set! dctx "fillStyle" "#E8E9EA")
|
||||||
(.fillRect dctx 0 0 viewport-width 20)
|
(if (= type :horizontal)
|
||||||
|
(do
|
||||||
(.save dctx)
|
(.fillRect dctx 0 0 size 20)
|
||||||
(.translate dctx trx 0)
|
(.translate dctx txfm 0))
|
||||||
|
(do
|
||||||
|
(.fillRect dctx 0 0 20 size)
|
||||||
|
(.translate dctx 0 txfm)))
|
||||||
|
|
||||||
(obj/set! dctx "font" "12px serif")
|
(obj/set! dctx "font" "12px serif")
|
||||||
(obj/set! dctx "fillStyle" "#7B7D85")
|
(obj/set! dctx "fillStyle" "#7B7D85")
|
||||||
(obj/set! dctx "strokeStyle" "#7B7D85")
|
(obj/set! dctx "strokeStyle" "#7B7D85")
|
||||||
(obj/set! dctx "textAlign" "center")
|
(obj/set! dctx "textAlign" "center")
|
||||||
|
|
||||||
(loop [i min-val]
|
(loop [i minv]
|
||||||
(when (< i max-val)
|
(when (< i maxv)
|
||||||
(let [pos (+ (* i zoom) 50)]
|
(let [pos (+ (* i zoom) 0)]
|
||||||
(when (= (mod i btm) 0)
|
(when (= (mod i step) 0)
|
||||||
(.fillText dctx (str i) (- pos 0) 13))
|
|
||||||
(recur (+ i 1)))))
|
|
||||||
|
|
||||||
(let [path (js/Path2D.)]
|
|
||||||
(loop [i min-val]
|
|
||||||
(if (> i max-val)
|
|
||||||
(.stroke dctx path)
|
|
||||||
(let [pos (+ (* i zoom) 50)]
|
|
||||||
(when (= (mod i btm) 0)
|
|
||||||
(.moveTo path pos 17)
|
|
||||||
(.lineTo path pos STEP-PADDING))
|
|
||||||
(recur (inc i))))))
|
|
||||||
|
|
||||||
(.restore dctx))))
|
|
||||||
|
|
||||||
[:canvas.horizontal-rule {:ref canvas :width (:viewport-width size) :height 20}]))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Vertical Rule (Component)
|
|
||||||
|
|
||||||
(mf/defc vertical-rule
|
|
||||||
{::mf/wrap [mf/memo #(mf/throttle % 60)]}
|
|
||||||
[{:keys [zoom size]}]
|
|
||||||
(let [canvas (mf/use-ref)
|
|
||||||
{:keys [y height viewport-height]} size]
|
|
||||||
(mf/use-layout-effect
|
|
||||||
(mf/deps height y zoom)
|
|
||||||
(fn []
|
|
||||||
(let [node (mf/ref-val canvas)
|
|
||||||
dctx (.getContext node "2d")
|
|
||||||
|
|
||||||
btm 1
|
|
||||||
try (- (* (- 0 y) zoom) 50)
|
|
||||||
|
|
||||||
min-val (js/Math.round y)
|
|
||||||
max-val (js/Math.round (+ y (/ viewport-height zoom)))
|
|
||||||
|
|
||||||
tmp0 (js/Math.abs (- max-val min-val))
|
|
||||||
tmp1 (js/Math.round (/ tmp0 100))
|
|
||||||
btm (max (* btm (* 10 tmp1)) 1)]
|
|
||||||
|
|
||||||
(obj/set! node "height" viewport-height)
|
|
||||||
|
|
||||||
(obj/set! dctx "fillStyle" "#E8E9EA")
|
|
||||||
(.fillRect dctx 0 0 20 viewport-height)
|
|
||||||
|
|
||||||
(obj/set! dctx "font" "11px serif")
|
|
||||||
(obj/set! dctx "fillStyle" "#7B7D85")
|
|
||||||
(obj/set! dctx "strokeStyle" "#7B7D85")
|
|
||||||
(obj/set! dctx "textAlign" "center")
|
|
||||||
|
|
||||||
(.translate dctx 0 try)
|
|
||||||
|
|
||||||
(loop [i min-val]
|
|
||||||
(when (< i max-val)
|
|
||||||
(let [pos (+ (* i zoom) 50)]
|
|
||||||
(when (= (mod i btm) 0)
|
|
||||||
(.save dctx)
|
(.save dctx)
|
||||||
|
(if (= type :horizontal)
|
||||||
|
(do
|
||||||
|
(.fillText dctx (str i) pos 13))
|
||||||
|
(do
|
||||||
(.translate dctx 12 pos)
|
(.translate dctx 12 pos)
|
||||||
(.rotate dctx (/ (* 270 js/Math.PI) 180))
|
(.rotate dctx (/ (* 270 js/Math.PI) 180))
|
||||||
(.fillText dctx (str i) 0 0)
|
(.fillText dctx (str i) 0 0)))
|
||||||
(.restore dctx))
|
(.restore dctx))
|
||||||
(recur (inc i)))))
|
(recur (inc i)))))
|
||||||
|
|
||||||
(let [path (js/Path2D.)]
|
(let [path (js/Path2D.)]
|
||||||
(loop [i min-val]
|
(loop [i minv]
|
||||||
(if (> i max-val)
|
(if (> i maxv)
|
||||||
(.stroke dctx path)
|
(.stroke dctx path)
|
||||||
(let [pos (+ (* i zoom) 50)]
|
(let [pos (+ (* i zoom) 0)]
|
||||||
(when (= (mod i btm) 0)
|
(when (= (mod i step) 0)
|
||||||
|
(if (= type :horizontal)
|
||||||
|
(do
|
||||||
|
(.moveTo path pos 17)
|
||||||
|
(.lineTo path pos 20))
|
||||||
|
(do
|
||||||
(.moveTo path 17 pos)
|
(.moveTo path 17 pos)
|
||||||
(.lineTo path STEP-PADDING pos))
|
(.lineTo path 20 pos))))
|
||||||
(recur (inc i)))))))))
|
(recur (inc i))))))))
|
||||||
|
|
||||||
[:canvas.vertical-rule {:ref canvas :width 20 :height height}]))
|
|
||||||
|
|
||||||
|
(mf/defc horizontal-rule
|
||||||
|
[{:keys [zoom vbox vport] :as props}]
|
||||||
|
(let [canvas (mf/use-ref)
|
||||||
|
width (- (:width vport) 20)]
|
||||||
|
(mf/use-layout-effect
|
||||||
|
(mf/deps zoom width (:x vbox))
|
||||||
|
(fn []
|
||||||
|
(let [node (mf/ref-val canvas)
|
||||||
|
dctx (.getContext ^js node "2d")]
|
||||||
|
(obj/set! node "width" width)
|
||||||
|
(draw-rule! dctx {:zoom zoom
|
||||||
|
:type :horizontal
|
||||||
|
:size width
|
||||||
|
:start (:x vbox)}))))
|
||||||
|
|
||||||
|
[:canvas.horizontal-rule
|
||||||
|
{:ref canvas
|
||||||
|
:width width
|
||||||
|
:height 20}]))
|
||||||
|
|
||||||
|
(mf/defc vertical-rule
|
||||||
|
[{:keys [zoom vbox vport] :as props}]
|
||||||
|
(let [canvas (mf/use-ref)
|
||||||
|
height (- (:height vport) 20)]
|
||||||
|
(mf/use-layout-effect
|
||||||
|
(mf/deps zoom height (:y vbox))
|
||||||
|
(fn []
|
||||||
|
(let [node (mf/ref-val canvas)
|
||||||
|
dctx (.getContext ^js node "2d")]
|
||||||
|
(obj/set! node "height" height)
|
||||||
|
(draw-rule! dctx {:zoom zoom
|
||||||
|
:type :vertical
|
||||||
|
:size height
|
||||||
|
:count 100
|
||||||
|
:start (:y vbox)}))))
|
||||||
|
|
||||||
|
[:canvas.vertical-rule
|
||||||
|
{:ref canvas
|
||||||
|
:width 20
|
||||||
|
:height height}]))
|
||||||
|
|
|
@ -118,7 +118,7 @@
|
||||||
:width (+ width 2)
|
:width (+ width 2)
|
||||||
:height (+ height 2)
|
:height (+ height 2)
|
||||||
:style {:stroke "#1FDEA7"
|
:style {:stroke "#1FDEA7"
|
||||||
:stroke-width "1"
|
:stroke-width (/ 1 zoom)
|
||||||
:fill "transparent"}}])
|
:fill "transparent"}}])
|
||||||
|
|
||||||
(when (not (#{:move :rotate} current-transform))
|
(when (not (#{:move :rotate} current-transform))
|
||||||
|
|
|
@ -98,7 +98,8 @@
|
||||||
:transform (str
|
:transform (str
|
||||||
"scale(" inv-zoom ", " inv-zoom ") "
|
"scale(" inv-zoom ", " inv-zoom ") "
|
||||||
"translate(" (* zoom (:x label-pos)) ", "
|
"translate(" (* zoom (:x label-pos)) ", "
|
||||||
(* zoom (:y label-pos)) ")")
|
(* zoom (:y label-pos))
|
||||||
|
")")
|
||||||
;; User may also select the frame with single click in the label
|
;; User may also select the frame with single click in the label
|
||||||
:on-click on-double-click}
|
:on-click on-double-click}
|
||||||
(:name shape)]
|
(:name shape)]
|
||||||
|
|
|
@ -130,7 +130,8 @@
|
||||||
{:keys [drawing-tool
|
{:keys [drawing-tool
|
||||||
zoom
|
zoom
|
||||||
flags
|
flags
|
||||||
size
|
vport
|
||||||
|
vbox
|
||||||
edition
|
edition
|
||||||
tooltip
|
tooltip
|
||||||
selected]} local
|
selected]} local
|
||||||
|
@ -276,7 +277,8 @@
|
||||||
(st/emit! (dw/decrease-zoom pos))
|
(st/emit! (dw/decrease-zoom pos))
|
||||||
(st/emit! (dw/increase-zoom pos))))
|
(st/emit! (dw/increase-zoom pos))))
|
||||||
(let [event (.getBrowserEvent event)
|
(let [event (.getBrowserEvent event)
|
||||||
delta (.-deltaY ^js event)]
|
delta (.-deltaY ^js event)
|
||||||
|
delta (/ delta @refs/selected-zoom)]
|
||||||
(if (kbd/shift? event)
|
(if (kbd/shift? event)
|
||||||
(st/emit! (dw/update-viewport-position {:x #(+ % delta)}))
|
(st/emit! (dw/update-viewport-position {:x #(+ % delta)}))
|
||||||
(st/emit! (dw/update-viewport-position {:y #(+ % delta)})))))))
|
(st/emit! (dw/update-viewport-position {:y #(+ % delta)})))))))
|
||||||
|
@ -299,28 +301,23 @@
|
||||||
on-resize
|
on-resize
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [node (mf/ref-val viewport-ref)
|
(let [node (mf/ref-val viewport-ref)
|
||||||
parent (.-parentElement ^js node)]
|
prnt (dom/get-parent node)]
|
||||||
(st/emit! (dw/update-viewport-size
|
(st/emit! (dw/update-viewport-size (dom/get-client-size prnt)))))
|
||||||
{:width (.-clientWidth ^js parent)
|
|
||||||
:height (.-clientHeight ^js parent)}))))
|
|
||||||
|
|
||||||
on-mount
|
on-mount
|
||||||
(fn []
|
(fn []
|
||||||
(let [node (mf/ref-val viewport-ref)
|
(let [node (mf/ref-val viewport-ref)
|
||||||
prnt (.-parentElement ^js node)
|
prnt (dom/get-parent node)
|
||||||
|
|
||||||
key1 (events/listen js/document EventType.KEYDOWN on-key-down)
|
key1 (events/listen js/document EventType.KEYDOWN on-key-down)
|
||||||
key2 (events/listen js/document EventType.KEYUP on-key-up)
|
key2 (events/listen js/document EventType.KEYUP on-key-up)
|
||||||
key3 (events/listen node EventType.MOUSEMOVE on-mouse-move)
|
key3 (events/listen node EventType.MOUSEMOVE on-mouse-move)
|
||||||
;; bind with passive=false to allow the event to be cancelled
|
;; bind with passive=false to allow the event to be cancelled
|
||||||
;; https://stackoverflow.com/a/57582286/3219895
|
;; https://stackoverflow.com/a/57582286/3219895
|
||||||
key4 (events/listen js/window EventType.WHEEL on-mouse-wheel
|
key4 (events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
|
||||||
#js {"passive" false})
|
|
||||||
key5 (events/listen js/window EventType.RESIZE on-resize)]
|
key5 (events/listen js/window EventType.RESIZE on-resize)]
|
||||||
|
|
||||||
(st/emit! (dw/initialize-viewport
|
(st/emit! (dw/initialize-viewport (dom/get-client-size prnt)))
|
||||||
{:width (.-clientWidth ^js prnt)
|
|
||||||
:height (.-clientHeight ^js prnt)}))
|
|
||||||
|
|
||||||
(fn []
|
(fn []
|
||||||
(events/unlistenByKey key1)
|
(events/unlistenByKey key1)
|
||||||
|
@ -335,13 +332,14 @@
|
||||||
(mf/use-effect on-mount)
|
(mf/use-effect on-mount)
|
||||||
[:*
|
[:*
|
||||||
[:& coordinates {:zoom zoom}]
|
[:& coordinates {:zoom zoom}]
|
||||||
[:svg.viewport {
|
[:svg.viewport
|
||||||
:width (:viewport-width size)
|
{:preserveAspectRatio "xMidYMid meet"
|
||||||
:height (:viewport-height size)
|
:width (:width vport 0)
|
||||||
:view-box (str/join " " [(:x size)
|
:height (:height vport 0)
|
||||||
(:y size)
|
:view-box (str/join " " [(:x vbox 0)
|
||||||
(:width size)
|
(:y vbox 0)
|
||||||
(:height size)])
|
(:width vbox 0 )
|
||||||
|
(:height vbox 0)])
|
||||||
:ref viewport-ref
|
:ref viewport-ref
|
||||||
:class (when drawing-tool "drawing")
|
:class (when drawing-tool "drawing")
|
||||||
:on-context-menu on-context-menu
|
:on-context-menu on-context-menu
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
;; defined by the Mozilla Public License, v. 2.0.
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
|
||||||
|
|
||||||
(ns uxbox.util.dom
|
(ns uxbox.util.dom
|
||||||
(:require
|
(:require
|
||||||
|
@ -69,6 +68,10 @@
|
||||||
[event]
|
[event]
|
||||||
(.-target event))
|
(.-target event))
|
||||||
|
|
||||||
|
(defn get-parent
|
||||||
|
[dom]
|
||||||
|
(.-parentElement ^js dom))
|
||||||
|
|
||||||
(defn get-value
|
(defn get-value
|
||||||
"Extract the value from dom node."
|
"Extract the value from dom node."
|
||||||
[node]
|
[node]
|
||||||
|
@ -150,6 +153,11 @@
|
||||||
y (.-clientY event)]
|
y (.-clientY event)]
|
||||||
(gpt/point x y)))
|
(gpt/point x y)))
|
||||||
|
|
||||||
|
(defn get-client-size
|
||||||
|
[node]
|
||||||
|
{:width (.-clientWidth ^js node)
|
||||||
|
:height (.-clientHeight ^js node)})
|
||||||
|
|
||||||
(defn focus!
|
(defn focus!
|
||||||
[node]
|
[node]
|
||||||
(.focus node))
|
(.focus node))
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
;; 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/.
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
;;
|
;;
|
||||||
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
;; Copyright (c) 2020 UXBOX Labs SL
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
(ns uxbox.util.geom.shapes
|
(ns uxbox.util.geom.shapes
|
||||||
|
@ -80,52 +83,6 @@
|
||||||
dy (if y (- (_chk y) (_chk (:y shape))) 0)]
|
dy (if y (- (_chk y) (_chk (:y shape))) 0)]
|
||||||
(move shape (gpt/point dx dy))))
|
(move shape (gpt/point dx dy))))
|
||||||
|
|
||||||
;; --- Rotation
|
|
||||||
|
|
||||||
;; TODO: maybe we can consider apply the rotation
|
|
||||||
;; directly to the shape coordinates?
|
|
||||||
;; FIXME: deprecated, should be removed
|
|
||||||
|
|
||||||
(defn rotate
|
|
||||||
"Apply the rotation to the shape."
|
|
||||||
[shape rotation]
|
|
||||||
(assoc shape :rotation rotation))
|
|
||||||
|
|
||||||
;; --- Corner points
|
|
||||||
|
|
||||||
(defn corner-points [points]
|
|
||||||
(let [minx (apply min (map :x points))
|
|
||||||
miny (apply min (map :y points))
|
|
||||||
maxx (apply max (map :x points))
|
|
||||||
maxy (apply max (map :y points))]
|
|
||||||
{:x1 minx :y1 miny :x2 maxx :y2 maxy}))
|
|
||||||
|
|
||||||
;; --- Size
|
|
||||||
|
|
||||||
(declare size-path)
|
|
||||||
|
|
||||||
(defn size
|
|
||||||
"Calculate the size of the shape."
|
|
||||||
[shape]
|
|
||||||
(case (:type shape)
|
|
||||||
:curve (size-path shape)
|
|
||||||
:path (size-path shape)
|
|
||||||
shape))
|
|
||||||
|
|
||||||
(defn- size-path
|
|
||||||
[{:keys [segments x1 y1 x2 y2] :as shape}]
|
|
||||||
(if (and x1 y1 x2 y2)
|
|
||||||
(assoc shape
|
|
||||||
:width (- x2 x1)
|
|
||||||
:height (- y2 y1))
|
|
||||||
(let [minx (apply min (map :x segments))
|
|
||||||
miny (apply min (map :y segments))
|
|
||||||
maxx (apply max (map :x segments))
|
|
||||||
maxy (apply max (map :y segments))]
|
|
||||||
(assoc shape
|
|
||||||
:width (- maxx minx)
|
|
||||||
:height (- maxy miny)))))
|
|
||||||
|
|
||||||
;; --- Center
|
;; --- Center
|
||||||
|
|
||||||
(declare center-rect)
|
(declare center-rect)
|
||||||
|
@ -174,8 +131,6 @@
|
||||||
[{:keys [width height] :as shape}]
|
[{:keys [width height] :as shape}]
|
||||||
(assoc shape :proportion (/ width height)))
|
(assoc shape :proportion (/ width height)))
|
||||||
|
|
||||||
;; TODO: implement the rest of shapes
|
|
||||||
|
|
||||||
;; --- Paths
|
;; --- Paths
|
||||||
|
|
||||||
(defn update-path-point
|
(defn update-path-point
|
||||||
|
@ -231,49 +186,6 @@
|
||||||
(assoc :height value)
|
(assoc :height value)
|
||||||
(assoc :width (* value proportion)))))))
|
(assoc :width (* value proportion)))))))
|
||||||
|
|
||||||
;; --- Resize
|
|
||||||
|
|
||||||
(defn calculate-scale-ratio
|
|
||||||
"Calculate the scale factor from one shape to an other.
|
|
||||||
|
|
||||||
The shapes should be of rect-like type because width
|
|
||||||
and height are used for calculate the ratio."
|
|
||||||
[origin final]
|
|
||||||
[(/ (:width final) (:width origin))
|
|
||||||
(/ (:height final) (:height origin))])
|
|
||||||
|
|
||||||
(defn- get-vid-coords [vid]
|
|
||||||
(case vid
|
|
||||||
:top-left [:x2 :y2]
|
|
||||||
:top-right [:x1 :y2]
|
|
||||||
:top [:x1 :y2]
|
|
||||||
:bottom-left [:x2 :y1]
|
|
||||||
:bottom-right [:x :y ]
|
|
||||||
:bottom [:x1 :y1]
|
|
||||||
:right [:x1 :y1]
|
|
||||||
:left [:x2 :y1]))
|
|
||||||
|
|
||||||
(defn resize-shape
|
|
||||||
"Apply a resize transformation to a rect-like shape. The shape
|
|
||||||
should have the `width` and `height` attrs, because these attrs
|
|
||||||
are used for the resize transformation.
|
|
||||||
|
|
||||||
Mainly used in drawarea and interactive resize on workspace
|
|
||||||
with the main objective that on the end of resize have a way
|
|
||||||
a calculte the resize ratio with `calculate-scale-ratio`."
|
|
||||||
[vid shape initial target lock?]
|
|
||||||
|
|
||||||
(let [{:keys [x y]} (gpt/subtract target initial)
|
|
||||||
[cor-x cor-y] (get-vid-coords vid)]
|
|
||||||
(let [final-x (if (#{:top :bottom} vid) (:x2 shape) x)
|
|
||||||
final-y (if (#{:right :left} vid) (:y2 shape) y)
|
|
||||||
width (Math/abs (- final-x (cor-x shape)))
|
|
||||||
height (Math/abs (- final-y (cor-y shape)))
|
|
||||||
proportion (:proportion shape 1)]
|
|
||||||
(assoc shape
|
|
||||||
:width width
|
|
||||||
:height (if lock? (/ width proportion) height)))))
|
|
||||||
|
|
||||||
;; --- Setup (Initialize)
|
;; --- Setup (Initialize)
|
||||||
|
|
||||||
(declare setup-rect)
|
(declare setup-rect)
|
||||||
|
@ -454,15 +366,6 @@
|
||||||
|
|
||||||
;; --- Outer Rect
|
;; --- Outer Rect
|
||||||
|
|
||||||
(defn rotation-matrix
|
|
||||||
"Generate a rotation matrix from shape."
|
|
||||||
[{:keys [x y width height rotation] :as shape}]
|
|
||||||
(let [cx (+ x (/ width 2))
|
|
||||||
cy (+ y (/ height 2))]
|
|
||||||
(cond-> (gmt/matrix)
|
|
||||||
(and rotation (pos? rotation))
|
|
||||||
(gmt/rotate rotation (gpt/point cx cy)))))
|
|
||||||
|
|
||||||
(declare transform-apply-modifiers)
|
(declare transform-apply-modifiers)
|
||||||
|
|
||||||
(defn selection-rect-shape
|
(defn selection-rect-shape
|
||||||
|
@ -730,7 +633,8 @@
|
||||||
(gpt/divide (gpt/point (:width shape-path-temp-rec) (:height shape-path-temp-rec))
|
(gpt/divide (gpt/point (:width shape-path-temp-rec) (:height shape-path-temp-rec))
|
||||||
(gpt/point (:width shape-path-temp-dim) (:height shape-path-temp-dim)))))
|
(gpt/point (:width shape-path-temp-dim) (:height shape-path-temp-dim)))))
|
||||||
|
|
||||||
(defn- fix-invalid-rect-values [rect-shape]
|
(defn fix-invalid-rect-values
|
||||||
|
[rect-shape]
|
||||||
(letfn [(check [num] (if (or (nil? num) (mth/nan? num)) 0 num))
|
(letfn [(check [num] (if (or (nil? num) (mth/nan? num)) 0 num))
|
||||||
(to-positive [num] (if (< num 1) 1 num))]
|
(to-positive [num] (if (< num 1) 1 num))]
|
||||||
(-> rect-shape
|
(-> rect-shape
|
||||||
|
@ -831,3 +735,33 @@
|
||||||
(gmt/translate shape-center)
|
(gmt/translate shape-center)
|
||||||
(gmt/multiply (:transform shape (gmt/matrix)))
|
(gmt/multiply (:transform shape (gmt/matrix)))
|
||||||
(gmt/translate (gpt/negate shape-center))))))
|
(gmt/translate (gpt/negate shape-center))))))
|
||||||
|
|
||||||
|
(defn adjust-to-viewport
|
||||||
|
([viewport srect] (adjust-to-viewport viewport srect nil))
|
||||||
|
([viewport srect {:keys [padding] :or {padding 0}}]
|
||||||
|
(let [gprop (/ (:width viewport) (:height viewport))
|
||||||
|
srect (-> srect
|
||||||
|
(update :x #(- % padding))
|
||||||
|
(update :y #(- % padding))
|
||||||
|
(update :width #(+ % padding padding))
|
||||||
|
(update :height #(+ % padding padding)))
|
||||||
|
width (:width srect)
|
||||||
|
height (:height srect)
|
||||||
|
lprop (/ width height)]
|
||||||
|
(cond
|
||||||
|
(> gprop lprop)
|
||||||
|
(let [width' (* (/ width lprop) gprop)
|
||||||
|
padding (/ (- width' width) 2)]
|
||||||
|
(-> srect
|
||||||
|
(update :x #(- % padding))
|
||||||
|
(assoc :width width')))
|
||||||
|
|
||||||
|
(< gprop lprop)
|
||||||
|
(let [height' (/ (* height lprop) gprop)
|
||||||
|
padding (/ (- height' height) 2)]
|
||||||
|
(-> srect
|
||||||
|
(update :y #(- % padding))
|
||||||
|
(assoc :height height')))
|
||||||
|
|
||||||
|
:else srect))))
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
;; 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/.
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
;;
|
;;
|
||||||
;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
;; Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
(ns uxbox.util.math
|
(ns uxbox.util.math
|
||||||
"A collection of math utils."
|
"A collection of math utils."
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue