理解HTML 5画布的缩放和平移顺序

15

我正在围绕坐标中心点0,0的位置进行一些关于IT技术方面的图形绘制。当准备进行渲染时,我使用translate重新定位,然后使用scale缩小图形大小以填充画布(例如将所有内容缩小50%)。

我注意到调用scale和translate的顺序很重要,但我无法理解其中的原理。这是一个问题,因为不是所有的图形都能够适应我的思维模型,所以我很难去解决它。

有人能解释一下为什么scale和translate的调用顺序很重要吗?

3个回答

24

那么让我们在一个300x300的画布上画一个网格:

http://jsfiddle.net/simonsarris/4uaZy/

这里输入图片的描述

这就是了。没有什么特别的。红线表示原点位于(0,0),并延伸得非常长,因此当我们移动它时,我们会看到一些东西。这里的原点是左上角,在红线交汇处(0,0)。

以下所有的翻译都发生在我们绘制网格之前,所以我们将移动网格,从而让您看到正在发生的情况。


让我们把画布向下和向右平移100,100:

这里输入图片的描述

http://jsfiddle.net/simonsarris/4uaZy/1/

所以我们平移了原点,也就是红色的X所在的位置。现在原点在100,100。


现在我们将先平移再缩放。请注意,原点与上一张图片中的位置相同,只不过每个东西都变大了两倍。

这里输入图片的描述

http://jsfiddle.net/simonsarris/4uaZy/2/

嘭。原点仍然在100,100。但是所有的东西都被膨胀了两倍。先改变原点位置,然后在原地扩大所有东西。


现在让我们倒序看它们。这次我们首先缩放,所以一开始每件事物都变胖了: enter image description here http://jsfiddle.net/simonsarris/4uaZy/3/ 所有内容都被膨胀了2倍。原点在0,0处,即起始点。
现在我们先进行缩放,然后进行平移。 enter image description here http://jsfiddle.net/simonsarris/4uaZy/4/ 我们仍然沿着100,100的方向平移,但实际像素中原点已经移动到了200,200。与之前的两幅图进行比较。
这是因为任何发生在缩放之后的操作都必须进行缩放,包括其他转换。因此,在缩放的画布上进行(100,100)的变换会导致它移动200,200。
要记住的关键是,改变变换会影响从那时起如何绘制(或转换!)的东西。如果你将x2缩放,然后平移,平移将是x2。
如果您想在数学上看到每个步骤发生了什么,我鼓励您查看此处的代码: https://github.com/simonsarris/Canvas-tutorials/blob/master/transform.js 这模拟了画布所做的整个变换过程,并让您看到以前的变换如何修改后面的变换。

非常好的解释。现在看起来如此明显 :) - DougN
好的,还有些地方不太明白。看看这个:http://jsfiddle.net/sdJ7v/1/ 试错法帮助我将蓝色圆形置于绿色圆形中心。但是根据坐标来看,这种偏移是说不通的。不确定 transform 是如何应用的... - DougN
1
请查看我的评论:http://jsfiddle.net/simonsarris/sdJ7v/2/。这样说通吗? - Simon Sarris
换句话说,这个变换永久性地改变了原点,并且比例永久性地应用于任何新的计算,因此“-25,-25”变成了“-50,-50”,由于原点实际上在200,200处,所以它最终被绘制在真正的150,150处。 - Simon Sarris
1
所以画布基本上是反向应用变换的。 "先平移再缩放"实际上是先缩放,然后再平移。 "先缩放再平移"实际上是先平移,然后再缩放。 - Calmarius
@Calmarius:是的,你可以这样看。我在下面的回答中详细阐述了这一点。 - undefined

2

缩放和旋转是相对于原点进行的,因此如果您的变换具有平移,那么这将使顺序变得重要。

这里有一篇不错的文章: 为什么变换顺序很重要


糟糕,我说错了,应该是“翻译”而不是“转换”。已经修正。我读了这篇文章,但仍然不明白。什么意思是“缩放是相对于原点进行的”?如果我将所有东西按50%缩放,原点在哪里有什么关系吗? - DougN
1
@DougN 这很重要,因为如果物体缩小或放大,它们会围绕平面上的一个单点缩小或放大。如果该点位于您的画布中心,则50%缩放就像“取消缩放”。如果该点位于左上角,则画布中的所有内容都将向该点移动50%。如果它在可见区域之外,则您正在查看的所有内容可能会随着其向该点移动50%而移动到屏幕外。换句话说,只有原始像素是纯粹缩放的,而其余部分相对于起始位置缩小且移动。 - Peter Hansen

0
在Simon Sarris出色的回答基础上,我想解释一下我个人觉得最困惑的地方,那就是HTML规范中的示例
引用: 转换必须按照相反的顺序进行。
例如,如果将一个将宽度加倍的缩放变换应用于画布,然后再应用一个将绘图操作旋转四分之一圈的旋转变换,然后在画布上绘制一个宽度是高度两倍的矩形,实际结果将是一个正方形。
从一个40x20的矩形开始:

enter image description here https://jsfiddle.net/mhsmith/p6nLo9d4/2/

显然,添加ctx.scale(2, 1)使其变为80x20。

enter image description here https://jsfiddle.net/mhsmith/p6nLo9d4/4/

你可能会认为添加一个四分之一的旋转(ctx.rotate(Math.PI / 2))会将矩形旋转成20x80的形状。但实际上,它会变成一个正方形!

enter image description here https://jsfiddle.net/mhsmith/p6nLo9d4/5/

这是因为旋转受到比例的影响。为了形象化说明这一点,以下是上述三幅图像在原点周围画圆的效果:

       

https://jsfiddle.net/mhsmith/p6nLo9d4/8/

缩放将圆变成椭圆,而随后的旋转则围绕该椭圆的边缘进行,而不是围绕原始圆进行。因此,当X轴从指向右侧旋转到指向下方时,它被压缩了2倍。当Y轴从指向下方旋转到指向左侧时,它被扩展了2倍。最终结果是80x20的矩形变成了40x40的正方形。

有两种思考一系列变换的方式:

  1. 想象它们发生在坐标轴上,按照它们在代码中出现的顺序进行,每一步都与前一步的坐标轴进行比较;或者
  2. 想象它们发生在图像上,按照代码中出现的相反顺序进行,每一步都与原始坐标轴进行比较。

这个答案和Simon Sarris的答案都是以第一种方式编写的。HTML规范是以第二种方式编写的,我认为这种方式更容易形象化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接