TL; dr Как бы я использовал 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 находится в документе, который масштабируется по размеру окна, шириной около 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, где Юджин говорит: «Переопределите onMoving для вашего объекта и измените объект «shift», чтобы он никогда не перемещал фигуру за пределы указанных границ». изменить объект shift
, поэтому мои следующие попытки объявляют новый тип dojox/gfx/Moveable
и переопределяют onMoving
.
Я попытался использовать матричные преобразования, чтобы получить экран CTM SVG (который входит в объект { a, b, c, d, e, f }
) и использовать его как dojox/gfx
Matrix2D
({ xx, xy, dx, yx, yy, dy }
), используя прямые матричные операции. Цель состоит в том, чтобы изменить объект shift
, чтобы преобразовать единицы экрана в мировые единицы, прежде чем он будет использоваться в матрице преобразования формы, но я очень запутался. Для начала кажется, что CTM имеет большой dy около 50, что сразу же заставляет форму вылетать из нижней части экрана. Вот моя последняя очень грязная и неудачная попытка: https://codepen.io/neekfenwick/pen/EoWNOb а>
Я могу вручную взять значения шкалы CTM x и y и применить их к объекту сдвига: https://codepen.io/neekfenwick/pen/KZWapa
Как можно использовать матричные операции, такие как Matrix2D.invert()
и Matrix2D.multiplyPoint()
, чтобы взять систему координат SVG, произвести матрицу преобразования для преобразования экранных координат в мировые координаты и применить это к dx,dy, по которым перемещалась мышь?