2D Масштабирование и перемещение
Здравствуйте!
У меня задача сделать масштабирование при помощи колесика мыши на холсте SVG. Причем масштабирование делается через точку, которая в момент действия находится под курсором мыши. Ну, аналогично как это сделано в векторных редакторах. Проблема в том, что работает это, но плохо. Сначала нормально, а потом точка масштабирования не совпадает с точкой курсора мыши. Вот код: // Единичная матрица var matrixPrevious = Ext.create("Ext.draw.Matrix", 1, 0, 0, 1, 0, 0); me.getEl().on("mousewheel", function(e) { // Здесь по событию от колесика мыши выбирается коэффициент масштабирования var scale = e.event.wheelDelta > 0 ? 1.2 : 0.8; // Создаю матрицу масштабирования var matrixScale = Ext.create("Ext.draw.Matrix", scale, 0, 0, scale, 0, 0); // Вычисляю координаты курсора мыши относительно холста SVG x = e.pageX - me.getX(); y = e.pageY - me.getY(); // Вычисляю смещение относительно мыши и необходимого положения масштабируемого изображения var offsetX = x * (1 - scale); var offsetY = y * (1 - scale); // Создаю матрицу перемещения var matrixTranslate = Ext.create("Ext.draw.Matrix", 1, 0, 0, 1, offsetX, offsetY); // Беру предыдущую матрицу var matrixResult = matrixPrevious; // Все матрицы соединяю умножением matrixResult.multiply(matrixTranslate); matrixResult.multiply(matrixScale); // Применяю матрицу к элементу SVG-холста me.getSurface().matrix(matrixResult); // Сохраняю матрицу как предыдущую, чтобы в следующей итерации ее использовать // для относительных трансформаций matrixPrevious = matrixResult; }); У меня есть подозрения, что масштабирования я сделал относительное, а вот перемещение похоже не совсем относительное. Но как это исправить пока не знаю. |
Может лучше использовать snap.svg для этой цели?
http://jsfiddle.net/AGq9X/5/ http://snapsvg.io/docs/#Matrix.scale |
Но это ведь не отменяет создание матрицы?
|
Что-то непонятно, что здесь происходит.
// Вычисляю координаты курсора мыши относительно холста SVG /* Вот здесь получаются реальные (экранные) пиксели. А дальше я не вижу, чтобы ты их переводил в свои сабпиксели (то есть, ты не учитываешь уже существующее масштабирование) */ x = e.pageX - me.getX(); y = e.pageY - me.getY(); /* Вот где-то здесь тебе надо бы x и у умножить на текущий scale */ // Вычисляю смещение относительно мыши и необходимого положения масштабируемого изображения var offsetX = x - x * scale; var offsetY = y - y * scale; |
А как их переводить? У меня когда изначально масштаб 1:1 стоит, то пиксель изображения равен пикселу экрана. А вот когда накладывается transform, то уже они меняются.
Вот куда текущий scale приложить так и не понял. |
Я взял формулу отсюда http://xiper.net/learn/svg/svg-essen...a-center-point
но там расписано как смасштабировать один раз. А что делать, когда надо потом (колесико мыши крутится же дальше) еще раз смасштабировать? Я думал что нужно просто умножать новую матрицу на существующую. |
khusamov, если вы в точности придерживаетесь того, что там описываете, то для масштабирования при прокрутке вам нужно завести отдельную переменную для scale, в которой хранится текущее значение масштабирования. При прокрутке колесика вы:
1) прибавляете к текущему значению scale deltaWheel (scale += deltaWheel) 2) масштабируете оригинальное изображение с текущим (только что записанным) значением scale |
У меня для этой цели заведена специальная матрица. Она сначала пустая (нули для смещений, и 1-ки для масштаба). А потом приращения масштаба туда записываются.
var matrixPrevious = Ext.create("Ext.draw.Matrix", 1, 0, 0, 1, 0, 0); |
khusamov, дайте пример? Где-нить здесь.
http://jsfiddle.net/ |
Я готовлю пример. Там у меня куча моих классов. Надо как-то их все разместить.
|
Вот это место. Вы вычисляете смещение С ТЕКУЩИМ scale'ом. А масштабирующий scale может отличаться, поскольку является суммой нескольких предыдущих.
// Вычисляю смещение относительно мыши и необходимого положения масштабируемого изображения var offsetX = x - x * scale; var offsetY = y - y * scale; |
Выложил код тут https://fiddle.sencha.com/#fiddle/kr9
Если не запустится автоматом, то нужно зеленую кнопку жать. Появится звезда. Ее можно масштабировать колесиком мыши. Сразу будет видна проблема масштабирования - курсор не совпадает с точкой на фигуре во время масштабирования. Требуемый код находится в файле app.js на строке 119 |
Цитата:
var offsetX = x - x * matrixPrevious.getScaleX(); Ничего путного не выходит. |
На языке матриц попробую изложить свою проблему.
У меня есть фигура. Нужно ее масштабировать относительно центра. У меня есть готовая матрица для масштабирования относительно центра, обозначу ее буквой М1 Фигуру обозначу буквой Ф1 Итого, чтобы масштабировать фигуру мне нужно сделать следующее: Ф2 = Ф1 * М1 Я получаю новые координаты Ф2 Дело в том, что я эти координаты не сохраняю. Движок отображения работает так: в фигуре хранятся координаты Ф1 и сама матрица М1. Чтобы мне масштабировать фируру дальше, нужно создать вторую матрицу М2 и сделать следующую операцию М3 = М1 * М2 Ф3 = Ф1 * М2 Ф3 это координаты фигуры уже послу двух операций масштабирования. Внимание, проблема. Матрицу масштабирования я без ошибок создаю с учетом, что масштабирование делается относительно определенного центра. Если я выше описанный цикл операций масштабирования произвожу без смены центра, то все в порядке. Но если на какой-либо итерации меняется центр, то происходят проблемы (по условиям задачи это требуется). В итоге, получается я неправильно создаю матрицу когда центр меняется. |
Тема временно закрыта. Оказывается проблема не в моем коде, а в работе SVG.
Дело в том, что если на плоскости есть квадрат, и сделать сначала перенос его таким образом, чтобы ближайший к началу координат угол совпал с началом координат, а затем повернуть, то: а) в учебниках по матрицам квадрат должен развернуться вокруг начала координат б) а в SVG он вращается вокруг точки -x, -y (где x, y та точка квадрата что совпала с началом координат после перемещения). То есть точка вращения тоже переместилась!!! Вот отсюда все мои проблемы и исходят. А код похоже верный. Сейчас читаю спецификацию SVG и пытаюсь понять как это вообще произошло, можно ли это отключить, а если нет, то надо как-то по-другому считать. |
Продолжение тут http://javascript.ru/forum/showthrea...595#post365595
|
имхо 1 проблема в логике (т.е. непонимании)
имхо 2 всем будет лень разбираться в чужой логике не совсем понятно зачем использовать матрицу трансформации для простого маштабирования |
Я решил проблему. Описание тут http://javascript.ru/forum/offtopic/...tml#post365595
Кому надо будет - тот разберется. |
Часовой пояс GMT +3, время: 16:03. |