HTML5 Canvas - 放大一个点

标签 html svg html5-canvas

所以我知道这里已经有关于它的线程,例如 that one 。 我遵循了上面线程中提出的想法,并且它有效。但是,我不明白为什么它会起作用。

这是一个例子:

假设我有一个以 (100, 100) 为中心的正方形,其宽度/高度为 100。因此它的左上角将位于 (50, 50)。

现在假设我要将 X2 放大到正方形的中心,即放大到 (100, 100)。所以我将编写以下转换序列:

translate(100, 100);
scale(2, 2);
translate(-100, -100);

因此,因为 Canvas 以相反的顺序应用变换,所以变换后的正方形的左上角现在将位于 (0, 0),并且其高度/宽度将为 200。

好吧,假设现在我想将 X2 缩放到已经变换的正方形的右下角。直观上,我想执行以下转换序列:

translate(200, 200);
scale(2, 2);
translate(-200, -200);

但它不会工作,因为 Canvas 再次以相反的顺序应用变换。也就是说,如果我将两个转换序列相加,我将得到:

// First Sequence
translate(100, 100);
scale(2, 2);
translate(-100, -100);

// Second Sequence
translate(200, 200);
scale(2, 2);
translate(-200, -200);

这意味着第二个序列将应用于第一个序列之前的每个点(因为 Canvas 将从下到上应用变换),这是错误的。因此,正如上面链接中的线程建议的那样:

因为序列 2 将首先应用,所以我应该通过应用第一个序列的逆来将点 (200, 200) 转换为其原始坐标。也就是说,如果T1是表示第一个序列的矩阵,那么它将如下所示:

// First Sequence
translate(100, 100);
scale(2, 2);
translate(-100, -100);

// Second Sequence
var point = SVGPoint(200, 200);
var transformedPoint = point.matrixTransform(T1.inverse());
translate(-transformedPoint.x, -transformedPoint.y);
scale(2, 2);
translate(transformedPoint.x, transformedPoint.y);

但是为什么它有效呢?我真的不明白为什么它应该这样工作...任何人都可以详细说明吗?

谢谢!

最佳答案

HTML5 Canvas 转换是自上而下进行的,而不是您所认为的自下而上的。造成这种区别的原因是因为应用于 Canvas 的变换会影响坐标系,而不是逻辑坐标。

通过 translate(100, 100) 进行翻译会左右移动坐标系,这与上下移动逻辑坐标非常相似。

让我们看第一个序列(我已将 transform 的使用更改为 translate):

translate(100, 100);
scale(2, 2);
translate(-100, -100);

自然地,当我们想要从中心缩放对象时,我们会将对象平移到 (0,0),缩放对象,然后将对象向后移动。上面的代码,当反向阅读时,似乎就是这样做的。然而,事实并非如此。

当我们从上到下阅读上面的代码时,它说(假设我们从身份转换开始):

  1. 将上下文的 (0,0) 向右移动 100 个单位并向下移动 100 个单位。这会将其带到 Canvas 的 (100,100) 位置。
  2. 将坐标系放大 2 倍。
  3. 将上下文的 (0,0) 向左移动 100 个单位并向上移动 100 个单位,实质上是将其返回到其原始位置(在上下文坐标空间中,而不是 Canvas 空间中)。

缩放是相对于上下文的 (0,0) 点进行的,该点位于 Canvas 上的 (100,100) 处。

如果我们现在添加您的第二个序列:

translate(200, 200);
scale(2, 2);
translate(-200, -200);

这将:

  1. 将上下文的 (0,0) 移动到坐标系的 (200,200) 位置。
  2. 使坐标系比原来大 2 倍。
  3. 将上下文的 (0,0) 返回到之前的位置(在上下文坐标空间中,而不是 Canvas 空间中)。

正如您所发现的,这并没有给您所期望的结果,因为 (200,200) 不是您想要缩放的点。请记住,所有单位都相对于上下文坐标系。因此,我们需要将 Canvas 位置(200,200)转换为上下文坐标位置(150,150),这是矩形的原始右下角。

因此我们将序列 #2 更改为:

translate(150, 150);
scale(2, 2);
translate(-150, -150);

这给了我们我们所期望的(放大矩形的右下角)。这就是我们进行逆变换的原因。

demo application ,当应用程序放大时,它会获取用户鼠标所在 Canvas 单位的坐标,使用迄今为止的上下文转换对其进行逆变换,以获取单击的上下文坐标空间中的位置。上下文原点移动到该位置,缩放,然后返回到之前的位置。

引用文献:

关于HTML5 Canvas - 放大一个点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16752984/

相关文章:

javascript - SVG - 更改比例后如何计算 x 和 y 坐标?

javascript - 有没有办法使用 SVG 渐变作为置换贴图的输入?

javascript - React组件将视频帧连续绘制到 Canvas : doesn't work on iOS

javascript - 调整图像大小以获得特定的最大值。文件大小

javascript - Canvas 下拉文本动画

html - Bootstrap 中的居中形式?

html - 在固定高度的框中显示具有可变高度内容的 3 列布局?

javascript - Fabric.js 基于svg的多重裁剪

javascript - 单击 select2 下拉菜单时获取更改框消息

javascript - jQuery 解析巨大的响应失败