diff --git a/common/src/app/common/svg/path.cljc b/common/src/app/common/svg/path.cljc index 5951002a184..ac89be9d066 100644 --- a/common/src/app/common/svg/path.cljc +++ b/common/src/app/common/svg/path.cljc @@ -40,3 +40,76 @@ (map (fn [segment] (.toPersistentMap ^js segment))) (parser/parse path-str))))) + +#?(:cljs + (defn content->buffer + "Converts the path content into binary format." + [content] + (let [total (count content) + ssize 28 + buffer (new js/ArrayBuffer (* total ssize)) + dview (new js/DataView buffer)] + (loop [index 0] + (when (< index total) + (let [segment (nth content index) + offset (* index ssize)] + (case (:command segment) + :move-to + (let [{:keys [x y]} (:params segment)] + (.setInt16 dview (+ offset 0) 1) + (.setFloat32 dview (+ offset 20) x) + (.setFloat32 dview (+ offset 24) y)) + :line-to + (let [{:keys [x y]} (:params segment)] + (.setInt16 dview (+ offset 0) 2) + (.setFloat32 dview (+ offset 20) x) + (.setFloat32 dview (+ offset 24) y)) + :curve-to + (let [{:keys [c1x c1y c2x c2y x y]} (:params segment)] + (.setInt16 dview (+ offset 0) 3) + (.setFloat32 dview (+ offset 4) c1x) + (.setFloat32 dview (+ offset 8) c1y) + (.setFloat32 dview (+ offset 12) c2x) + (.setFloat32 dview (+ offset 16) c2y) + (.setFloat32 dview (+ offset 20) x) + (.setFloat32 dview (+ offset 24) y)) + + :close-path + (.setInt16 dview (+ offset 0) 4)) + (recur (inc index))))) + buffer))) + +#?(:cljs + (defn buffer->content + "Converts the a buffer to a path content vector" + [buffer] + (assert (instance? js/ArrayBuffer buffer) "expected ArrayBuffer instance") + (let [ssize 28 + total (/ (.-byteLength buffer) ssize) + dview (new js/DataView buffer)] + (loop [index 0 + result []] + (if (< index total) + (let [offset (* index ssize) + type (.getInt16 dview (+ offset 0)) + command (case type + 1 :move-to + 2 :line-to + 3 :curve-to + 4 :close-path) + params (case type + 1 {:x (.getFloat32 dview (+ offset 20)) + :y (.getFloat32 dview (+ offset 24))} + 2 {:x (.getFloat32 dview (+ offset 20)) + :y (.getFloat32 dview (+ offset 24))} + 3 {:c1x (.getFloat32 dview (+ offset 4)) + :c1y (.getFloat32 dview (+ offset 8)) + :c2x (.getFloat32 dview (+ offset 12)) + :c2y (.getFloat32 dview (+ offset 16)) + :x (.getFloat32 dview (+ offset 20)) + :y (.getFloat32 dview (+ offset 24))} + 4 {})] + (recur (inc index) + (conj result {:command command + :params params}))) + result))))) diff --git a/frontend/src/app/render_wasm/shape.cljs b/frontend/src/app/render_wasm/shape.cljs index daaaedb6359..5082fbf3d51 100644 --- a/frontend/src/app/render_wasm/shape.cljs +++ b/frontend/src/app/render_wasm/shape.cljs @@ -8,6 +8,7 @@ (:require [app.common.transit :as t] [app.common.types.shape :as shape] + ;; [app.common.svg.path :as path] [app.render-wasm.api :as api] [clojure.core :as c] [cuerdas.core :as str])) @@ -16,7 +17,11 @@ (declare ^:private impl-conj) (declare ^:private impl-dissoc) -(deftype ShapeProxy [delegate] +(defn map-entry + [k v] + (cljs.core/MapEntry. k v nil)) + +(deftype ShapeProxy [id type delegate] Object (toString [coll] (str "{" (str/join ", " (for [[k v] coll] (str k " " v))) "}")) @@ -29,7 +34,7 @@ IWithMeta (-with-meta [_ meta] - (ShapeProxy. (with-meta delegate meta))) + (ShapeProxy. id type (with-meta delegate meta))) IMeta (-meta [_] (meta delegate)) @@ -49,7 +54,9 @@ ISeqable (-seq [_] - (c/-seq delegate)) + (cons (map-entry :id id) + (cons (map-entry :type type) + (c/-seq delegate)))) ICounted (-count [_] @@ -60,18 +67,28 @@ (-lookup coll k nil)) (-lookup [_ k not-found] - (c/-lookup delegate k not-found)) + (case k + :id id + :type type + (c/-lookup delegate k not-found))) IFind (-find [_ k] - (c/-find delegate k)) + (case k + :id + (map-entry :id id) + :type + (map-entry :type type) + (c/-find delegate k))) IAssociative (-assoc [coll k v] (impl-assoc coll k v)) (-contains-key? [_ k] - (contains? delegate k)) + (or (= k :id) + (= k :type) + (contains? delegate k))) IMap (-dissoc [coll k] @@ -79,7 +96,7 @@ IFn (-invoke [coll k] - (-lookup coll k)) + (-lookup coll k nil)) (-invoke [coll k not-found] (-lookup coll k not-found)) @@ -107,19 +124,44 @@ ;; is modified, we need to request ;; a new render. (api/request-render)) - (let [delegate (.-delegate ^ShapeProxy self) - delegate' (assoc delegate k v)] - (if (identical? delegate' delegate) - self - (ShapeProxy. delegate')))) + (case k + :id + (ShapeProxy. v + (.-type ^ShapeProxy self) + (.-delegate ^ShapeProxy self)) + :type + (ShapeProxy. (.-id ^ShapeProxy self) + v + (.-delegate ^ShapeProxy self)) + + (let [delegate (.-delegate ^ShapeProxy self) + delegate' (assoc delegate k v)] + (if (identical? delegate' delegate) + self + (ShapeProxy. (.-id ^ShapeProxy self) + (.-type ^ShapeProxy self) + delegate'))))) (defn- impl-dissoc [self k] - (let [delegate (.-delegate ^ShapeProxy self) - delegate' (dissoc delegate k)] - (if (identical? delegate delegate') - self - (ShapeProxy. delegate')))) + (case k + :id + (ShapeProxy. nil + (.-type ^ShapeProxy self) + (.-delegate ^ShapeProxy self)) + :type + (ShapeProxy. (.-id ^ShapeProxy self) + nil + (.-delegate ^ShapeProxy self)) + + :else + (let [delegate (.-delegate ^ShapeProxy self) + delegate' (dissoc delegate k)] + (if (identical? delegate delegate') + self + (ShapeProxy. (.-id ^ShapeProxy self) + (.-type ^ShapeProxy self) + delegate'))))) (defn- impl-conj [self entry] @@ -137,7 +179,9 @@ (defn create-shape "Instanciate a shape from a map" [attrs] - (ShapeProxy. attrs)) + (ShapeProxy. (:id attrs) + (:type attrs) + (dissoc attrs :id :type))) (t/add-handlers! ;; We only add a write handler, read handler uses the dynamic dispatch