SVG之transform

svg的形變和css的形變用的都是transform,並且屬性也幾乎沒差(是幾乎)。css

translate

transform="translate(x-value, y-value)"css3

簡單來講,就是偏移。沿x軸方向偏移x-value個單位長度,沿y軸方向偏移y-value個單位長度。svg

<symbol id="rect">
    <line x1="0" y1="0" x2="300" y2="0" stroke="grey"></line>
    <line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
    <rect x="20" y="20" width="50" height="50"></rect>
</symbol>
<use xlink:href="#rect" stroke="grey" fill="none"></use>
<use xlink:href="#rect" transform="translate(100,50)" stroke="black" fill="none"></use>

clipboard.png

複雜來講,svg處理偏移的時候,實際上是對元素所在的座標系作總體偏移。那上面例子來講,#rect內的全部元素在偏移後,座標數值沒有變化,兩條表明座標軸線的直線起始位置仍是(0,0)。只是這個(0,0)所在的座標系已經被偏移到了原座標系的(100,50)位置。wordpress

scale

transform="scale(x-value, y-value)"spa

簡單來講,就是縮放。x軸方向上的長度變爲原來的x-value倍,y軸方向上的長度變爲原來的y-value倍。容許只有一個參數scale(n),表示x和y軸方向上的長度同時變爲原來的n倍。code

<line x1="0" y1="0" x2="150" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
<symbol id="rect">
    <rect x="20" y="20" width="50" height="50" stroke-width="5"></rect>
</symbol>
<use xlink:href="#rect" stroke="grey" fill="none"></use>
<use xlink:href="#rect" transform="scale(2,2)" stroke="black" fill="none"></use>

clipboard.png

複雜來講,縮放的並非元素自己的長度,而是原來的單位長度。上例中的正方形不只自身變大了一倍,並且發生了偏移。就是說,rect全部的屬性值都變成了原來的2倍,包括做爲起點座標的x和y、做爲寬度長度的width和height,還有做爲線條粗細值得stroke-width。orm

rotate

transform="rotate(angle,[centerX, centerY])"ip

默認以座標系中(0,0)原點爲圓心,順時針旋轉angle度。0度爲水平從左向右方向。ci

clipboard.png

<line x1="0" y1="0" x2="200" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="200" stroke="grey"></line>
<symbol id="rect">
    <polygon points="50 10, 100 10, 150 60, 100 60"></polygon>
</symbol>
<use xlink:href="#rect" stroke="grey" fill="none"></use>
<use xlink:href="#rect" transform="rotate(45)" stroke="black" fill="none"></use>

clipboard.png

rotate的第二和第三個參數爲可選參數,用於指定旋轉中心座標,默認即爲0,0。因此若是向讓某個元素圍繞本身的中點旋轉,只要以它的中點座標的x和y值做爲第二和第三個參數便可。get

<line x1="0" y1="0" x2="150" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
<symbol id="rect2">
    <rect x="50" y="50" width="50" height="50"></rect>
</symbol>
<use xlink:href="#rect2" stroke="grey" fill="none"></use>
<use xlink:href="#rect2" transform="rotate(45, 75, 75)" stroke="black" fill="none"></use>

clipboard.png

skewX和shewY

transform="skewX(angle) skewY(angle)"

skewX和shewY可使x軸和Y軸歪斜

<line x1="0" y1="0" x2="300" y2="0" stroke="grey" stroke-dasharray="5 5"></line>
<line x1="0" y1="0" x2="0" y2="200" stroke="grey" stroke-dasharray="5 5"></line>

<g transform="skewX(45)" stroke-width="10" stroke="grey">
    <line x1="0" y1="0" x2="100" y2="0" ></line>
    <line x1="0" y1="0" x2="0" y2="100"></line>
    <text x="0" y="110" stroke-width="1" stroke="black">skewX</text>
</g>
<g transform="translate(175) skewY(45)" stroke-width="10" stroke="grey">
    <line x1="0" y1="0" x2="100" y2="0"></line>
    <line x1="0" y1="0" x2="0" y2="100"></line>
    <text x="0" y="110" stroke-width="1" stroke="black">skewY</text>
</g>

clipboard.png

直觀感覺是,用了skewX,變歪的倒是y軸。我以爲能夠這麼理解,上例中表明y軸直線起始位置的(0,0)和結束位置的(0,100)兩個座標,x軸座標沒有改變,但造成的直線卻不是一條筆直的豎線。被歪斜事後的座標(0,100)位置處於原座標系中(100,100)的位置,被歪斜的是x的座標。
書裏沒提歪斜角度的問題,簡單作了幾個demo,得出的結論還挺簡單的(不知道是否是由於簡單因此書裏懶得寫了。。。因此想了想也不寫了,本身作demo試試看就懂了,角度能夠是負數,能夠超過90度)

形變的次序

transform="translate(100,100) scale(2)"和transform="scale(2) translate(100,100)"形變後的結果是否徹底一致?
若是弄清楚了「複雜來講」的transform和scale,應該不可貴出結論。

<svg height="300" width="300">
    <line x1="0" y1="0" x2="200" y2="0" stroke="grey"></line>
    <line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>

    <symbol id="rect">
        <rect x="20" y="20" width="50" height="50"></rect>
    </symbol>
    <use xlink:href="#rect" stroke="grey" fill="none"></use>
    <use xlink:href="#rect" transform="translate(50,25) scale(2)" stroke="black" fill="none"></use>
</svg>
<svg height="300" width="300">
    <line x1="0" y1="0" x2="300" y2="0" stroke="grey"></line>
    <line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>

    <symbol id="rect">
        <rect x="20" y="20" width="50" height="50"></rect>
    </symbol>
    <use xlink:href="#rect" stroke="grey" fill="none"></use>
    <use xlink:href="#rect" transform="scale(2) translate(50,25)" stroke="black" fill="none"></use>
</svg>

clipboard.png

transform="translate(50,25) scale(2)"是先將rect所在座標系的原點偏移至(50,25),再將單位長度放大兩倍,等同於在原座標中畫這樣一個正方形:

<rect x="50+2*20" y="25+2*20" width="2*50" height="2*50" stroke="black" fill="none"></rect>(將計算結果代入便可運行)

transform="scale(2) translate(50,25)"是先將單位長度放大兩倍,再將rect所在座標系原點偏移至放大後坐標系的(50,25),等同於:

<rect x="2*(50+20)" y="2*(25+20)" width="2*50" height="2*50" stroke="black" fill="none"></rect>(將計算結果代入便可運行)

因此再使用聯合形變的時候,順序弄錯致使的結果就會出問題。

一些技巧

rotate能夠設置旋轉中心座標,但是scale卻沒有,如何讓scale也能按設置的座標爲中心縮放?
沒錯,就是位移+縮放,translate+scale。先位移仍是先縮放,理論上都行。
先位移的狀況下,位移計算公式:

translate(-centerX*(factor-1), -centerY*(factor-1))
scale(factor)

先縮放的狀況下,位移計算公式:

scale(factor)
translate(-centerX*(factor-1)/factor, -centerY*(factor-1)/factor)

明顯前者比較好用,後者容易除不盡嘛。

<line x1="0" y1="0" x2="300" y2="0" stroke="grey"></line>
<line x1="0" y1="0" x2="0" y2="150" stroke="grey"></line>
<circle cx="75" cy="75" r="1" style="fill: black;"></circle>
<g id="box" style="stroke: black; fill: none;">
   <circle cx="75" cy="75" r="15" stroke="grey" fill="none"></circle>
</g>
<use xlink:href="#box" transform=" translate(-75,-75) scale(2)" style="stroke-width: 0.5;"></use>
<use xlink:href="#box" transform=" translate(-112.5,-112.5) scale(2.5)" style="stroke-width: 0.4;"></use>
<use xlink:href="#box" transform=" translate(--150,-150) scale(3)" style="stroke-width: 0.33;"></use>

clipboard.png

css之transform

css中提供了一套與svg形變一致的transform屬性

  • transform:translate(x, y)

  • transform:scale(x, y) / scaleX(x) / scaleY(y)

  • transform:rotate(deg)

  • transform:skew(xdeg, ydeg) / skewX(deg) / skewY(deg)

  • transform:matrix(a,b,c,d,e,f)

一個DOM元素只容許有一個transform屬性,因此當多種形變同時做用於一個DOM元素時,能夠這樣寫:

transform:translate(100px, 100px) scale(1, 0.5) rotate(45deg)

須要注意兩點,

  1. 與svg同樣,形變是有次序的。

  2. 與svg不一樣,數值後須要指定單位。

最後一個Matrix形變矩陣,功能強大,一個屬性實現全部形變。
關於變形矩陣,張鑫旭的一片文章寫得通俗又詳細,推薦看這篇http://www.zhangxinxu.com/wor...

關於matrix這裏就再也不多寫了。但有幾點須要補充

  1. css的transform利用translate+scale也是能夠實現鏡像對稱的,不是非matrix不可。能夠說,maxtrix能夠實現的形變,利用translate+scale+rotate+skew一樣能夠實現。對於複雜的形變,無論用哪一種方式都離不開計算,但萬變不離其宗,理解形變的本質是改變座標體系,剩下的就看數學功底如何了。

  2. 關於用matrix實現和rotate同樣的旋轉,公式有些費解,靠死記硬揹我是一下子就忘了,花一點點篇幅記錄下。先上張圖
    clipboard.png

將圖像順時針旋轉θ,等價於將整個座標系旋轉-θ。如圖所示,原座標點A在原座標系X,Y中的座標爲(x,y),通過順時針旋轉後,點A至關於位於逆時針旋轉θ後的座標系X',Y'中。因此結果至關於求點A在新座標系X',Y'中的座標。這樣一來就簡單了,利用0x和0y做爲斜邊便可得出新座標:

x' = cosθ\*x + sinθ\*y
y' = sinθ\*y - cosθ\*x
相關文章
相關標籤/搜索