【问题标题】:dojox.gfx.Moveable convert screen coordinates to world coordinates for draggingdojox.gfx.Moveable 将屏幕坐标转换为世界坐标用于拖动
【发布时间】:2017-12-28 08:27:10
【问题描述】:

tl;博士 我将如何使用返回的 CTM:

var ctm = canvas.rawNode.getScreenCTM();

修改屏幕坐标中的dx, dy 向量,使其位于世界坐标中?即{ dx: 1, dy: 0} 应该变成{ dx: 3.6, dy: 0} 给定上面的 SVG 示例,其中 viewBox 0 0 1800 1800 在一个 500 像素宽的窗口中。

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

  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 节点位于将其缩放到窗口的文档中 大小,大约 500px 宽所以 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});

最后一个参数作为shift 参数传递给dojox/gfx/Moveable.onMoving,可能是例如{ 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”对象,使其永远不会将形状移动到指定边界之外。”,这似乎是修改 @ 的好点987654335@ 对象,所以我接下来的尝试声明了一种新类型的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鼠标移动过?

【问题讨论】:

    标签: svg matrix draggable coordinate-transformation dojox.gfx


    【解决方案1】:

    我得到了一个工作示例,仅从 DOMMatrix 中提取 ad 填充 Matrix2Dxxyy 元素:https://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 属性时过于热心,试图使用所有元素来填写我的Matrix2Dxyyx 等元素,以用作转换矩阵的基础使用在鼠标移动向量上。我发现文档https://developer.mozilla.org/en-US/docs/Web/API/DOMMatrix 很难理解,因为它没有在网格中布置矩阵元素,所以我认为 a、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/pen/BJWEZw

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多