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?