前言
在我的另一篇博文 Canvas坐標系轉換 中,我們知道了所有的平移縮放旋轉操作都會影響到畫布坐標系。那在我們對畫布進行了一系列操作之后,怎么再知道當前矩陣數據狀態呢。
具體代碼
首先請看下面的一段代碼(下文具體解釋代碼作用):
1 window.TrackTransform = function () { 2 var svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg'); 3 var xform = svg.createSVGMatrix(); 4 var savedTransforms = []; 5 this.trackTransform=function(ctx) { 6 7 ctx.getTransform = function () { return xform; }; 8 9 var save = ctx.save; 10 ctx.save = function () { 11 savedTransforms.push(xform.translate(0, 0)); 12 return save.call(ctx); 13 }; 14 var restore = ctx.restore; 15 ctx.restore = function () { 16 xform = savedTransforms.pop(); 17 return restore.call(ctx); 18 }; 19 20 var scale = ctx.scale; 21 ctx.scale = function (sx, sy) { 22 xform = xform.scaleNonUniform(sx, sy); 23 return scale.call(ctx, sx, sy); 24 }; 25 var rotate = ctx.rotate; 26 ctx.rotate = function (deg) { 27 28 var radians = deg * Math.PI / 180; 29 xform = xform.rotate(deg); 30 return rotate.call(ctx, radians); 31 }; 32 var translate = ctx.translate; 33 ctx.translate = function (dx, dy) { 34 xform = xform.translate(dx, dy); 35 return translate.call(ctx, dx, dy); 36 }; 37 var transform = ctx.transform; 38 ctx.transform = function (a, b, c, d, e, f) { 39 var m2 = svg.createSVGMatrix(); 40 m2.a = a; m2.b = b; m2.c = c; m2.d = d; m2.e = e; m2.f = f; 41 xform = xform.multiply(m2); 42 return transform.call(ctx, a, b, c, d, e, f); 43 }; 44 var setTransform = ctx.setTransform; 45 ctx.setTransform = function (a, b, c, d, e, f) { 46 xform.a = a; 47 xform.b = b; 48 xform.c = c; 49 xform.d = d; 50 xform.e = e; 51 xform.f = f; 52 return setTransform.call(ctx, a, b, c, d, e, f); 53 }; 54 var pt = svg.createSVGPoint(); 55 //通過原坐標系點x,y求對應當前坐標系的坐標值 56 ctx.transformedPoint = function (x, y) { 57 pt.x = x; pt.y = y; 58 return pt.matrixTransform(xform.inverse()); 59 } 60 var pt2 = svg.createSVGPoint(); 61 //當前坐標系中的的xy還原到原坐標系坐標值 62 ctx.transformedPoint2 = function (x, y) { 63 pt2.x = x; pt2.y = y; 64 return pt2.matrixTransform(xform); 65 } 66 var clearRect = ctx.clearRect; 67 ctx.clearRect = function (x, y, w, h) { 68 ctx.save(); 69 ctx.setTransform(1, 0, 0, 1, 0, 0); 70 clearRect.call(ctx, x, y, w, h); 71 ctx.restore(); 72 } 73 } 74 }
代碼中主要定義了一個類TrackTransform,重寫了CanvasRenderingContext2D
對象的save,restore,scale,rotate,translate,transform,setTransform,clearRect方法。
TrackTransform類使用
如何使用window.TrackTransform類呢?通過以下兩句代碼,變量contex的轉換方法即進行了重寫。
1 //初始化矩陣轉換; context為 getContext("2d")所得的CanvasRenderingContext2D
對象。
2 var track = new TrackTransform();
3 track.trackTransform(context);
方法詳解
具體解釋上面各行代碼的作用
1 創建矩陣對象xform
2 var svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg');
3 var xform = svg.createSVGMatrix();
第2行代碼通過createElementNS創建與獲取到SVG對象。
第3行代碼通過createSVGMatrix()方法創建并返回一個新的2x3的矩陣SVGMatrix矩陣對象賦值到xform。
我們在瀏覽器中打開開發者工具,到控制臺可以輸出矩陣看看初始值。
a b c d e f 這6個值就對應了我們在介紹transform方法的那6個參數。這個2x3的矩陣為了方便矩陣運算我們把它擴展為一個3x3的矩陣。
svgMatrix介紹
這里再簡單解釋下svgMatrix:
svgMatrix的方法和屬性如下圖(具體可參閱:https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix)
2 save方法
savedTransforms.push(xform.translate(0, 0));
return save.call(ctx);
先將xform存儲在一個數組savedTransforms中,然后調用原API方法。
3 restore方法
xform = savedTransforms.pop();
return restore.call(ctx);
從savedTransforms數組中去除最后一個對象,并將其賦值到變量xform,然后調用原API方法。
4 scale方法
xform = xform.scaleNonUniform(sx, sy);
return scale.call(ctx, sx, sy);
維護xform,將其縮放,然后調用原API方法。
5 rotate方法
var radians = deg * Math.PI / 180;
xform = xform.rotate(deg);
return rotate.call(ctx, radians);
將角度轉為弧度,維護xform將其進行旋轉變換,然后調用原API方法。
6 translate方法
xform = xform.translate(dx, dy);
return translate.call(ctx, dx, dy);
維護xform將其進行平移變換,然后調用原API方法。
7 transform方法
var m2 = svg.createSVGMatrix();
m2.a = a; m2.b = b; m2.c = c; m2.d = d; m2.e = e; m2.f = f;
xform = xform.multiply(m2);
return transform.call(ctx, a, b, c, d, e, f);
首先聲明一個新的矩陣m2,m2賦值為要進行變換的6個參數值,然后xform和m2執行矩陣乘法運算,運算結果賦值到xform將其維護。然后調用原API方法。
8 setTransform方法
xform.a = a;
xform.b = b;
xform.c = c;
xform.d = d;
xform.e = e;
xform.f = f;
return setTransform.call(ctx, a, b, c, d, e, f);
維護xform的值,然后調用原API方法。
9 clearRect方法
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clearRect.call(ctx, x, y, w, h);
ctx.restore();
首先保存context的當前狀態,將畫布重置到原始狀態(可以理解為坐標系重置到默認坐標系),然后調用原API方法清除畫布指定范圍內容。清除后調用restore恢復Canvas之前保存的狀態。
10 getTeansform方法
ctx.getTransform = function () { return xform; };
接下來介紹的三個方法都是原API沒有的。getTeansform直接返回xform,可以看到代表畫布矩陣的6個值abcdef。
11 transformedPoint方法
54 var pt = svg.createSVGPoint();
55 //通過原坐標系點x,y求對應當前坐標系的坐標值
56 ctx.transformedPoint = function (x, y) {
57 pt.x = x; pt.y = y;
58 return pt.matrixTransform(xform.inverse());
59 }
通過原坐標系點x,y求對應當前坐標系的坐標值。
createSVGPoint創建的點為(0,0),xform.inverse()是求xform的逆矩陣。MatrixTransform則是通過一種矩陣算法來進行運算得到相應的變形的效果的。矩陣的一些基本算法就不多總結了,以前上課就學過了,網上也有不少講解。
12 transformedPoint2方法
60 var pt2 = svg.createSVGPoint();
61 //當前坐標系中的的xy還原到原坐標系坐標值
62 ctx.transformedPoint2 = function (x, y) {
63 pt2.x = x; pt2.y = y;
64 return pt2.matrixTransform(xform);
65 }
當前坐標系中的的x,y還原到原坐標系坐標值。
文章列表