2013-05-25 75 views
2

所以我知道这里有线程已经在这里,如that one。 我遵循了上述线程中提出的想法,并且工作正常。但是,我不明白它为什么起作用。HTML5帆布 - 放大点

下面是一个例子:

假设我在(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); 

但它不会工作,因为再次,在画布上以相反的顺序适用transfomations。也就是说,如果我总结一下我的两个转变序列,我会得到:

// 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); 

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

谢谢!

回答

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个单位,基本上将其返回到原始位置(在上下文坐标空间中,而不是画布空间中)。

缩放发生在上下文的(0,0)点上,该点位于画布上的(100,100)处。

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

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

这将:

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

正如你已经发现的那样,这并不会给你你所期待的,因为(200,200)不是你想要缩放的点。请记住,所有单位都与上下文坐标系有关。所以我们需要将(200,200)的画布位置转换为(150,150)的上下文坐标位置,它是矩形的原始右下角。

所以我们改变序列#2为:

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

这给了我们什么,我们期待(以放大矩形的右下角)。这就是我们进行逆变换的原因。

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

参考文献:

+0

嗨!谢谢,这是一个很好的解释,它帮助我在应用于坐标系时查看转换的情况。但是在我接受这个答案之前,我仍然有一些东西缺失 - 我想请求你更深入地研究它 - 实际上,画布实现DO使用变换矩阵对逻辑点本身应用变换 - [请继续阅读下一条评论] – gipouf

+0

这些转换以相反的顺序应用,为了给你一个错觉,即当以原始顺序查看转换时,它们将在坐标系上工作。我在这里吗?这是困扰我的主要问题。它们以相反的顺序被应用,因为画布的当前变换矩阵与用户应用的每个新变换后乘 - 因此在实践中,每个逻辑点将首先用用户应用的最后一个变换进行变换。 [原文如下] – gipouf

+0

所以,我最初的问题是为什么这个演示的工作原理,如果我会试图解释它如何真正实现画布(以相反的顺序应用到每个点的转换) 。从这个观点来看,我很困惑。你明白我的意思吗? :) 或者我可能不知道画布是如何工作的,而我完全误导了自己。 **如果可能的话,我会很高兴与您聊天,所以我们不会进入漫长的评论。(我现在给你一个投票权)** – gipouf

1

你似乎正在改变方式overhinking!

这里有一个简单的原则:

如果应用任何变换集,则必须取消所有的人,如果你想回到你的未转化的状态。

期限!

所以我们说你做这4种转换:

  • 做#1。 context.translate(100,100);
  • 做了#2。 context.scale(2,2);
  • 做#3。 context.translate(-20,50);
  • 做#4。上下文。刻度(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);

认为它像走到你的朋友家。

您右转+左+右。

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

您必须撤消原来的步行路程的完全相反的步行道。

这也是如何转换的工作。

这就是为什么!

+0

呵呵..我想我们每个人都意味着别的东西3个员额在一排......大家可以去聊,所以我会澄清究竟是什么意思?如果你可以邀请我,这将是非常棒的。 再次感谢您的努力。 – gipouf