dojox.gfx.Moveable конвертировать экранные координаты в мировые координаты для перетаскивания

ТЛ; 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,

Я пытался использовать матричные преобразования, чтобы получить Screen CTM SVG (который входит в объект { a, b, c, d, e, f }) и использовать его как dojox/gfxMatrix2D ({ xx, xy, dx, yx, yy, dy }) используя прямые матричные операции. Цель состоит в том, чтобы изменить shift объект, чтобы преобразовать единицы экрана в мировые единицы, прежде чем он будет использован в матрице преобразования формы, но оказался очень запутанным. Для начала у CTM, кажется, есть большой dy приблизительно 50, который немедленно заставляет форму стрелять от основания экрана. Вот моя последняя очень грязная попытка: https://codepen.io/neekfenwick/pen/EoWNOb

Я могу вручную взять значения шкалы x и y CTM и применить их к объекту сдвига: https://codepen.io/neekfenwick/pen/KZWapa

Как можно использовать матричные операции, такие как Matrix2D.invert() а также Matrix2D.multiplyPoint() взять систему координат SVG, создать матрицу преобразования для преобразования из экранных координат в мировые координаты и применить это к dx, dy, по которому двигалась мышь?

1 ответ

Я получил рабочий пример, взяв только a а также d от DOMMatrix заселение только xx а также yy элементы Matrix2D: 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 атрибуты, пытаясь использовать все элементы, чтобы заполнить xy, yx и т. д. элементы моего 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-эквивалента" в документах указывает, что это на самом деле какая-то матрица 4х4 (здесь я использую? Для неопределенного элемента, я не уверен, какими будут значения по умолчанию):

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

Так что я все еще в замешательстве, но, по крайней мере, есть решение, использующее Matrix2D операции.

Я также кратко попытался использовать чистые операции SVG для создания SVGPoint и преобразования его с помощью операций DOMMatrix, но матрица преобразования выходит со смещением 100 или 200, и я отказался от него: https://codepen.io/neekfenwick/pen/BJWEZw

Другие вопросы по тегам