Увеличить изображение до разрыва курсора при перемещении мыши
Это вопрос о следующем вопросе Как увеличить указатель мыши при использовании моего собственного гладкого скругления колесика мыши?
Я использую css-преобразования, чтобы увеличить изображение до указателя мыши. Я также использую свой собственный алгоритм гладкой прокрутки для интерполяции и предоставления импульса колесику мыши.
С помощью Bali Balo в моем предыдущем вопросе мне удалось получить 90% пути.
Теперь вы можете масштабировать изображение до указателя мыши, сохраняя при этом гладкую прокрутку, как показано в следующем примере JSFiddle:
http://jsfiddle.net/qGGwx/7/
Однако функциональность прерывается при перемещении указателя мыши.
Чтобы еще раз пояснить, если я увеличиваю изображение на одной колесике на колесико мыши, изображение будет приближено к правильному положению. Такое поведение продолжается для каждой отметки, которую я увеличиваю на колесико мыши, полностью, как предполагалось. Если, однако, после изменения масштаба, я перемещаю мышь в другую позицию, функциональность ломается, и я должен полностью уменьшить масштаб, чтобы изменить положение зума.
Предполагаемое поведение заключается в том, чтобы любые изменения положения мыши в процессе масштабирования были правильно отражены в увеличенном изображении.
Две основные функции, которые управляют текущим поведением, следующие:
self.container.on('mousewheel', function (e, delta) {
var offset = self.image.offset();
self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
if (!self.running) {
self.running = true;
self.animateLoop();
}
self.delta = delta
self.smoothWheel(delta);
return false;
});
Эта функция собирает текущую позицию мыши в текущем масштабе масштабированного изображения.
Затем он запускает мой гладкий алгоритм прокрутки, который приводит к следующей функции, вызываемой для каждой интерполяции:
zoom: function (scale) {
var self = this;
self.currentLocation.x += ((self.mouseLocation.x - self.currentLocation.x) / self.currentscale);
self.currentLocation.y += ((self.mouseLocation.y - self.currentLocation.y) / self.currentscale);
var compat = ['-moz-', '-webkit-', '-o-', '-ms-', ''];
var newCss = {};
for (var i = compat.length - 1; i; i--) {
newCss[compat[i] + 'transform'] = 'scale(' + scale + ')';
newCss[compat[i] + 'transform-origin'] = self.currentLocation.x + 'px ' + self.currentLocation.y + 'px';
}
self.image.css(newCss);
self.currentscale = scale;
},
Эта функция принимает значение шкалы (1-10) и применяет преобразования css, перемещая изображение с использованием источника преобразования.
Хотя это отлично работает для положения неподвижной мыши, выбранного при полном уменьшении изображения; как указано выше, он ломается, когда курсор мыши перемещается после частичного увеличения.
Огромное спасибо заранее всем, кто может помочь.
Ответы
Ответ 1
Прежде чем вы проверите эту скрипту; Я должен упомянуть:
Прежде всего, в вашем методе .zoom()
; вы не должны делиться на currentscale
:
self.currentLocation.x += ((self.mouseLocation.x - self.currentLocation.x) / self.currentscale);
self.currentLocation.y += ((self.mouseLocation.y - self.currentLocation.y) / self.currentscale);
потому; вы уже используете этот коэффициент при вычислении mouseLocation
внутри метода initmousewheel()
следующим образом:
self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
Итак, вместо этого; (в методе .zoom()
), вы должны:
self.currentLocation.x += (self.mouseLocation.x - self.currentLocation.x);
self.currentLocation.y += (self.mouseLocation.y - self.currentLocation.y);
Но (например) a += b - a
всегда будет выдавать b
, поэтому приведенный выше код равен:
self.currentLocation.x = self.mouseLocation.x;
self.currentLocation.y = self.mouseLocation.y;
:
self.currentLocation = self.mouseLocation;
Тогда, кажется, вам даже не нужно self.currentLocation
. (2 переменные для одного и того же значения). Итак, почему бы не использовать переменную mouseLocation
в строке, где вы установили transform-origin
вместо этого и избавиться от переменной currentLocation
?
newCss[compat[i] + 'transform-origin'] = self.mouseLocation.x + 'px ' + self.mouseLocation.y + 'px';
Во-вторых,, вы должны включить прослушиватель событий mousemove
в метод initmousewheel()
(как и другие разработчики здесь), но он должен постоянно обновлять преобразование, а не только когда пользовательские колеса. В противном случае кончик указателя никогда не догонит, пока вы увеличиваете "любую" случайную точку.
self.container.on('mousemove', function (e) {
var offset = self.image.offset();
self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
self.zoom(self.currentscale);
});
Итак, вам больше не нужно будет вычислять это в обработчике событий mousewheel
, поэтому ваш метод initmousewheel()
будет выглядеть следующим образом:
initmousewheel: function () {
var self = this;
self.container.on('mousewheel', function (e, delta) {
if (!self.running) {
self.running = true;
self.animateLoop();
}
self.delta = delta;
self.smoothWheel(delta);
return false;
});
self.container.on('mousemove', function (e) {
var offset = self.image.offset();
self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
self.zoom(self.currentscale); // <--- update transform origin dynamically
});
}
Один выпуск:
Это решение работает так, как ожидалось, но с небольшой проблемой. Когда пользователь перемещает мышь на обычной или быстрой скорости; событие mousemove
, похоже, пропустит окончательную позицию (проверено в Chrome). Таким образом, масштабирование будет немного ниже местоположения указателя. В противном случае, когда вы двигаете мышь медленно, она получает точную точку. Это должно быть легко обойти это, хотя.
Другие примечания и предложения:
- У вас есть свойство duplicate (
prevscale
).
- Я предлагаю вам всегда использовать JSLint или JSHint (который доступен на
jsFiddle тоже), чтобы проверить ваш код.
- Я настоятельно рекомендую вам использовать закрытие (часто называемое Expression Expression Function Expression (IIFE)), чтобы избежать возможности глобального охвата; и скрыть ваши внутренние/частные свойства и методы.
Ответ 2
Собственно, не слишком сложно. Вам просто нужно отделить логику обновления местоположения мыши от логики обновления масштабирования. Посмотрите мою скрипку:
http://jsfiddle.net/qGGwx/41/
Все, что я сделал здесь, это добавить слушателя 'mousemove' в контейнер и поместить там логику обновления self.mouseLocation. Поскольку он больше не требуется, я также извлек логику обновления mouseLocation из обработчика "mousewheel". Код анимации остается прежним, как и решение о начале/остановке цикла анимации.
здесь код:
self.container.on('mousewheel', function (e, delta) {
if (!self.running) {
self.running = true;
self.animateLoop();
}
self.delta = delta
self.smoothWheel(delta);
return false;
});
self.container.on('mousemove', function (e) {
var offset = self.image.offset();
self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
});
Ответ 3
Добавьте метод mousemover
и вызовите его в методе init
:
mousemover: function() {
var self = this;
self.container.on('mousemove', function (e) {
var offset = self.image.offset();
self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
self.zoom(self.currentscale);
});
},
Fiddle: http://jsfiddle.net/powtac/qGGwx/34/
Ответ 4
Точка масштабирования не совсем правильная из-за масштабирования изображения (0.9
в ratio
). Фактически мышь указывает в частности точку в container
, но мы масштабируем image
. См. Этот скрипт http://jsfiddle.net/qGGwx/99/ Я добавляю marker
с позицией, равной transform-origin
. Поскольку вы видите, что размер изображения равен размеру контейнера, проблем нет. Вам нужно это масштабирование? Может быть, вы можете добавить второй контейнер? В скрипке я также добавил условие в mousemove
if(self.running && self.currentscale>1 && self.currentscale != self.lastscale) return;
Это предотвращает перемещение изображения во время масштабирования, а также создает проблему. Вы не можете изменить точку масштабирования, если zoom
все еще работает.
Ответ 5
Расширение ответа @jordancpaul Я добавил константу mouse_coord_weight
, которая умножается на дельту координат мыши. Это направлено на то, чтобы преобразование трансфокации было менее восприимчивым к изменению координат мыши. Проверьте http://jsfiddle.net/7dWrw/
Я переписал обработчик событий onmousemove
как:
self.container.on('mousemove', function (e) {
var offset = self.image.offset();
console.log(offset);
var x = (e.pageX - offset.left) / self.currentscale,
y = (e.pageY - offset.top) / self.currentscale;
if(self.running) {
self.mouseLocation.x += (x - self.mouseLocation.x) * self.mouse_coord_weight;
self.mouseLocation.y += (y - self.mouseLocation.y) * self.mouse_coord_weight;
} else {
self.mouseLocation.x = x;
self.mouseLocation.y = y;
}
});