HTML5画布 - 缩放到一个点

时间:2013-05-25 19:06:03

标签: html5 svg html5-canvas

所以我知道这里有关于它的线索,比如that one。 我遵循上面的线程中提出的想法,它的工作原理。但是,我不明白为什么它有效。

以下是一个例子:

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

现在让我们说我想将X2放大到正方形的中心,也就是放大(100,100)。所以我将编写以下转换序列:

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

因为画布以相反的顺序应用变换,我变换后的方块的左上角现在为(0,0),其高度/宽度为200.

好吧,让我们说现在我想将X2放大到已经改造过的广场的右下角。如此直观地说,我想执行以下转换序列:

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

但它不会起作用,因为画布再次以相反的顺序应用变形。也就是说,如果我总结我的两个转换序列,我会得到:

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

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

这意味着第二个序列将应用于第一个序列之前的每个点(因为画布将从下到上应用转换),这是错误的。因此,上面链接中的主题提示如下:

因为序列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);

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

谢谢!

2 个答案:

答案 0 :(得分:3)

HTML5画布转换是自上而下发生的,而不是自下而上的。区别的原因是因为应用于画布的变换会影响坐标系,而不会影响逻辑坐标。

translate(100, 100)进行翻译会使您的坐标系向下和向下移动,这与向上和向左移动逻辑坐标非常相似。

让我们采取第一个序列(我已将transform更改为translate):

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

当然,当我们考虑从它的中心缩放对象时,我们将对象转换为(0,0),缩放对象,然后将对象移回。上面的代码,当反向阅读时,似乎会这样做。但事实并非如此。

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

  1. 将上下文的(0,0)向右移动100个单位,向下移动100个单位。这将它带到画布的(100,100)位置。
  2. 使坐标系大2倍。
  3. 将上下文(0,0)向左移动100个单位并向上移动100个单位,基本上将其返回到原始位置(在上下文坐标空间中,而不是画布空间)。
  4. 缩放相对于上下文的(0,0)点发生,在画布上为(100,100)。

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

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

    这将:

    1. 将上下文的(0,0)移动到坐标系的(200,200)位置。
    2. 使坐标系比现在大2倍。
    3. 将上下文(0,0)返回到之前的位置(在上下文坐标空间中,而不是画布空间)。
    4. 正如您所知,这并不能满足您的期望,因为(200,200)不是您想要扩展的关键点。请记住,所有单位都与上下文坐标系相关。所以我们需要将(200,200)的画布位置转换为(150,150)的上下文坐标位置,这是我们矩形的原始右下角。

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

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

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

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

      参考文献:

答案 1 :(得分:1)

你似乎想要改变变形!

这是一个简单的规则:

如果您应用任何一组变换,那么如果您想要恢复到未转换状态,则必须撤消所有变换。

期间!!!!

所以,假设你做了这4次转换:

  • 做#1。 context.translate(100,100);
  • 做#2。 context.scale(2,2);
  • 做#3。 context.translate(-20,50);
  • 做#4。 context.scale(10,10);

要返回原始未转换状态,必须以完全相反的顺序撤消:

  • 撤消#4:context.scale(0.10,0.10); //因为我们缩放了10倍,所以我们必须按比例缩小0.10
  • 撤消#3:context.translate(20,-50);
  • 撤消#2:context.scale(0.50,0.50); //因为我们缩放了2倍,所以我们必须缩小0.50
  • 撤消#1:context.translate(-100,-100);

想想就像走到朋友家一样。

你右转+左+右。

然后回家必须扭转:左+右+左

您必须完全按照原始步行的方向撤消步行路径。

这也是变换的工作原理。

这就是为什么!!