mirror of
https://github.com/penpot/penpot.git
synced 2025-02-12 18:18:24 -05:00
🎉 Refactor, performance improvements
This commit is contained in:
parent
726cdb9a27
commit
e737ec0311
7 changed files with 165 additions and 98 deletions
|
@ -18,12 +18,12 @@ goog.scope(function() {
|
|||
const self = app.common.uuid_impl;
|
||||
|
||||
const fill = (() => {
|
||||
if (typeof window === "object") {
|
||||
if (typeof window === "object" && typeof window.crypto !== "undefined") {
|
||||
return (buf) => {
|
||||
window.crypto.getRandomValues(buf);
|
||||
return buf;
|
||||
};
|
||||
} else if (typeof self === "object") {
|
||||
} else if (typeof self === "object" && typeof self.crypto !== "undefined") {
|
||||
return (buf) => {
|
||||
self.crypto.getRandomValues(buf);
|
||||
return buf;
|
||||
|
|
|
@ -10,13 +10,26 @@
|
|||
(ns app.main.data.fetch
|
||||
(:require
|
||||
[promesa.core :as p]
|
||||
[app.util.object :as obj]))
|
||||
[potok.core :as ptk]
|
||||
[okulary.core :as l]
|
||||
[app.util.object :as obj]
|
||||
[app.main.store :as st]))
|
||||
|
||||
(defn pending-ref []
|
||||
(l/derived ::to-fetch st/state))
|
||||
|
||||
(defn add [to-fetch id]
|
||||
(let [to-fetch (or to-fetch (hash-set))]
|
||||
(conj to-fetch id)))
|
||||
|
||||
(defn fetch-as-data-uri [url]
|
||||
(-> (js/fetch url)
|
||||
(p/then (fn [res] (.blob res)))
|
||||
(p/then (fn [blob]
|
||||
(let [reader (js/FileReader.)]
|
||||
(p/create (fn [resolve reject]
|
||||
(obj/set! reader "onload" #(resolve [url (.-result reader)]))
|
||||
(.readAsDataURL reader blob))))))))
|
||||
(let [id (random-uuid)]
|
||||
(st/emit! (fn [state] (update state ::to-fetch add id)))
|
||||
(-> (js/fetch url)
|
||||
(p/then (fn [res] (.blob res)))
|
||||
(p/then (fn [blob]
|
||||
(let [reader (js/FileReader.)]
|
||||
(p/create (fn [resolve reject]
|
||||
(obj/set! reader "onload" #(resolve [url (.-result reader)]))
|
||||
(.readAsDataURL reader blob))))))
|
||||
(p/finally #(st/emit! (fn [state] (update state ::to-fetch disj id)))))))
|
||||
|
|
14
frontend/src/app/main/ui/context.cljs
Normal file
14
frontend/src/app/main/ui/context.cljs
Normal file
|
@ -0,0 +1,14 @@
|
|||
;; 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.context
|
||||
(:require
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(def embed-ctx (mf/create-context false))
|
|
@ -14,6 +14,7 @@
|
|||
[app.common.geom.shapes :as geom]
|
||||
[app.main.ui.shapes.attrs :as attrs]
|
||||
[app.util.object :as obj]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.main.data.fetch :as df]
|
||||
[promesa.core :as p]))
|
||||
|
||||
|
@ -24,13 +25,15 @@
|
|||
(let [shape (unchecked-get props "shape")
|
||||
{:keys [id x y width height rotation metadata]} shape
|
||||
uri (cfg/resolve-media-path (:path metadata))
|
||||
data-uri (mf/use-state nil)]
|
||||
embed-resources? (mf/use-ctx muc/embed-ctx)
|
||||
data-uri (mf/use-state (when (not embed-resources?) uri))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps shape)
|
||||
(mf/deps uri)
|
||||
(fn []
|
||||
(-> (df/fetch-as-data-uri uri)
|
||||
(p/then #(reset! data-uri (second %))))))
|
||||
(if embed-resources?
|
||||
(-> (df/fetch-as-data-uri uri)
|
||||
(p/then #(reset! data-uri (second %)))))))
|
||||
|
||||
(let [transform (geom/transform-matrix shape)
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
|
@ -49,7 +52,4 @@
|
|||
:stroke "#000000"})]
|
||||
[:> "image" (obj/merge!
|
||||
props
|
||||
#js {:xlinkHref @data-uri})]))
|
||||
|
||||
|
||||
))
|
||||
#js {:href @data-uri})]))))
|
||||
|
|
|
@ -6,16 +6,17 @@
|
|||
|
||||
(ns app.main.ui.shapes.text
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[promesa.core :as p]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]
|
||||
[app.main.data.fetch :as df]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as geom]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.util.object :as obj]
|
||||
[clojure.set :as set]))
|
||||
[app.util.object :as obj]))
|
||||
|
||||
;; --- Text Editor Rendering
|
||||
|
||||
|
@ -114,11 +115,12 @@
|
|||
([node] (render-text-node 0 node))
|
||||
([index {:keys [type text children] :as node}]
|
||||
(mf/html
|
||||
(let [embeded-fonts (mf/use-state nil)]
|
||||
(let [embed-resources? (mf/use-ctx muc/embed-ctx)
|
||||
embeded-fonts (mf/use-state nil)]
|
||||
(mf/use-effect
|
||||
(mf/deps node)
|
||||
(fn []
|
||||
(when (= type "root")
|
||||
(when (and embed-resources? (= type "root"))
|
||||
(let [font-to-embed (get-all-fonts node)
|
||||
embeded (map embed-font font-to-embed)]
|
||||
(-> (p/all embeded)
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
[app.common.uuid :refer [uuid]]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.colors :as dwc]
|
||||
#_[app.main.ui.modal :as modal]
|
||||
[app.main.ui.modal :as modal]
|
||||
[okulary.core :as l]
|
||||
[app.main.refs :as refs]
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.drawing :as dd]
|
||||
[app.main.data.colors :as dwc]
|
||||
[app.main.data.fetch :as mdf]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
|
@ -42,10 +43,12 @@
|
|||
[app.util.dom :as dom]
|
||||
[app.util.dom.dnd :as dnd]
|
||||
[app.util.object :as obj]
|
||||
[app.main.ui.context :as muc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.util.perf :as perf]
|
||||
[app.common.uuid :as uuid])
|
||||
[app.common.uuid :as uuid]
|
||||
[app.util.timers :as timers])
|
||||
(:import goog.events.EventType))
|
||||
|
||||
;; --- Coordinates Widget
|
||||
|
@ -161,6 +164,108 @@
|
|||
:selected selected
|
||||
:hover hover}]]))
|
||||
|
||||
(defn format-viewbox [vbox]
|
||||
(str/join " " [(+ (:x vbox 0) (:left-offset vbox 0))
|
||||
(:y vbox 0)
|
||||
(:width vbox 0)
|
||||
(:height vbox 0)]))
|
||||
|
||||
(mf/defc pixel-picker-overlay
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [vport (unchecked-get props "vport")
|
||||
vbox (unchecked-get props "vbox")
|
||||
viewport-ref (unchecked-get props "viewport-ref")
|
||||
options (unchecked-get props "options")
|
||||
svg-ref (mf/use-ref nil)
|
||||
canvas-ref (mf/use-ref nil)
|
||||
fetch-pending (mf/deref (mdf/pending-ref))
|
||||
|
||||
on-mouse-move-picker
|
||||
(fn [event]
|
||||
(when-let [zoom-view-node (.getElementById js/document "picker-detail")]
|
||||
(let [{brx :left bry :top} (dom/get-bounding-rect (mf/ref-val viewport-ref))
|
||||
x (- (.-clientX event) brx)
|
||||
y (- (.-clientY event) bry)
|
||||
|
||||
zoom-context (.getContext zoom-view-node "2d")
|
||||
canvas-node (mf/ref-val canvas-ref)
|
||||
canvas-context (.getContext canvas-node "2d")
|
||||
pixel-data (.getImageData canvas-context x y 1 1)
|
||||
rgba (.-data pixel-data)
|
||||
r (obj/get rgba 0)
|
||||
g (obj/get rgba 1)
|
||||
b (obj/get rgba 2)
|
||||
a (obj/get rgba 3)
|
||||
|
||||
area-data (.getImageData canvas-context (- x 25) (- y 20) 50 40)]
|
||||
|
||||
(-> (js/createImageBitmap area-data)
|
||||
(p/then (fn [image]
|
||||
;; Draw area
|
||||
(obj/set! zoom-context "imageSmoothingEnabled" false)
|
||||
(.drawImage zoom-context image 0 0 200 160))))
|
||||
(st/emit! (dwc/pick-color [r g b a])))))
|
||||
|
||||
on-mouse-down-picker
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dwc/pick-color-select true (kbd/shift? event))))
|
||||
|
||||
on-mouse-up-picker
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dwc/stop-picker))
|
||||
(modal/disallow-click-outside!))]
|
||||
|
||||
(mf/use-effect
|
||||
;; Everytime we finish retrieving a new URL we redraw the canvas
|
||||
;; so even if we're not finished the user can start to pick basic
|
||||
;; shapes
|
||||
(mf/deps fetch-pending)
|
||||
(fn []
|
||||
(try
|
||||
(timers/raf
|
||||
#(let [svg-node (mf/ref-val svg-ref)
|
||||
canvas-node (mf/ref-val canvas-ref)
|
||||
canvas-context (.getContext canvas-node "2d")
|
||||
xml (.serializeToString (js/XMLSerializer.) svg-node)
|
||||
content (str "data:image/svg+xml;base64," (js/btoa xml))
|
||||
img (js/Image.)]
|
||||
(obj/set! img "onload"
|
||||
(fn []
|
||||
(.drawImage canvas-context img 0 0)))
|
||||
(obj/set! img "src" content)))
|
||||
(catch :default e (.error js/console e)))))
|
||||
|
||||
[:*
|
||||
[:div.overlay
|
||||
{:style {:position "absolute"
|
||||
:top 0
|
||||
:left 0
|
||||
:width "100%"
|
||||
:height "100%"
|
||||
:cursor cur/picker}
|
||||
:on-mouse-down on-mouse-down-picker
|
||||
:on-mouse-up on-mouse-up-picker
|
||||
:on-mouse-move on-mouse-move-picker}]
|
||||
[:canvas {:ref canvas-ref
|
||||
:width (:width vport 0)
|
||||
:height (:height vport 0)
|
||||
:style {:display "none"}}]
|
||||
[:& (mf/provider muc/embed-ctx) {:value true}
|
||||
[:svg.viewport
|
||||
{:ref svg-ref
|
||||
:preserveAspectRatio "xMidYMid meet"
|
||||
:width (:width vport 0)
|
||||
:height (:height vport 0)
|
||||
:view-box (format-viewbox vbox)
|
||||
:style {:display "none"
|
||||
:background-color (get options :background "#E8E9EA")}}
|
||||
[:& frames]]]]))
|
||||
|
||||
(mf/defc viewport
|
||||
[{:keys [page-id page local layout] :as props}]
|
||||
(let [{:keys [options-mode
|
||||
|
@ -176,7 +281,6 @@
|
|||
|
||||
file (mf/deref refs/workspace-file)
|
||||
viewport-ref (mf/use-ref nil)
|
||||
canvas-ref (mf/use-ref nil)
|
||||
zoom-view-ref (mf/use-ref nil)
|
||||
last-position (mf/use-var nil)
|
||||
drawing (mf/deref refs/workspace-drawing)
|
||||
|
@ -418,46 +522,7 @@
|
|||
prnt (dom/get-parent node)]
|
||||
(st/emit! (dw/update-viewport-size (dom/get-client-size prnt)))))
|
||||
|
||||
options (mf/deref refs/workspace-page-options)
|
||||
|
||||
on-mouse-move-picker
|
||||
(fn [event]
|
||||
(when-let [zoom-view-node (.getElementById js/document "picker-detail")]
|
||||
(let [{brx :left bry :top} (dom/get-bounding-rect (mf/ref-val viewport-ref))
|
||||
x (- (.-clientX event) brx)
|
||||
y (- (.-clientY event) bry)
|
||||
|
||||
zoom-context (.getContext zoom-view-node "2d")
|
||||
canvas-node (mf/ref-val canvas-ref)
|
||||
canvas-context (.getContext canvas-node "2d")
|
||||
pixel-data (.getImageData canvas-context x y 1 1)
|
||||
rgba (.-data pixel-data)
|
||||
r (obj/get rgba 0)
|
||||
g (obj/get rgba 1)
|
||||
b (obj/get rgba 2)
|
||||
a (obj/get rgba 3)
|
||||
|
||||
area-data (.getImageData canvas-context (- x 25) (- y 20) 50 40)]
|
||||
|
||||
(-> (js/createImageBitmap area-data)
|
||||
(p/then (fn [image]
|
||||
;; Draw area
|
||||
(obj/set! zoom-context "imageSmoothingEnabled" false)
|
||||
(.drawImage zoom-context image 0 0 200 160))))
|
||||
(st/emit! (dwc/pick-color [r g b a])))))
|
||||
|
||||
on-mouse-down-picker
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dwc/pick-color-select true (kbd/shift? event))))
|
||||
|
||||
on-mouse-up-picker
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dwc/stop-picker))
|
||||
(modal/disallow-click-outside!))]
|
||||
options (mf/deref refs/workspace-page-options)]
|
||||
|
||||
(mf/use-layout-effect
|
||||
(fn []
|
||||
|
@ -481,44 +546,18 @@
|
|||
|
||||
(mf/use-layout-effect (mf/deps layout) on-resize)
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps props)
|
||||
(fn []
|
||||
(when picking-color?
|
||||
(try
|
||||
(let [svg-node (mf/ref-val viewport-ref)
|
||||
canvas-node (mf/ref-val canvas-ref)
|
||||
canvas-context (.getContext canvas-node "2d")
|
||||
xml (.serializeToString (js/XMLSerializer.) svg-node)
|
||||
content (str "data:image/svg+xml;base64," (js/btoa xml))
|
||||
img (js/Image.)]
|
||||
(obj/set! img "onload"
|
||||
(fn []
|
||||
(.drawImage canvas-context img 0 0)))
|
||||
(obj/set! img "src" content))
|
||||
(catch :default e (.error js/console e))))))
|
||||
|
||||
[:*
|
||||
|
||||
(when picking-color?
|
||||
[:canvas {:ref canvas-ref
|
||||
:width (:width vport 0)
|
||||
:height (:height vport 0)
|
||||
:on-mouse-down on-mouse-down-picker
|
||||
:on-mouse-up on-mouse-up-picker
|
||||
:on-mouse-move on-mouse-move-picker
|
||||
:style {:position "absolute"
|
||||
:top 0
|
||||
:left 0
|
||||
:cursor cur/picker}}])
|
||||
[:& pixel-picker-overlay {:vport vport
|
||||
:vbox vbox
|
||||
:viewport-ref viewport-ref
|
||||
:options options}])
|
||||
|
||||
[:svg.viewport
|
||||
{:preserveAspectRatio "xMidYMid meet"
|
||||
:width (:width vport 0)
|
||||
:height (:height vport 0)
|
||||
:view-box (str/join " " [(+ (:x vbox 0) (:left-offset vbox 0))
|
||||
(:y vbox 0)
|
||||
(:width vbox 0)
|
||||
(:height vbox 0)])
|
||||
:view-box (format-viewbox vbox)
|
||||
:ref viewport-ref
|
||||
:class (when drawing-tool "drawing")
|
||||
:style {:cursor (cond
|
||||
|
|
Loading…
Add table
Reference in a new issue