createGradientBox是Matrix类中的一个方法,在做渐变填充(beginGradientFill)或渐变笔触(lineGradientStyle)的时候可能会用到。
createGradientBox有5个参数,如下,参数的涵义,官方API写的很清楚,可以看一下。
渐变框宽度:渐变扩展到的宽度(以像素为单位)
渐变框高度:渐变扩展到的高度(以像素为单位)
渐变框旋转:将应用于渐变的旋转角度(以弧度为单位)
水平平移:将渐变水平移动的距离(以像素为单位)
垂直平移:将渐变垂直移动的距离(以像素为单位)
虽然写的很清楚,但是这几个参数到底是什么意思呢,下面,我们就结合flash中的渐变变形工具来理解一下。
在flash中,画一个矩形,填充选为线性渐变,用渐变变形工具选中刚才的矩形,如下。
为了看的清,我稍微拉伸了一下,可以看到两条蓝色的线,这两条蓝色的线组成的矩形,就是GradientBox(渐变框)。渐变框的宽度高度旋转角度就是矩形的宽度高度旋转角度,需要注意的是平移,平移值得是矩形框中间那个小圆点(flash中可以拖动改变位置)相对于父容器坐标原点的位移。其实,如果做过变形框,就很好理解了,变形框和元件是分离的,其实我们操作的是变形框,只是在变形框变形的时候,对可视元件也做了相同的变形操作。
下面是旋转之后的。
matrix对象调用createGradientBox之后,matrix对象的属性值就和这个渐变框的matrix属性值相同了。如此看来,其实我们可以直接创建matrix或者通过旋转平移缩放来得到GradientBox的matrix,而不必使用createGradientBox,createGradientBox只是提供了一些便利而已。
例1
下面是官方帮助文档中的例子。
var myMatrix:Matrix = new Matrix(); trace(myMatrix.toString()); // (a=1, b=0, c=0, d=1, tx=0, ty=0) myMatrix.createGradientBox(200, 200, 0, 50, 50); trace(myMatrix.toString()); // (a=0.1220703125, b=0, c=0, d=0.1220703125, tx=150, ty=150) var colors:Array = [0xFF0000, 0x0000FF]; var alphas:Array = [100, 100]; var ratios:Array = [0, 0xFF]; this.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, myMatrix); this.graphics.drawRect(0, 0, 300, 200);
画出的图形如下:
createGradientBox的参数是(200, 200, 0, 50, 50),也就是一个宽200、高200的矩形框,没有旋转,沿x轴y轴分别平移50。
渐变框实际应该就是图中黑色的矩形框,flash中线性渐变沿高度方向平移不起作用。所以,你会看到flash中渐变框沿y轴没有平移。
那么这个矩形框的matrix值应该是多少呢?
把矩形框看做一个影片剪辑,影片剪辑的原点为中心(即小圆点坐在的位置),那么,它的matrix应该是(a=1, b=0, c=0, d=1, tx=150, ty=150)。
等一下,实际输出的matrix却是(a=0.1220703125, b=0, c=0, d=0.1220703125, tx=150, ty=150),tx、ty没有问题,a和d的值错了。
例2
如果我们把旋转角度改为30°试试。
myMatrix.createGradientBox(200, 200, Math.PI/6, 50, 50);
发现输出变成了(a=0.10571599167290512, b=0.06103515624999999, c=-0.06103515624999999, d=0.10571599167290512, tx=150, ty=150),
按照我们上面的理论,矩形框的matrix应该是d=a=cos(30°)=根号3/2=0.8660254037844387,b=sin(30°)=0.5,c=-b=-0.5;
仔细观察,上面的输出结果中,a和d还是相等的,c还是等于-b的,我们算一下:
0.8660254037844387/0.10571599167290512=8.192;
0.5/0.06103515624999999=8.192;
比值是相等的。
同样,对于第一个例子:
1/0.1220703125=8.192;
初步猜想:也就是说,两个matrix只是a/b/c/d值差了一个比例系数。我们在不使用createGradientBox计算出matrix之后,应该给abcd除以8.192,再用于beginGradientFill和lineGradientStyle就得到预期的结果了。
我们知道,ad乘以一个系数,代表的物理含义是缩放,bc乘以一个系数代表的物理含义是倾斜或剪切。
例3
上面的例子(用例2,因为可以看到bc的值),我们用的宽高都是200,如果我们改变宽高值,比如把高改为400,会怎么样呢?
试验发现输出变成了(a=0.10571599167290512, b=0.12207031249999999, c=-0.06103515624999999, d=0.21143198334581023, tx=150, ty=250)。
对比一下,发现,b和d都变成了原来的两倍。
按照我们上面的理论,矩形框的matrix还应该是a=cos(30°)=根号3/2=0.8660254037844387,b=sin(30°)=0.5,c=-b=-0.5;
再来分析一下:
我们上面没有考虑矩形框的缩放,矩形的宽高就是我们设置的宽高,matrix中是不涉及宽高的,矩形的宽高不同只会影响tx和ty,实际上我们发现,高变为原来的两倍,d会变为原来的两倍,也就是说,是有缩放的,既然有缩放,就要有一个scale=1时的基础宽高。高200的时候,d的比值是8.192,也就是说基础高应该是200*8.192=1638.4。b和d有着相同的缩放变化,所以我们不妨简单的理解为,高的缩放会影响bd的缩放,同样的,宽会影响ac。
同样,我们计算一下基础宽的值,同样为200*8.192=1638.4。
也就是说,变形框的初始宽高为1638.4,当我们创建的变形框,都是由一个宽高都是1638.4的矩形框变形得到的。对于宽是如何影响ac的值的,还不能解释。但是经过验证,确实是可行的。
总结一下:
matrix.a = Math.cos(r) * w / 1638.4;
matrix.d = Math.cos(r) * h / 1638.4;
matrix.b = Math.sin(r) * h / 1638.4;
matrix.c = -Math.sin(r) * w / 1638.4;
对于tx,ty常规处理即可。
其中,r是旋转角度,单位弧度,w、h为宽高。
例4
如myMatrix.createGradientBox(200, 400, Math.PI/6, 50, 50);
等价于:
myMatrix.a = Math.cos(Math.PI/6) * 200 / 1638.4;
myMatrix.d = Math.cos(Math.PI/6) * 400 / 1638.4;
myMatrix.b = Math.sin(Math.PI/6) * 400 / 1638.4;
myMatrix.c = -Math.sin(Math.PI/6) * 200 / 1638.4;
myMatrix.tx=200/2+50;
myMatrix.ty=400/2+50;
可自行验证。
继续。
如果createGradientBox创建的真的是falsh中我们看到的那个变形框的话,我们知道,对于线性渐变填充,改变高度,并不会改变填充效果。
试验一下:
var myMatrix:Matrix = new Matrix(); trace(myMatrix.toString()); // (a=1, b=0, c=0, d=1, tx=0, ty=0) myMatrix.createGradientBox(200, 400, Math.PI/6, 50, 50); trace(myMatrix.toString()); // (a=0.10571599167290512, b=0.12207031249999999, c=-0.06103515624999999, d=0.21143198334581023, tx=150, ty=250) var colors:Array = [0xFF0000, 0x0000FF]; var alphas:Array = [100, 100]; var ratios:Array = [0, 0xFF]; this.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, myMatrix); this.graphics.drawRect(0, 0, 400, 200); myMatrix = new Matrix(); myMatrix.createGradientBox(200, 100, Math.PI/6, 50, 260); trace(myMatrix.toString()); //(a=0.10571599167290512, b=0.030517578124999997, c=-0.06103515624999999, d=0.05285799583645256, tx=150, ty=310) this.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, myMatrix); this.graphics.drawRect(0,210, 400, 200);
createGradientBox的参数,只有高度不一样(y方向平移是为了弥补画图位置的偏移),第一个是400,第二个是100。画出的图如下:
两个图的填充明显不一样。也就是说,我们前边关于createGradientBox创建的就是那个渐变框,以及渐变框的属性与createGradientBox中参数的对应关系,等等,都是错的,或者哪里有问题。我猜想,问题出在旋转那里,旋转并不是绕渐变框的中心那个小圆圈旋转。
越来越理不清了。
如果我们不管createGradientBox方法,就是想要按照我上面理解的变形宽来设置渐变填充的话,改为下面这样就可以了。
matrix.a = Math.cos(r) * w / 1638.4;
matrix.d = Math.cos(r) * h / 1638.4;
matrix.b = Math.sin(r) * w / 1638.4;
matrix.c = -Math.sin(r) * h / 1638.4;
对于tx,ty常规处理即可。
对于放射性渐变填充,上面的公式同样适用。
同样,对于渐变笔触也适用。
有空做个演示的demo放在这里。
。。。。。。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。