mirror of
https://github.com/penpot/penpot.git
synced 2025-07-31 09:48:33 +02:00
116 lines
4.7 KiB
Clojure
116 lines
4.7 KiB
Clojure
;; 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) KALEIDOS INC
|
|
|
|
(ns app.util.text-svg-position
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.data.macros :as dm]
|
|
[app.common.transit :as transit]
|
|
[app.main.fonts :as fonts]
|
|
[app.util.dom :as dom]
|
|
[app.util.text-position-data :as tpd]
|
|
[promesa.core :as p]))
|
|
|
|
(defn parse-text-nodes
|
|
"Given a text node retrieves the rectangles for everyone of its paragraphs and its text."
|
|
[parent-node direction text-node text-align]
|
|
|
|
(letfn [(parse-entry [^js entry]
|
|
(when (some? (.-position entry))
|
|
{:node (.-node entry)
|
|
:position (dom/bounding-rect->rect (.-position entry))
|
|
:text (.-text entry)
|
|
:direction direction}))]
|
|
(into
|
|
[]
|
|
(keep parse-entry)
|
|
(tpd/parse-text-nodes parent-node text-node text-align))))
|
|
|
|
(def load-promises (atom {}))
|
|
|
|
(defn load-font
|
|
[font]
|
|
(if (contains? @load-promises font)
|
|
(get @load-promises font)
|
|
(let [load-promise (dom/load-font font)]
|
|
(swap! load-promises assoc font load-promise)
|
|
load-promise)))
|
|
|
|
(defn resolve-font
|
|
[^js node]
|
|
|
|
(let [styles (js/getComputedStyle node)
|
|
font (.getPropertyValue styles "font")
|
|
font (if (or (not font) (empty? font))
|
|
;; Firefox 95 won't return the font correctly.
|
|
;; We can get the font shorthand with the font-size + font-family
|
|
(dm/str (.getPropertyValue styles "font-size")
|
|
" "
|
|
(.getPropertyValue styles "font-family"))
|
|
font)
|
|
|
|
font-id (.getPropertyValue styles "--font-id")]
|
|
|
|
(-> (fonts/ensure-loaded! font-id)
|
|
(p/then #(when (not (dom/check-font? font))
|
|
(load-font font)))
|
|
(p/catch #(.error js/console (dm/str "Cannot load font" font-id) %)))))
|
|
|
|
(defn- calc-text-node-positions
|
|
[shape-id]
|
|
|
|
(when (some? shape-id)
|
|
(let [text-nodes (-> (dom/query (dm/fmt "#html-text-node-%" shape-id))
|
|
(dom/query-all ".text-node"))
|
|
load-fonts (->> text-nodes (map resolve-font))
|
|
|
|
process-text-node
|
|
(fn [parent-node]
|
|
(let [root (dom/get-parent-with-selector parent-node ".text-node-html")
|
|
paragraph (dom/get-parent-with-selector parent-node ".paragraph")
|
|
shape-x (-> (dom/get-attribute root "data-x") d/parse-double)
|
|
shape-y (-> (dom/get-attribute root "data-y") d/parse-double)
|
|
direction (.-direction (js/getComputedStyle parent-node))
|
|
text-align (.-textAlign (js/getComputedStyle paragraph))]
|
|
|
|
(->> (.-childNodes parent-node)
|
|
(mapcat #(parse-text-nodes parent-node direction % text-align))
|
|
(mapv #(-> %
|
|
(update-in [:position :x] + shape-x)
|
|
(update-in [:position :y] + shape-y))))))]
|
|
(-> (p/all load-fonts)
|
|
(p/then
|
|
(fn []
|
|
(->> text-nodes (mapcat process-text-node))))))))
|
|
|
|
(defn calc-position-data
|
|
[shape-id]
|
|
(when (some? shape-id)
|
|
(p/let [text-data (calc-text-node-positions shape-id)]
|
|
(when (d/not-empty? text-data)
|
|
(->> text-data
|
|
(mapv (fn [{:keys [node position text direction]}]
|
|
(let [{:keys [x y width height]} position
|
|
styles (js/getComputedStyle ^js node)
|
|
get (fn [prop]
|
|
(let [value (.getPropertyValue styles prop)]
|
|
(when (and value (not= value ""))
|
|
value)))]
|
|
(d/without-nils
|
|
{:x x
|
|
:y (+ y height)
|
|
:width width
|
|
:height height
|
|
:direction direction
|
|
:font-family (str (get "font-family"))
|
|
:font-size (str (get "font-size"))
|
|
:font-weight (str (get "font-weight"))
|
|
:text-transform (str (get "text-transform"))
|
|
:text-decoration (str (get "text-decoration"))
|
|
:letter-spacing (str (get "letter-spacing"))
|
|
:font-style (str (get "font-style"))
|
|
:fills (transit/decode-str (get "--fills"))
|
|
:text text})))))))))
|