0

tl; dr 我将如何使用以下返回的 CTM:

var ctm = canvas.rawNode.getScreenCTM();

修改dx, dy屏幕坐标中的矢量,使其位于世界坐标中?ie{ dx: 1, dy: 0}应该成为上面500px 宽窗口中{ dx: 3.6, dy: 0}带有 viewBox 的 SVG 示例。0 0 1800 1800

我认为以下方法会起作用:

  var ctm = canvas.rawNode.getScreenCTM();
  // Turn this into a dojox/gfx/matrix Matrix2D
  var ctmm = new matrix.Matrix2D({xx: ctm.a, xy: ctm.b, dx: ctm.c,
                                  yx: ctm.d, yy: ctm.e, dy: ctm.f});
  // Invert this
  var itm = matrix.invert(ctmm);
  // Multiply screen coords by transform matrix
  var worldshift = matrix.multiplyPoint(itm, shift.dx, shift.dy);
  console.log('ctm ', ctm, ', shift ', shift, ' became worldshift ', worldshift);
  shift.dx = worldshift.x;
  shift.dy = worldshift.y;

itm出来的时候充满了 NaN 和 Infinity。

CodePen 示例后面是长版问题

我知道这背后的基本数学,但发现自己很难用矩阵变换来做这件事。文档似乎避免了这个主题。情况是:

  • SVG 节点具有定义世界坐标的 viewBox,例如 0,0 到 1800,1800
  • SVG 节点位于将其缩放到窗口大小的文档中,大约 500 像素宽因此 SVG 中的世界坐标(1800 x 1800 单位)不会 1:1 映射到屏幕坐标。每个像素跨度为 1800/500 = 3.6 世界单位
  • dojox/gfx/Moveable 使用 dojox/gfx/Mover ,它的 onMouseMove函数传递了它在屏幕坐标中移动的量:

    this.host.onMove(this, {dx: x - this.lastX, dy: y - this.lastY});

dojox/gfx/Moveable.onMoving最后一个参数作为参数传入shift,如果鼠标向右移动一个像素,则可能是例如 { dx: 1, dy: 0 }。

如果我们愚蠢地允许框架将其应用于被拖动形状的平移变换,则其位置与鼠标坐标不完全匹配:https ://codepen.io/neekfenwick/pen/RxpoMq (这在 dojox 演示中运行良好因为它们的 SVG 坐标系与屏幕坐标系 1:1 匹配)。

我在http://grokbase.com/t/dojo/dojo-interest/08anymq4t9/gfx-constrainedmoveable找到了一些灵​​感,其中 Eugene 说“在你的对象上覆盖 onMoving 并修改“shift”对象,因此它永远不会将形状移出一个指定的边界。”,这似乎是修改shift对象的一个​​好点,所以我接下来的尝试声明了一个新的类型dojox/gfx/Moveable和覆盖onMoving

我尝试使用矩阵转换来获取 SVG 的 Screen CTM(它位于 的对象中)并使用直接矩阵运算{ a, b, c, d, e, f }将其用作dojox/gfx Matrix2D( )。{ xx, xy, dx, yx, yy, dy }目的是在将shift对象用于形状的变换矩阵之前修改对象以将屏幕单位转换为世界单位,但发现自己很困惑。一开始,CTM 似乎有一个大约 50 的大 dy,这立即使形状从屏幕底部射出。这是我最新的非常混乱和破碎的尝试:https ://codepen.io/neekfenwick/pen/EoWNOb

我可以手动获取 CTM 的 x 和 y 比例值并将它们应用于 shift 对象:https ://codepen.io/neekfenwick/pen/KZWapa

如何使用矩阵运算,例如Matrix2D.invert()Matrix2D.multiplyPoint()获取 SVG 的坐标系,生成一个转换矩阵以从屏幕坐标转换为世界坐标,并将其应用于鼠标移动的 dx,dy?

4

1 回答 1

0

我得到了一个工作示例,仅从a填充dDOMMatrixxx元素yy中获取Matrix2Dhttps ://codepen.io/neekfenwick/pen/mpWgrO

 var MyMoveable = declare(Moveable, {
    onMoving: function(/* dojox/gfx/Mover */ mover, /* Object */ shift){
      // console.log('mover ', mover, ' shift ', shift);
      // shift comes in screen coordinates
      // Get the Screen Coordinate Transform Matrix
      var ctm = canvas.rawNode.getScreenCTM();
      // Turn this into a dojox/gfx/matrix Matrix2D
      var ctmm = new matrix.Matrix2D({xx: ctm.a, yy: ctm.d});
      // Invert this
      var itm = matrix.invert(ctmm);
      // Multiply screen coords by transform matrix
      var worldshift = matrix.multiplyPoint(itm, shift.dx, shift.dy);
      console.log('ctm ', ctm, ', shift ', shift, ' became worldshift ', worldshift);
      // Replace the shift dx,dy vector with the transformed coordinates
      shift.dx = worldshift.x;
      shift.dy = worldshift.y;
    }
  });

这样,红色圆圈与鼠标光标同步移动。

看起来我在使用DOMMatrix属性时过于热心,试图使用所有元素来填充我的xy, yxetc 元素,Matrix2D以用作转换矩阵的基础,以用于鼠标移动矢量。我发现文档https://developer.mozilla.org/en-US/docs/Web/API/DOMMatrix很难理解,因为它没有在网格中布置矩阵元素,所以我想, b、c、d、e、f 被简单地布置在 3x3 网格中:

{ a, b, c,
  d, e, f,
  0, 0, 1 }

然而,文档的“3D 等效”部分表明它实际上是某种 4x4 矩阵(这里我使用 ? 表示未指定的元素,我不确定默认值是什么):

{ a, b, ?, ?,
  c, d, ?, ?,
  ?, ?, ?, ?,
  e, f, ?, ? }

所以我仍然很困惑,但至少有一个使用Matrix2D操作的解决方案。

我还尝试使用纯 SVG 操作来创建一个 SVGPoint 并使用 DOMMatrix 操作对其进行转换,但是转换矩阵的偏移量为 100 或 200,我已经放弃了:https ://codepen.io/neekfenwick /笔/BJWEZw

于 2017-12-29T09:52:58.967 回答