此系列文章
- [技術分享] 理解 SVG 中的 Viewport 和 ViewBox-拖曳與縮放功能實做(上)
- [技術分享] 利用 SVG 中的 CTM 進行座標系統的轉換(SVG Coordinate System Transform Matrix)-拖曳與縮放功能實做(中)
- [技術分享] 實做 SVG 中的位移與縮放(SVG Tranaslte and Zoom Scale)-拖曳與縮放功能實做(下)
在這一系列文章中我們把 SVG 整個元素視為一個畫布(Canvas),而不是去 SVG 討論裡面的各個圖形,另外,只討論當 viewport 和 viewBox 兩者比例相等的情況。
在上一篇文章中([教學] 理解 SVG 中的 Viewport 和 ViewBox-拖曳與縮放功能實做(上)),說明到了在 viewport 座標系統中,1px 的大小就會是實際 1px 的大小;但在 viewBox 的 SVG 座標系統中,則可以透過 ViewBox 的設定,去進行縮放和移動,進而使的圖案本身有位移(translate)和縮放(scale)的效果。
為了要讓我們能夠實做出拖拉和縮放的效果,有幾點是我們需要進一步說明的。
實做效果和原始碼
這是我們這一篇文章希望做出來的效果,我們能夠取的 viewport 的座標點,並轉換成 SVG 座標系統中的座標值。另外我另外加了幾個按鈕,讓你可以直接設定 viewBox 並觀察其中圓心的座標會有如何的變化,建議可以在 jsfiddle 中比較方便操作和感受。
詳細的作法會在下面說明:
複習 SVG 座標系統和 viewport 座標系統
從上篇文章我們知道 viewport 的座標系統可以視為是相對於瀏覽器不會變動的座標系統(1px 就是 1px),但是 SVG 座標系統則是會變動的,隨著給定不同的 viewBox 值,SVG 座標系統中的 1 個單位以有可能等於、大於或小於 1px。
這三張圖對於這個觀念的理解真的很重要很重要,所以讓我們快速地再看一次(灰色的是 viewport 座標系統;藍色的是 SVG 座標系統):
當 viewBox 等同於 viewport 的情況
當 viewport 等同於 viewBox 時可以看到鸚鵡右下角的藍點不論在 viewport 座標系統中的 offset 座標點或 SVG 座標系統中的座標點,座標值都是(200, 300),你可以對應到上方側和左方側的指標:
| ![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图2](https://3.bp.blogspot.com/-0lkfg5M8oh0/WNE5gL4ViNI/AAAAAAAAyJI/_qSPBHzgh34CNK_LYfFop91c3FsamjI3gCLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-21%2B%25E4%25B8%258B%25E5%258D%258810.31.40.png#align=left&display=inline&height=948&margin=%5Bobject%20Object%5D&originHeight=948&originWidth=1600&status=done&style=none&width=1600)
|
| viewBox 和 viewport 尺寸大小相同時,offset 座標值等於 svg |
當 viewBox 小於 viewport 的情況
當 viewBox 小於 viewport 時(這裡 viewBox = “400 300 0 0”),因為 viewBox 會先被裁切然後填滿整個 viewport ,所以在 SVG 座標系統藍點雖然還是(200, 300),可視實際上 viewport 座標系統中的 offset 座標值對應回去是(400, 600),也就是說在這個情況下 SVG 座標系統中的 1 單位,會是 viewport 座標系統的 2 單位,也就是 2px。
| ![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图3](https://3.bp.blogspot.com/-FUVyASuZjaQ/WNE5gMw_XaI/AAAAAAAAyJE/E3QcydTaPvweDhHn2FtpIp3xkJ8PE8ezwCLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-21%2B%25E4%25B8%258B%25E5%258D%258810.31.49.png#align=left&display=inline&height=976&margin=%5Bobject%20Object%5D&originHeight=976&originWidth=1600&status=done&style=none&width=1600)
|
| 此時 SVG 座標系統中的 1 單位,會是 viewport 座標系統的 2 單位,也就是 2px |
當 viewBox 大於 viewport 的情況
當 viewBox 大於 viewport 時(這裡 viewBox = “1600 1200 0 0”),因為 viewBox 會先被裁切然後填滿整個 viewport ,所以在 SVG 座標系統藍點雖然還是(200, 300),可視實際上 viewport 座標系統中對應回去是(100, 150),也就是說在這個情況下 SVG 座標系統中的 1 單位,會是 viewport 座標系統的 0.5 單位,也就是 0.5px。
| ![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图4](https://3.bp.blogspot.com/-ilNbsVhzTfI/WNE5fxzkhDI/AAAAAAAAyJA/di56LLVMfnQKgw4xcOVyIbUZvzPj8B9YACLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-21%2B%25E4%25B8%258B%25E5%258D%258810.32.03.png#align=left&display=inline&height=1010&margin=%5Bobject%20Object%5D&originHeight=1010&originWidth=1600&status=done&style=none&width=1600)
|
| 此時 SVG 座標系統中的 1 單位,會是 viewport 座標系統的 0.5 單位,也就是 0.5px |
SVG 座標系統和 viewport 座標系統的轉換:觀念
如果你對於上面的觀念還不清楚的話,建議可以再把第一篇文章看過一次,或在想清楚。接下來我們要說明如何在 SVG 座標系統和 viewport 座標系統中做轉換。
另外,在上一篇文章中,我們有提到 viewBox = “x-min y-min width height” 這四個屬性值,而在上面的範例中,敏銳的讀者應該會發現, 不論是放大或縮小,都是從最左上方的點開始(橘點),這點非常很重要,之後在實做縮放的時候會用到這個觀念。
| |
| 不論是放大或縮小,都是從最左上方的點開始(橘點) | 其實 SVG 座標系統和 viewport 座標系統中是有辦法做相對應的轉換的。在上面的說明中,為了方便比較 viewport 座標系統和 SVG 座標系統單位大小的不同,我們都是用 offset 的座標點,但是如果我們希望能在 viewport 座標系統和 SVG 座標系統間做相對的轉換,我們就會需要用到 client 這個座標名稱。
client 座標和 offset 座標一樣都是屬於 viewport 座標系統,只是前者是以瀏覽器視窗左上角為原點(0, 0);後者則是以容器左上角為原點。
|
|
| client 座標和 offset 座標一樣都是屬於 viewport 座標系統,只是前者是以瀏覽器視窗左上角為原點(0, 0);後者則是以容器左上角為原點 |
SVG 座標系統和 viewport 座標系統間的轉換需要一些數學的運算(電腦會幫你算),但為了避免 ~ 大家~(我)看到數學就害怕(看到數學就先暈一半),我們先用簡單的方式來理解這兩者座標的轉換。
作法其實很簡單,想像有一個叫做 CTM 的魔術棒,透過這個魔術棒,我們就可以將 viewport 座標系統中的 client(x, y) 轉換成 SVG 座標系統中的 svg(x, y);相似地,我們可以透過 CTM 這個魔術幫棒將 SVG 座標系統中的 svg(x, y) 轉換為 viewport 座標系統中的 client(x, y):
更精確的說,當我們要從 SVG 座標系統 → viewport(client) 座標系統時,是利用 CTM X SVG 座標系統中的座標,可以得到 viewport 座標系統中的座標值:
可是如果要從 viewport(client) 座標系統 → SVG 座標系統,那麼我們的 CTM 也要反轉 一下才能得會 SVG 座標。為什麼要把 CTM 反轉過來才能用呢?你可以想像你要用鑰匙開鎖和解鎖,開鎖的時候要順時鐘轉,解鎖的時候要用逆時針轉,CTM 的反轉也可以用這樣的概念來想。
這裡有一點要留意的是兩個座標系統間的轉換時,我們用的是 viewport 座標系統中的 client(x, y) 而不是 offset(x, y),這點要非常留意。
CTM 的真面貌
好吧!一下魔術棒,一下要鑰匙的,你可能覺得很煩,我就直接說了,其實 CTM 就是個 3 x 3 的矩陣,全名是 current transform matrix。什麼…!!矩陣…!!那我需要把高中的數學課本拿出來嗎??
~
~~ 就說用魔術棒想會比較好吧~,其實,如果你只是想要瞭解基本的位移和縮放,只要瞭解 viewBox 裡面的四個屬性值,知道有魔術棒這個東西可以幫助我們把座標點從 viewport(client) 座標系統和 SVG 座標間做轉換就好了,還有很重要的一點就是是,每次我們透過設定 viewBox 去對 SVG 進行縮放或位移後,魔術棒(CTM)的樣式都會變的不一樣這樣就可以了。
但是如果你想要更深入瞭解 SVG 的各種變化,像是選旋轉(rotate)、歪斜(skewed)或者應用到 SVG 當中的各個元素的話(例如,、),那你可能就需要更深入的瞭解 CTM 矩陣。
至於為什麼魔術棒需要像鑰匙一樣向左轉、向右轉,其實就是反矩陣的概念。
為了閱讀上的舒適度,我會把實際上矩陣轉換的公式寫在文中最後,如果不排斥的話,可以最後再看,或者就先直接當成它是一個魔術棒吧!
至於要如何取得 CTM 這個魔術棒,就讓我們實際看一下 code 吧!
SVG 座標系統和 viewport 座標系統的轉換:實做
接下來我們會看到許多 JavaScrip Web API 來協助我們進行 SVG 的操作,但是要注意的是,在這裡我們都是針對 SVG 這個元素(也就是 ,<svg></svg> 個 tag 本身),而不是針對 svg 裡面的圖案(例如 `, 等等)進行操作。
在 JavaScript Web API 中可以直接透過 SVGGraphicsElement.getScreenCTM() 這個方法,只要針對某個 svg 元素就可以讓我們直接取得 CTM,那麼到底要如何實際易應用呢?
取得 viewport 座標系統的座標值(clientXY, offsetXY)
我們先在 HTML 建立 SVG 元素:
<svg id="svg" width="600" height="300" viewBox="0 0 600 300"><rect x="0" y="0" fill="none" stroke="#EB7B2D" stroke-width="2" width="600" height="300" /><circle cx="300" cy="150" r="5" fill="#EB7B2D" /></svg><!-- 取得滑鼠座標資訊 --><div id="info"><p id="offset">offset</p><p id="client">client</p><p id="showSvg">svg</p></div>
透過 <svg width="600" height="300">,我們定義了 viewport 為 600 x 300(px)。利用 <circle></circle>,我們在 SVG 中畫了一個圓心在(300, 150)、半徑(r)為 5 的圓,要注意的是,這裡的(300, 150)指的是 SVG 座標系統。
另外利用 <rect x="0" y="0" fill="none" stroke="#EB7B2D" stroke-width="2" width="600" height="300" /> 也在 SVG 中幫我們畫一個邊框,這能夠幫助我們看之後 SVG 座標系統的位移和縮放。
接著,我們利用 JS 來取得 viewport 座標系統中的 offset 和 client 座標值,並且希望滑鼠滑動的時候可以馬上取得該滑鼠所在的 viewport 座標值,因此我們在 svg 這個元素上把上 mousemove 事件 svg.addEventListener('mousemove', reportCurrentPoint),當滑鼠一滑動,就觸發去執行 reportCurrentPoint 這個函式:
``function reportCurrentPoint (e) {// 選取 HTML 各元素const info = document.getElementById('info')const offset = document.getElementById('offset')const client = document.getElementById('client')const showSvg = document.getElementById('showSvg')// 取得 viewport 座標系統中的 offset 和 client 座標值offset.textContent = `offset (${e.offsetX}, ${e.offsetY})`client.textContent = `client (${e.clientX}, ${e.clientY})`}const svg = document.getElementById('svg')svg.addEventListener('mousemove', reportCurrentPoint)``
利用則是利用 ES6 中模版字串符的方式代入 offset 和 client 座標值。
在我們的範例中,你會發現 offset 和 client 的值相差 9px ,當我們把滑鼠移到這個 container 的最左上角時,你會發現 offset(0, 0),client(9, 9),也就是從 container 左上角和 window 左上角的差值。
(註:一般來說 client 的值會以瀏覽器視窗左上角的圓點,但在示範所用的 fiddle 中,因為它是分割視窗的緣故,所以是以 Result 視窗的左上角為原點)
取的 SVG 座標系統中的座標值
接著我們要寫 JS ,要在座標系統中的座標可以彼此轉換,我們要先在 SVG 座標系統中建立一個點,可以直接使用 SVGElement.createSVGPoint() 這個方法,這個點建立起來後會是一個 SVGPoint 物件,包含屬性 x 和屬性 y ,初始值會是(0, 0)。
然後,我們可以利用 SVGGraphicsElement.getScreenCTM() 來取得魔術棒 CTM。
`const svg = document.getElementById('svg') // 選取 SVG 元素
let SVGPoint = svg.createSVGPoint() // 建立一個 SVG 座標,初始值為(0,0)
let CTM = svg.getScreenCTM() // 取的該元素的 CTM
/*
** svgPoint(SVG 座標系統) * CTM ---> client (viewport 座標系統)
*/
// 把 SVG 的座標點給進去
SVGPoint.x = 300
SVGPoint.y = 150
clientPoint = SVGPoint.matrixTransform(CTM) // client(309, 159)
/*
** client (viewport 座標系統) * CTM^(-1) ---> svgPoint(SVG 座標系統)
*/
SVGPoint = clientPoint.matrixTransform(CTM.inverse()) // svg(300, 150)`
SVG 座標系統轉換成 viewport 座標系統的 client 座標點,可以直接使用 CTM。
因此假設我想要知道圓心的 svg(300, 150) 轉換之後在 viewport 的 client 座標是多少,我們可以利用 SVGPoint.x = 300; SVGPoint.y = 150 把座標點給進去,接著讓這個 svg 座標點透過魔術棒 CTM (實際上做的是矩陣相乘,CTM * svg)轉換為 client 座標點,於是寫 clientPoint = SVGPoint.matrixTransform(CTM),我們就能得到 client(309, 159) 這個屬於 viewport 座標系統的座標值。
viewport 座標系統的 client 座標點要轉換為 SVG 座標系統的 SVGPoint 時,則使用反轉後的 CTM(CTM 的反矩陣)。
我們也可以把剛剛得到的 client(309, 159) 代入反轉過的 CTM 中轉回 SVG 座標系統的座標點(一樣是矩陣相乘,只是被乘的是 CTM 的反矩陣, CTM^(-1) x client),寫法是 SVGPoint = clientPoint.matrixTransform(CTM.inverse()) ,這樣我就會得回 SVG 座標系統中的座標值。
把 SVG 的轉換也綁到滑鼠移動的事件上
一般來說,因為 viewport 座標系統的尺寸是確定的(1px 就是 1px),所以我們比較常利用 client 座標來回推 SVG 座標系統的座標值,也就是 CTM^(-1) x client。
現在,就讓我們把 client 座標轉換為 SVG 座標的寫法綁在 mousemove 這個事件上,讓滑鼠移動的時候,都能夠馬上取得 SVG 座標系統中的座標值。
``function reportCurrentPoint (e) {
// 選取 HTML 各元素
const info = document.getElementById('info')
const offset = document.getElementById('offset')
const client = document.getElementById('client')
const showSvg = document.getElementById('showSvg')
const svgElement = document.getElementById('svgElement')
// 取得 viewport 座標系統中的 offset 和 client 座標值,並顯示於視窗上
offset.textContent = `offset (${e.offsetX}, ${e.offsetY})`
client.textContent = `client (${e.clientX}, ${e.clientY})`
// 建立 SVG 座標點(0, 0)
const clientPoint = svg.createSVGPoint()
// 取得 CTM
const CTM = svg.getScreenCTM()
// 將 SVG 座標點的 x, y 設成 client(x, y)
clientPoint.x = e.clientX
clientPoint.y = e.clientY
// 將 client 的座標點轉成 SVG 座標點
SVGPoint = clientPoint.matrixTransform(CTM.inverse())
// 將資訊顯示於視窗上
showSvg.textContent = `svg (${SVGPoint.x.toFixed(0)}, ${SVGPoint.y.toFixed(0)})`
}
svg.addEventListener('mousemove', reportCurrentPoint)``
在這裡我把最後顯示的 SVG 座標加上 SVGPoint.x.toFixed(0) 加上 toFixed(0) ,因為矩陣轉換之後得到的會是很多為的小數,不方便觀看,因此我就四捨五入把小數點去除。
改變 viewBox 看看座標系統會有什麼樣的影響
接著,你可以改變設定在 SVG 中的 viewBox 值,看看對於 SVG 的座標系統會有什麼樣的影響,在 viewBox 中前兩項(min-x 和 min-y)控制了位移;後兩項控制了縮放(width 和 height),為了方便瞭解,會建議你在後兩項的設定和 viewport 是等比例的縮放,也就是我們原本的 viewport 是 600 x 300 ,你可以把後面這兩項等比例放大設為 1200 x 600 或縮小 300 x 150,來看效果。
例如,一開始 viewport 和 viewBox 的尺寸相等,且沒有位移時(viewBox = "0 0 600 300"),圓心的點座標會如下圖:
但是當我把 viewBox width 和 height 做等比例的改變後(viewBox = "0 0 450 225"),你會發現圓點的座標,在 SVG 座標系統仍然是 svg(300, 150),但是在 viewport 的座標系統中 offset(400, 200),client(409, 209)。這是因為當我的 viewBox 比例縮小為原本的 0.75 倍時,SVG 座標系統則會被放大(從左上角的地方放大),進而把圓點從中心的位置往右下推動,而圓也跟著放大了。
|
|
| 是從左上方當中心開始做縮放 |
你可以再把 viewBox 設定成不同的值測試看看,這將有助於你更能夠掌握 viewport 和 ViewBox 之間的關係。
進一步瞭解 CTM
在這裡我們會簡單說明 CTM 矩陣,如果你只是想要瞭解如何用 viewBox 做到縮放和拖移的效果,沒有瞭解 CTM 矩陣並不會有太大的影響。但是如何你想要對於座標點是如何在兩個不同的座標系統間轉換,瞭解一下矩陣的運算是很有幫助了。另外,在這裡我們是針對 SVG 這個 tag 本身去取得 CTM ,如果你是想要針對 SVG 裡的圖形(例如,, )去做變化,其背後的原理是相似的,但這就不在我們這篇討論的範圍內了。
CTM 概念說明
CTM 它的本質是一個 3 X 3 的矩陣,長的像這樣子:
|
|
| CTM 矩陣的樣子 | 其中 e 和 f 控制的是位移(translate);a 和 d 控制的是縮放(scale)。
更深入的話,透過 a, b, c, d, e, f 的改變,我們就能達到各種縮放、位移、選轉、變形等等的效果。
在矩陣的概念中,我們則是將座標點用這樣的方式表示:
|
|
| 以矩陣的方式表示座標點 |
所以從 SVG 座標系統的座標點透過 CTM 轉到 viewport 座標系統的座標點,公式就像這樣:
|
|
| SVG 座標系統的座標點透過 CTM 轉到 viewport 座標系統的座標點 |
如果想從 viewport 座標系統轉回 SVG 座標系統就需要利用到 CTM 的反矩陣(以 - 1 表示),公式像這樣:
|
|
| viewport 座標系統轉回 SVG 座標系統就需要利用到 CTM 的反矩陣(以 - 1 表示) |
讓我們來實做看看
這裡推薦一個很方便的網站-矩陣計算器,我們就用這個網站來驗證我們上面程式的結果。
現在我把上面範例中的 viewBox = "0 0 450 225" 的設定,透過上面所教得方式,我們將滑鼠游標移到圓心,可以發現在 viewport 座標系統中的 client(409, 209),接著,利用 svg.getScreenCTM() 我們可以取得當前 SVG 元素的 CTM ,算出來是的 matrix(a, b, c, d, e, f) = matrix(1.3333, 0, 0, 1.3333, 9, 9),現在我們就可以把這些值代入矩陣計算機中,按下等號:
計算的結果就像這樣,你可以看到最後的結果就是 (300, 150),而這也就是我們上面利用程式所顯示的 SVG 座標值:
重點總結
- 利用魔術棒(CTM)可以讓 viewport 座標系統中的 client 座標值和 SVG 座標系統中的座標值做轉換。
- 要記得轉換回去的是 viewport 的 clientXY 而不是 offsetXY
參考資料
- SVG 座標轉換 @ MSDN.aspx)
- Understanding SVG Coordinate Systems and Transformations
- [中譯]理解 SVG 座標系統和 Transformation @ Andyyou
- SVG 研究之路 (20) - transform Matrix @ OXXO
- SVGPoint @ MDN
- 首頁圖片來源 @ TeamTreehouse
- Grid Icon Created By Josh @ NounProject
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图1](https://1.bp.blogspot.com/-JwXszAsOjf4/WM-O3LtE7ZI/AAAAAAAAyGU/jdvzlIUZDzQh0PhAQTdeqLvCtwAis9BJgCLcB/s640/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-20%2B%25E4%25B8%258B%25E5%258D%25884.11.38.png#align=left&display=inline&height=290&margin=%5Bobject%20Object%5D&originHeight=290&originWidth=640&status=done&style=none&width=640)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图7](https://1.bp.blogspot.com/-XeA2GZu91lU/WNE8JeOAH9I/AAAAAAAAyJo/y4B2xlavpKYRuccM8hN1NdUilfDRQtuigCLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-21%2B%25E4%25B8%258B%25E5%258D%258810.43.09.png#align=left&display=inline&height=673&margin=%5Bobject%20Object%5D&originHeight=673&originWidth=1600&status=done&style=none&width=1600)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图8](https://4.bp.blogspot.com/-SVDGgoLznek/WNE8JXpihaI/AAAAAAAAyJk/adRFNjcYb2Uf61ml5YQjjPLHGX9o2yIRQCLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-21%2B%25E4%25B8%258B%25E5%258D%258810.43.16.png#align=left&display=inline&height=691&margin=%5Bobject%20Object%5D&originHeight=691&originWidth=1600&status=done&style=none&width=1600)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图9](https://3.bp.blogspot.com/-ifY8ApdI9W0/WNE8JbvMCoI/AAAAAAAAyJs/ZIebzp3QSnULBLg1jkDiCuIjgNTznyttACLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-21%2B%25E4%25B8%258B%25E5%258D%258810.43.24.png#align=left&display=inline&height=688&margin=%5Bobject%20Object%5D&originHeight=688&originWidth=1600&status=done&style=none&width=1600)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图10](https://4.bp.blogspot.com/-aF0HBL5GfpM/WNEl_lWSFsI/AAAAAAAAyIc/2hI5JgpmYRsUIfwlT4VXofdvowq4UP_IgCLcB/s640/thematrix-1.jpg#align=left&display=inline&height=512&margin=%5Bobject%20Object%5D&originHeight=512&originWidth=640&status=done&style=none&width=640)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图11](https://1.bp.blogspot.com/-00JGYpIWrn4/WNHXpbmQynI/AAAAAAAAyK0/c2Qtf2oAt9AImd3ILy7WqT6uB8P8oZ6_gCLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-22%2B%25E4%25B8%258A%25E5%258D%25889.46.53.png#align=left&display=inline&height=1097&margin=%5Bobject%20Object%5D&originHeight=1097&originWidth=1600&status=done&style=none&width=1600)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图12](https://4.bp.blogspot.com/-8YvrZADW3pw/WNHYFPHPg7I/AAAAAAAAyK4/XwMPYsSp6CoNCRk10FL2pR-7RmR3I8XpwCLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-22%2B%25E4%25B8%258A%25E5%258D%25889.48.44.png#align=left&display=inline&height=1095&margin=%5Bobject%20Object%5D&originHeight=1095&originWidth=1600&status=done&style=none&width=1600)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图18](https://2.bp.blogspot.com/-VcXEhYERkGY/WNHoOKqtvZI/AAAAAAAAyM8/oXSfc0_6Zis56nxHKSzfHOoYN2YrF-hDgCLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-22%2B%25E4%25B8%258A%25E5%258D%258810.57.33.png#align=left&display=inline&height=597&margin=%5Bobject%20Object%5D&originHeight=597&originWidth=1600&status=done&style=none&width=1600)
![[技术分享] 利用 SVG 中的 CTM 进行座标系统的转换(SVG Coordinate System Transform Matrix)-拖曳与缩放功能实做(中) - 图19](https://4.bp.blogspot.com/-CMKfJ47tuK0/WNHpjEUqodI/AAAAAAAAyNQ/tpmUxkOZEPYm2IaR-FAzKRNI4OhK47eiACLcB/s1600/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%2B2017-03-22%2B%25E4%25B8%258A%25E5%258D%258811.03.03.png#align=left&display=inline&height=632&margin=%5Bobject%20Object%5D&originHeight=632&originWidth=1332&status=done&style=none&width=1332)
