canvas教程

Canvas学习:自定义的坐标变换(4)

字号+ 作者:H5之家 来源:H5之家 2017-08-04 13:02 我要评论( )

理论上而言,一个点是不存在什么缩放变换的,但考虑到所有图像都是由点组成,因此,如果图像在 x 轴和 y 轴方向分别放大 k1 和 k2 倍的话,那么图像中的所有点的 x 坐标和 y 坐标均会分别放大 k1 和 k2 倍。 用公式

理论上而言,一个点是不存在什么缩放变换的,但考虑到所有图像都是由点组成,因此,如果图像在 x 轴和 y 轴方向分别放大 k1 和 k2 倍的话,那么图像中的所有点的 x 坐标和 y 坐标均会分别放大 k1 和 k2 倍。

用公式表示就是: (x y) 代表原坐标的点, (x',y') 代表新坐标的点。

如果用矩阵来表示就是:

我们分别进行两个测试, X 方向测试矩阵如下:

ctx.fillStyle = '#f36'; ctx.transform(.5, 0, 0, 1, 0, 0); ctx.fillRect(0,0,100,100);

效果如下:

可以看到,正方形在 X 方向上进行了缩放,变成了之前的 0.5 倍。再进行 Y 方向的矩阵测试:

ctx.fillStyle = '#f36'; ctx.transform(1, 0, 0, .5, 0, 0); ctx.fillRect(0,0,100,100);

效果如下:

没有问题, Y 方向变成原来的 0.5 倍。

注:从上面的示例可以看出来,不管是 X 轴还是 Y 的缩放都是基于原点进行的。如果需要基于元素自身中心点做缩放,那需要在 transform() 或 setTransform() 之前先做 translate() 操作。当然也可以使用 transform() 或 setTransform() 来替代 translate() 。

旋转

前面我们看到了怎么通过 transform() 和 setTransform() 方法来实现 translate() 和 scale() 的效果,接下来看怎么实现 rotate() 效果。因为旋转涉及到角度的问题,这里有一个数学知识很有必要先进行了解。

假定有一个点 P(x0,y0) 相对坐标原点顺时针旋转 θ 到达点 P(x,y) ,同时假定 P 点离坐标原点的距离为 r ,如下图所示:

那么要计算出 P 点的坐标,就需要运用到两角和公式:

sin(α + θ) = sin(α)*cos(θ) + cos(α)*sin(θ) cos(α + θ) = cos(α)*cos(θ) - sin(α)*sin(θ)

除了有两角和公式之外,还有对应的两角差公式:

sin(α - θ) = sin(α)*cos(θ) - cos(α)*sin(θ) cos(α - θ) = cos(α)*cos(θ) + sin(α)*sin(θ)

根据上图我们可以推导出, P0 点以半径 r 旋转一定的角度 α ,然后位置在 (x0,y0) 位置处,并且从 (x0,y0) 处继续围绕原点旋转 θ 度到达 P 点 (x,y) 处。根据前面的两角和公式,可以计算出 P 点 (x,y) 的值:

x = r * cos(α + θ) = r*cos(α)*cos(θ) - r*sin(α)*sin(θ) y = r * sin(α + θ) = r*sin(α)*cos(θ) + r*cos(α)*sin(θ)

而 x0 = r*cos(α); y0=r*sin(θ) ,那么:

x = r * cos(α + θ) = r*cos(α)*cos(θ) - r*sin(α)*sin(θ) = x0*cos(θ) - y0*cos(θ) y = r * sin(α + θ) = r*sin(α)*cos(θ) + r*cos(α)*sin(θ) = y0*cos(θ) + x0*sin(θ)

如果用矩阵,就可以表示为:

我们来进行一个 90 度旋转的测试, cos(90)=0,sin(90)=1 ,所以矩阵应该写成:

将上面的矩阵通过 transform() 来表示就是 transform(0,1,-1,0,0,0) 。来看在Canvas中的效果:

ctx.fillStyle = '#f36'; ctx.transform(0,1,-1,0,0,0); ctx.fillRect(0,0,200,100);

如果就这样的话,大家在Canvas的画布中看不到任何的图形,有可能还以为是出错了,其实并非如此。为什么呢?因为如果从 (0,0) 点绘制一个旋转的图,那么肯定已经转到屏幕外面了,所以我们给它加一个偏移试试(位移前面介绍过了):

ctx.fillStyle = '#f36'; ctx.transform(0,1,-1,0,200,50); ctx.fillRect(0,0,200,100);

这下效果就出来了:

斜切

斜切变换Skew在数学上又称为Shear Mapping或者Transvection,它是一种比较特殊的线性变换。大家不知道是否还记得,在上一节或者说本节内容前面,我们提到Canvas自定的变换有 rotate() 、 scale() 和 translate() ,就是没有看到 skew() 这样的方法。虽然没有自带 skew() 这样的方法,但值得庆幸的是,可以通过 transform() 或者说 setTransform() 方法来实现。接下来我们来看看怎么实现斜切变换。

斜切变换的效果就是让所有点的 x 坐标(或者 y 坐标)保持不变,而对应的 y 坐标(或者 x 坐标)按比例发生平移,且平移的大小和该点到 x 轴(或 y 轴)的垂直距离成正比。斜切变换,属于面积变换,即一个形状在斜切变换的前后,其面积是相等的。

比如下图,各点的 y 坐标保持不变,但其 x 坐标则按比例发生了平移。这种情况将发生水平斜切:

下图各点的 x 坐标保持不变,但其 y 坐标则按比例发生了平移。这种情况将发生垂直斜切:

与旋转变换相比,旋转变换是旋转坐标系中的点,而斜切内里是转坐标轴,坐标轴旋转之后,要保持各点的坐标值不变,所有各点的位置就变了,如下图:

变换后,点在新坐标系中的位置不变,在原坐标系中的位置是:

f(x) = x * tan(α) f(y) = y * tan(α)

计算如下:

回到Canvas当中来,假定有一个点 P0(x0,y0) 经过斜切变换后得到 P(x,y) ,对于水平斜切,它们之关的关系是:

x = x0 + k*y0 y = y0

用矩阵表示就是:

扩展到 3 x 3 的矩阵就是下面这样的形式:

同理,对于垂直斜切,可以有:

在数学上严格的斜切变换就是上面这样,但在Canvas中除了有上面说的情况之外,还可以同时进行水平、垂直斜切,那么矩阵就变成:

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • HTML5 CANVAS画图 beginPath和closeP

    HTML5 CANVAS画图 beginPath和closeP

    2017-08-04 15:03

  • canvas学习笔记(二):绘制图形

    canvas学习笔记(二):绘制图形

    2017-08-04 13:00

  • canvas学习总结(6):绘制矩形

    canvas学习总结(6):绘制矩形

    2017-08-04 12:02

  • 【canvas学习笔记二】绘制图形

    【canvas学习笔记二】绘制图形

    2017-08-04 09:01

网友点评
"