diff --git a/src/uxbox/svg.cljs b/src/uxbox/svg.cljs index a74a1ed81c..9498fd53cc 100644 --- a/src/uxbox/svg.cljs +++ b/src/uxbox/svg.cljs @@ -1,17 +1,78 @@ -(ns uxbox.svg) +(ns uxbox.svg + "A svg related utils." + (:require [cuerdas.core :as str] + [uxbox.matrix :as mtx] + [uxbox.math :as mth] + [uxbox.util.data :refer (without-keys)])) -(defn translate - [x y] - (str "translate(" x "," y ")")) +(defn translate-matrix + ([x] + (translate-matrix x x)) + ([x y] + (mtx/matrix [[1 0 x] + [0 1 y] + [0 0 1]]))) -(defn rotate - [d] - (str "rotate(" d ")")) +(defn scale-matrix + ([w] + (scale-matrix w w)) + ([w h] + (mtx/matrix [[w 0 0] + [0 h 0] + [0 0 1]]))) -(defn transform - [{:keys [center] :as opts}] - (let [r (get opts :rotate 0) - {:keys [x y]} center] - (str (translate x y) - (rotate r) - (translate (- x) (- y))))) +(defn rotation-matrix + [^number degrees] + (let [v1 (mth/cos (mth/radiants degrees)) + v2 (mth/sin (mth/radiants degrees)) + v3 (mth/neg v2)] + (mtx/matrix [[v1 v3 0] + [v2 v1 0] + [0 0 1]]))) + +(defn apply-translate + [{:keys [x y]}] + (translate-matrix x y)) + +(defn apply-scale + [{:keys [width height view-box]}] + (if (and width height) + (let [orig-width (nth view-box 2) + orig-height (nth view-box 3) + scale-x (/ width orig-width) + scale-y (/ height orig-height)] + (scale-matrix scale-x scale-y)) + (scale-matrix 1 1))) + +(defn apply-rotation + [{:keys [rotation x y width height view-box] :or {rotation 0}}] + (let [width (nth view-box 2) + height (nth view-box 3) + x (- width (/ width 2)) + y (- height (/ height 2))] + (mtx/multiply (translate-matrix x y) + (rotation-matrix rotation) + (translate-matrix (- x) + (- y))))) + +(def interpret-attrs (juxt apply-translate + apply-scale + apply-rotation)) + +(defn calculate-transform + [attrs] + (let [result (->> (interpret-attrs attrs) + (apply mtx/multiply) + (deref) + (take 6) + (flatten))] + (->> (map #(nth result %) [0 3 1 4 2 5]) + (str/join ",") + (str/format "matrix(%s)")))) + +(defn apply-transform + [attrs] + (let [transform (calculate-transform attrs)] + (-> attrs + (without-keys [:rotation :width :height :x :y :view-box]) + (assoc :transform transform))))