mirror of
https://github.com/penpot/penpot.git
synced 2025-02-08 16:18:11 -05:00
✨ Linear and radial gradient handlers
This commit is contained in:
parent
8466c1c54d
commit
08b537a158
6 changed files with 442 additions and 26 deletions
|
@ -199,3 +199,26 @@
|
|||
(defn center-points [points]
|
||||
(let [k (point (count points))]
|
||||
(reduce #(add %1 (divide %2 k)) (point) points)))
|
||||
|
||||
(defn normal-left
|
||||
"Returns the normal unit vector on the left side"
|
||||
[{:keys [x y]}]
|
||||
(unit (point (- y) x)))
|
||||
|
||||
(defn normal-right
|
||||
"Returns the normal unit vector on the right side"
|
||||
[{:keys [x y]}]
|
||||
(unit (point y (- x))))
|
||||
|
||||
(defn point-line-distance
|
||||
[point line-point1 line-point2]
|
||||
(let [{x0 :x y0 :y} point
|
||||
{x1 :x y1 :y} line-point1
|
||||
{x2 :x y2 :y} line-point2
|
||||
num (mth/abs
|
||||
(+ (* x0 (- y2 y1))
|
||||
(- (* y0 (- x2 x1)))
|
||||
(* x2 y1)
|
||||
(- (* y2 x1))))
|
||||
dist (distance line-point2 line-point1)]
|
||||
(/ num dist)))
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
;; Copyright (c) 2016-2020 UXBOX Labs SL
|
||||
|
||||
(ns app.main.ui.shapes.attrs
|
||||
(:require [app.util.object :as obj]))
|
||||
(:require
|
||||
[cuerdas.core :as str]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
(defn- stroke-type->dasharray
|
||||
[style]
|
||||
|
@ -19,16 +21,20 @@
|
|||
nil))
|
||||
|
||||
(defn extract-style-attrs
|
||||
[shape]
|
||||
(let [stroke-style (:stroke-style shape :none)
|
||||
attrs #js {:fill (or (:fill-color shape) "transparent")
|
||||
:fillOpacity (:fill-opacity shape nil)
|
||||
:rx (:rx shape nil)
|
||||
:ry (:ry shape nil)}]
|
||||
(when (not= stroke-style :none)
|
||||
(obj/merge! attrs
|
||||
#js {:stroke (:stroke-color shape nil)
|
||||
:strokeWidth (:stroke-width shape 1)
|
||||
:strokeOpacity (:stroke-opacity shape nil)
|
||||
:strokeDasharray (stroke-type->dasharray stroke-style)}))
|
||||
attrs))
|
||||
([shape] (extract-style-attrs shape nil))
|
||||
([shape gradient-id]
|
||||
(let [stroke-style (:stroke-style shape :none)
|
||||
attrs #js {:rx (:rx shape nil)
|
||||
:ry (:ry shape nil)}
|
||||
attrs (obj/merge! attrs
|
||||
(if gradient-id
|
||||
#js {:fill (str/format "url(#%s)" gradient-id)}
|
||||
#js {:fill (or (:fill-color shape) "transparent")
|
||||
:fillOpacity (:fill-opacity shape nil)}))]
|
||||
(when (not= stroke-style :none)
|
||||
(obj/merge! attrs
|
||||
#js {:stroke (:stroke-color shape nil)
|
||||
:strokeWidth (:stroke-width shape 1)
|
||||
:strokeOpacity (:stroke-opacity shape nil)
|
||||
:strokeDasharray (stroke-type->dasharray stroke-style)}))
|
||||
attrs)))
|
||||
|
|
78
frontend/src/app/main/ui/shapes/gradients.cljs
Normal file
78
frontend/src/app/main/ui/shapes/gradients.cljs
Normal file
|
@ -0,0 +1,78 @@
|
|||
;; 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 app.main.ui.shapes.gradients
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[goog.object :as gobj]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.common.geom.point :as gpt]))
|
||||
|
||||
(mf/defc linear-gradient [{:keys [id shape gradient]}]
|
||||
(let [{:keys [x y width height]} shape]
|
||||
[:defs
|
||||
[:linearGradient {:id id
|
||||
:x1 (:start-x gradient)
|
||||
:y1 (:start-y gradient)
|
||||
:x2 (:end-x gradient)
|
||||
:y2 (:end-y gradient)}
|
||||
(for [{:keys [offset color opacity]} (:stops gradient)]
|
||||
[:stop {:key (str id "-stop-" offset)
|
||||
:offset (or offset 0)
|
||||
:stop-color color
|
||||
:stop-opacity opacity}])]]))
|
||||
|
||||
(mf/defc radial-gradient [{:keys [id shape gradient]}]
|
||||
(let [{:keys [x y width height]} shape]
|
||||
[:defs
|
||||
(let [translate-vec (gpt/point (+ x (* width (:start-x gradient)))
|
||||
(+ y (* height (:start-y gradient))))
|
||||
|
||||
|
||||
gradient-vec (gpt/to-vec (gpt/point (* width (:start-x gradient))
|
||||
(* height (:start-y gradient)))
|
||||
(gpt/point (* width (:end-x gradient))
|
||||
(* height (:end-y gradient))))
|
||||
|
||||
angle (gpt/angle gradient-vec
|
||||
(gpt/point 1 0))
|
||||
|
||||
shape-height-vec (gpt/point 0 (/ height 2))
|
||||
|
||||
scale-factor-y (/ (gpt/length gradient-vec) (/ height 2))
|
||||
scale-factor-x (* scale-factor-y (:width gradient))
|
||||
|
||||
scale-vec (gpt/point (* scale-factor-y (/ height 2))
|
||||
(* scale-factor-x (/ width 2))
|
||||
)
|
||||
tr-translate (str/fmt "translate(%s, %s)" (:x translate-vec) (:y translate-vec))
|
||||
tr-rotate (str/fmt "rotate(%s)" angle)
|
||||
tr-scale (str/fmt "scale(%s, %s)" (:x scale-vec) (:y scale-vec))
|
||||
transform (str/fmt "%s %s %s" tr-translate tr-rotate tr-scale)]
|
||||
[:radialGradient {:id id
|
||||
:cx 0
|
||||
:cy 0
|
||||
:r 1
|
||||
:gradientUnits "userSpaceOnUse"
|
||||
:gradientTransform transform}
|
||||
(for [{:keys [offset color opacity]} (:stops gradient)]
|
||||
[:stop {:key (str id "-stop-" offset)
|
||||
:offset (or offset 0)
|
||||
:stop-color color
|
||||
:stop-opacity opacity}])])]))
|
||||
|
||||
(mf/defc gradient
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [gradient (gobj/get props "gradient")]
|
||||
(case (:type gradient)
|
||||
:linear [:> linear-gradient props]
|
||||
:radial [:> radial-gradient props]
|
||||
nil)))
|
|
@ -13,7 +13,12 @@
|
|||
[app.main.ui.shapes.attrs :as attrs]
|
||||
[app.main.ui.shapes.custom-stroke :refer [shape-custom-stroke]]
|
||||
[app.common.geom.shapes :as geom]
|
||||
[app.util.object :as obj]))
|
||||
[app.util.object :as obj]
|
||||
[app.main.ui.shapes.gradients :refer [gradient]]
|
||||
|
||||
[cuerdas.core :as str]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.common.geom.point :as gpt]))
|
||||
|
||||
(mf/defc rect-shape
|
||||
{::mf/wrap-props false}
|
||||
|
@ -21,7 +26,10 @@
|
|||
(let [shape (unchecked-get props "shape")
|
||||
{:keys [id x y width height]} shape
|
||||
transform (geom/transform-matrix shape)
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
|
||||
gradient-id (when (:fill-color-gradient shape) (str (uuid/next)))
|
||||
|
||||
props (-> (attrs/extract-style-attrs shape gradient-id)
|
||||
(obj/merge!
|
||||
#js {:x x
|
||||
:y y
|
||||
|
@ -30,7 +38,12 @@
|
|||
:width width
|
||||
:height height}))]
|
||||
|
||||
[:& shape-custom-stroke {:shape shape
|
||||
:base-props props
|
||||
:elem-name "rect"}]))
|
||||
|
||||
[:*
|
||||
(when gradient-id
|
||||
[:& gradient {:id gradient-id
|
||||
:shape shape
|
||||
:gradient (:fill-color-gradient shape)}])
|
||||
[:& shape-custom-stroke {:shape shape
|
||||
:base-props props
|
||||
:elem-name "rect"}]]))
|
||||
|
|
290
frontend/src/app/main/ui/workspace/gradients.cljs
Normal file
290
frontend/src/app/main/ui/workspace/gradients.cljs
Normal file
|
@ -0,0 +1,290 @@
|
|||
;; 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 app.main.ui.workspace.gradients
|
||||
"Gradients handlers and renders"
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[beicon.core :as rx]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
[app.common.math :as mth]
|
||||
[app.util.dom :as dom]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.matrix :as gmt]))
|
||||
|
||||
(def gradient-line-stroke-width 2)
|
||||
(def gradient-line-stroke-color "white")
|
||||
(def gradient-square-width 15)
|
||||
(def gradient-square-radius 2)
|
||||
(def gradient-square-stroke-width 2)
|
||||
(def gradient-width-handler-radius 5)
|
||||
(def gradient-width-handler-color "white")
|
||||
(def gradient-square-stroke-color "white")
|
||||
(def gradient-square-stroke-color-selected "#1FDEA7")
|
||||
|
||||
(mf/defc shadow [{:keys [id x y width height offset]}]
|
||||
[:filter {:id id
|
||||
:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:filterUnits "userSpaceOnUse"
|
||||
:color-interpolation-filters "sRGB"}
|
||||
[:feFlood {:flood-opacity "0" :result "BackgroundImageFix"}]
|
||||
[:feColorMatrix {:in "SourceAlpha" :type "matrix" :values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"}]
|
||||
[:feOffset {:dy offset}]
|
||||
[:feGaussianBlur {:stdDeviation "1"}]
|
||||
[:feColorMatrix {:type "matrix" :values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"}]
|
||||
[:feBlend {:mode "normal" :in2 "BackgroundImageFix" :result id}]
|
||||
[:feBlend {:mode "normal" :in "SourceGraphic" :in2 id :result "shape"}]])
|
||||
|
||||
(mf/defc gradient-line-drop-shadow-filter [{:keys [id zoom from-p to-p]}]
|
||||
[:& shadow
|
||||
{:id id
|
||||
:x (min (- (:x from-p) (/ 2 zoom))
|
||||
(- (:x to-p) (/ 2 zoom)))
|
||||
:y (min (- (:y from-p) (/ 2 zoom))
|
||||
(- (:y to-p) (/ 2 zoom)))
|
||||
:width (+ (mth/abs (- (:x to-p) (:x from-p))) (/ 4 zoom))
|
||||
:height (+ (mth/abs (- (:y to-p) (:y from-p))) (/ 4 zoom))
|
||||
:offset (/ 2 zoom)}])
|
||||
|
||||
|
||||
(mf/defc gradient-square-drop-shadow-filter [{:keys [id zoom point]}]
|
||||
[:& shadow
|
||||
{:id id
|
||||
:x (- (:x point) (/ gradient-square-width zoom 2) 2)
|
||||
:y (- (:y point) (/ gradient-square-width zoom 2) 2)
|
||||
:width (+ (/ gradient-square-width zoom) (/ 2 zoom) 4)
|
||||
:height (+ (/ gradient-square-width zoom) (/ 2 zoom) 4)
|
||||
:offset (/ 2 zoom)}])
|
||||
|
||||
(mf/defc gradient-width-handler-shadow-filter [{:keys [id zoom point]}]
|
||||
[:& shadow
|
||||
{:id id
|
||||
:x (- (:x point) (/ gradient-width-handler-radius zoom) 2)
|
||||
:y (- (:y point) (/ gradient-width-handler-radius zoom) 2)
|
||||
:width (+ (/ (* 2 gradient-width-handler-radius) zoom) (/ 2 zoom) 4)
|
||||
:height (+ (/ (* 2 gradient-width-handler-radius) zoom) (/ 2 zoom) 4)
|
||||
:offset (/ 2 zoom)}])
|
||||
|
||||
(def default-gradient
|
||||
{:type :linear
|
||||
:start-x 0.5 :start-y 0.5
|
||||
:end-x 0.5 :end-y 1
|
||||
:width 1.0
|
||||
:stops [{:offset 0
|
||||
:color "#FF0000"
|
||||
:opacity 1}
|
||||
{:offset 1
|
||||
:color "#FF0000"
|
||||
:opacity 0.2}]})
|
||||
|
||||
(def checkboard "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAIAAAC0tAIdAAACvUlEQVQoFQGyAk39AeLi4gAAAAAAAB0dHQAAAAAAAOPj4wAAAAAAAB0dHQAAAAAAAOPj4wAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB////AAAAAAAA4+PjAAAAAAAAHR0dAAAAAAAA4+PjAAAAAAAAHR0dAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATj4+MAAAAAAAAdHR0AAAAAAADj4+MAAAAAAAAdHR0AAAAAAADj4+MAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjScaa0cU7nIAAAAASUVORK5CYII=")
|
||||
|
||||
(mf/defc gradient-color-handler
|
||||
[{:keys [filter-id zoom point color angle on-click on-mouse-down on-mouse-up]}]
|
||||
[:g {:filter (str/fmt "url(#%s)" filter-id)
|
||||
:transform (gmt/rotate-matrix angle point)}
|
||||
|
||||
[:image {:href checkboard
|
||||
:x (- (:x point) (/ gradient-square-width 2 zoom))
|
||||
:y (- (:y point) (/ gradient-square-width 2 zoom))
|
||||
:width (/ gradient-square-width zoom)
|
||||
:height (/ gradient-square-width zoom)}]
|
||||
|
||||
[:rect {:x (- (:x point) (/ gradient-square-width 2 zoom))
|
||||
:y (- (:y point) (/ gradient-square-width 2 zoom))
|
||||
:rx (/ gradient-square-radius zoom)
|
||||
:width (/ gradient-square-width zoom 2)
|
||||
:height (/ gradient-square-width zoom)
|
||||
:fill (:value color)
|
||||
:on-click (partial on-click :to-p)
|
||||
:on-mouse-down (partial on-mouse-down :to-p)
|
||||
:on-mouse-up (partial on-mouse-up :to-p)}]
|
||||
|
||||
[:rect {:x (- (:x point) (/ gradient-square-width 2 zoom))
|
||||
:y (- (:y point) (/ gradient-square-width 2 zoom))
|
||||
:rx (/ gradient-square-radius zoom)
|
||||
:width (/ gradient-square-width zoom)
|
||||
:height (/ gradient-square-width zoom)
|
||||
:stroke "white"
|
||||
:stroke-width (/ gradient-square-stroke-width zoom)
|
||||
:fill (:value color)
|
||||
:fill-opacity (:opacity color)
|
||||
:on-click on-click
|
||||
:on-mouse-down on-mouse-down
|
||||
:on-mouse-up on-mouse-up}]])
|
||||
|
||||
(mf/defc gradient-handler-transformed
|
||||
[{:keys [from-p to-p width-p from-color to-color zoom on-change-start on-change-finish on-change-width on-change-stop-color]}]
|
||||
(let [moving-point (mf/use-var nil)
|
||||
angle (+ 90 (gpt/angle from-p to-p))
|
||||
|
||||
on-click (fn [position event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event))
|
||||
|
||||
on-mouse-down (fn [position event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(reset! moving-point position))
|
||||
|
||||
on-mouse-up (fn [position event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(reset! moving-point nil))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps @moving-point from-p to-p width-p)
|
||||
(fn []
|
||||
(let [subs (->> st/stream
|
||||
(rx/filter ms/pointer-event?)
|
||||
(rx/filter #(= :viewport (:source %)))
|
||||
(rx/map :pt)
|
||||
(rx/subs #(case @moving-point
|
||||
:from-p (when on-change-start (on-change-start %))
|
||||
:to-p (when on-change-finish (on-change-finish %))
|
||||
:width-p (when on-change-width
|
||||
(let [width-v (gpt/unit (gpt/to-vec from-p width-p))
|
||||
distance (gpt/point-line-distance % from-p to-p)
|
||||
new-width-p (gpt/add
|
||||
from-p
|
||||
(gpt/multiply width-v (gpt/point distance)))]
|
||||
(on-change-width new-width-p)))
|
||||
nil)))]
|
||||
(fn [] (rx/dispose! subs)))))
|
||||
[:g.gradient-handlers
|
||||
[:defs
|
||||
[:& gradient-line-drop-shadow-filter {:id "gradient_line_drop_shadow" :from-p from-p :to-p to-p :zoom zoom}]
|
||||
[:& gradient-line-drop-shadow-filter {:id "gradient_widh_line_drop_shadow" :from-p from-p :to-p width-p :zoom zoom}]
|
||||
[:& gradient-square-drop-shadow-filter {:id "gradient_square_from_drop_shadow" :point from-p :zoom zoom}]
|
||||
[:& gradient-square-drop-shadow-filter {:id "gradient_square_to_drop_shadow" :point to-p :zoom zoom}]
|
||||
[:& gradient-width-handler-shadow-filter {:id "gradient_width_handler_drop_shadow" :point width-p :zoom zoom}]]
|
||||
|
||||
[:g {:filter "url(#gradient_line_drop_shadow)"}
|
||||
[:line {:x1 (:x from-p)
|
||||
:y1 (:y from-p)
|
||||
:x2 (:x to-p)
|
||||
:y2 (:y to-p)
|
||||
:stroke gradient-line-stroke-color
|
||||
:stroke-width (/ gradient-line-stroke-width zoom)}]]
|
||||
|
||||
(when width-p
|
||||
[:g {:filter "url(#gradient_widh_line_drop_shadow)"}
|
||||
[:line {:x1 (:x from-p)
|
||||
:y1 (:y from-p)
|
||||
:x2 (:x width-p)
|
||||
:y2 (:y width-p)
|
||||
:stroke gradient-line-stroke-color
|
||||
:stroke-width (/ gradient-line-stroke-width zoom)}]])
|
||||
|
||||
(when width-p
|
||||
[:g {:filter "url(#gradient_width_handler_drop_shadow)"}
|
||||
[:circle {:cx (:x width-p)
|
||||
:cy (:y width-p)
|
||||
:r (/ gradient-width-handler-radius zoom)
|
||||
:fill gradient-width-handler-color
|
||||
:on-mouse-down (partial on-mouse-down :width-p)
|
||||
:on-mouse-up (partial on-mouse-up :width-p)}]])
|
||||
|
||||
[:& gradient-color-handler
|
||||
{:filter-id "gradient_square_from_drop_shadow"
|
||||
:zoom zoom
|
||||
:point from-p
|
||||
:color from-color
|
||||
:angle angle
|
||||
:on-click (partial on-click :from-p)
|
||||
:on-mouse-down (partial on-mouse-down :from-p)
|
||||
:on-mouse-up (partial on-mouse-up :from-p)}]
|
||||
|
||||
[:& gradient-color-handler
|
||||
{:filter-id "gradient_square_to_drop_shadow"
|
||||
:zoom zoom
|
||||
:point to-p
|
||||
:color to-color
|
||||
:angle angle
|
||||
:on-click (partial on-click :to-p)
|
||||
:on-mouse-down (partial on-mouse-down :to-p)
|
||||
:on-mouse-up (partial on-mouse-up :to-p)}]]))
|
||||
|
||||
(mf/defc gradient-handlers
|
||||
[{:keys [shape zoom]}]
|
||||
(let [{:keys [x y width height] :as sr} (:selrect shape)
|
||||
|
||||
state (mf/use-state (:fill-color-gradient shape default-gradient))
|
||||
|
||||
[{start-color :color start-opacity :opacity}
|
||||
{end-color :color end-opacity :opacity}] (:stops @state)
|
||||
|
||||
from-p (gpt/point (+ x (* width (:start-x @state)))
|
||||
(+ y (* height (:start-y @state))))
|
||||
|
||||
to-p (gpt/point (+ x (* width (:end-x @state)))
|
||||
(+ y (* height (:end-y @state))))
|
||||
|
||||
gradient-vec (gpt/to-vec from-p to-p)
|
||||
gradient-length (gpt/length gradient-vec)
|
||||
|
||||
width-v (-> gradient-vec
|
||||
(gpt/normal-left)
|
||||
(gpt/multiply (gpt/point (* (:width @state) (/ gradient-length (/ height 2) ))))
|
||||
(gpt/multiply (gpt/point (/ width 2))))
|
||||
|
||||
width-p (gpt/add from-p width-v)
|
||||
|
||||
on-change-start (fn [point]
|
||||
(let [start-x (/ (- (:x point) x) width)
|
||||
start-y (/ (- (:y point) y) height)]
|
||||
(swap! state assoc
|
||||
:start-x start-x
|
||||
:start-y start-y )))
|
||||
|
||||
on-change-finish (fn [point]
|
||||
(let [end-x (/ (- (:x point) x) width)
|
||||
end-y (/ (- (:y point) y) height)]
|
||||
(swap! state assoc
|
||||
:end-x end-x
|
||||
:end-y end-y)))
|
||||
|
||||
on-change-width (fn [point]
|
||||
(let [scale-factor-y (/ gradient-length (/ height 2))
|
||||
norm-dist (/ (gpt/distance point from-p)
|
||||
(* (/ width 2) scale-factor-y))]
|
||||
(swap! state assoc :width norm-dist)))
|
||||
|
||||
on-change-stop-color (fn [offset color opacity] (println "change-color"))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps shape)
|
||||
(fn []
|
||||
(reset! state (:fill-color-gradient shape default-gradient))))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps @state)
|
||||
(fn []
|
||||
(when (not= (:fill-color-gradient shape) @state)
|
||||
(st/emit! (dwc/update-shapes
|
||||
[(:id shape)]
|
||||
#(assoc % :fill-color-gradient @state))))))
|
||||
|
||||
[:& gradient-handler-transformed
|
||||
{:from-p from-p
|
||||
:to-p to-p
|
||||
:width-p (when (= :radial (:type @state)) width-p)
|
||||
:from-color {:value start-color :opacity start-opacity}
|
||||
:to-color {:value end-color :opacity end-opacity}
|
||||
:zoom zoom
|
||||
:on-change-start on-change-start
|
||||
:on-change-finish on-change-finish
|
||||
:on-change-width on-change-width
|
||||
:on-change-stop-color on-change-stop-color}]))
|
|
@ -16,18 +16,20 @@
|
|||
[rumext.alpha :as mf]
|
||||
[rumext.util :refer [map->obj]]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
[app.main.ui.cursors :as cur]
|
||||
[app.common.math :as mth]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.object :as obj]
|
||||
[app.common.geom.shapes :as geom]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.util.debug :refer [debug?]]
|
||||
[app.main.ui.workspace.shapes.outline :refer [outline]]))
|
||||
|
||||
[app.main.ui.workspace.shapes.outline :refer [outline]]
|
||||
[app.main.ui.workspace.gradients :refer [gradient-handlers]]))
|
||||
|
||||
(def rotation-handler-size 25)
|
||||
(def resize-point-radius 4)
|
||||
|
@ -168,7 +170,6 @@
|
|||
:cursor (if (#{:left :right} position)
|
||||
(cur/resize-ew rotation)
|
||||
(cur/resize-ns rotation)) }}]))
|
||||
|
||||
(mf/defc controls
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
|
@ -180,7 +181,9 @@
|
|||
current-transform (mf/deref refs/current-transform)
|
||||
|
||||
selrect (geom/shape->rect-shape shape)
|
||||
transform (geom/transform-matrix shape)]
|
||||
transform (geom/transform-matrix shape)
|
||||
|
||||
tr-shape (geom/transform-shape shape)]
|
||||
|
||||
(when (not (#{:move :rotate} current-transform))
|
||||
[:g.controls
|
||||
|
@ -190,8 +193,7 @@
|
|||
:transform transform
|
||||
:zoom zoom
|
||||
:color color}]
|
||||
[:& outline {:shape (geom/transform-shape shape)
|
||||
:color color}]
|
||||
[:& outline {:shape tr-shape :color color}]
|
||||
|
||||
;; Handlers
|
||||
(for [{:keys [type position props]} (handlers-for-selection selrect)]
|
||||
|
@ -208,7 +210,11 @@
|
|||
(case type
|
||||
:rotation (when (not= :frame (:type shape)) [:> rotation-handler props])
|
||||
:resize-point [:> resize-point-handler props]
|
||||
:resize-side [:> resize-side-handler props])))])))
|
||||
:resize-side [:> resize-side-handler props])))
|
||||
|
||||
(when (= :rect (:type shape))
|
||||
[:& gradient-handlers {:shape tr-shape
|
||||
:zoom zoom}])])))
|
||||
|
||||
;; --- Selection Handlers (Component)
|
||||
(mf/defc path-edition-selection-handlers
|
||||
|
|
Loading…
Add table
Reference in a new issue