你的位置:首页 > 网页设计

[网页设计]获取Canvas当前坐标系矩阵


前言

在我的另一篇博文 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还原到原坐标系坐标值。