javascript - usar - el puntero del mouse se mueve solo mac
Zoom de la imagen al cursor se rompe cuando se mueve el ratón (5)
Agregue un método mousemover
y mousemover
en el método 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);
});
},
Esta es una pregunta de seguimiento sobre ¿Cómo hacer zoom al puntero del mouse mientras uso mi propia rueda de desplazamiento suave?
Estoy usando css transforms para acercar una imagen al puntero del mouse. También estoy usando mi propio algoritmo de desplazamiento suave para interpolar y dar impulso a la rueda del ratón.
Con la ayuda de Bali Balo en mi pregunta anterior, logré obtener el 90% del camino.
Ahora puede ampliar la imagen hasta el puntero del mouse mientras sigue teniendo un desplazamiento suave como lo ilustra el siguiente JSFiddle:
Sin embargo, la funcionalidad se interrumpe cuando se mueve el puntero del mouse.
Para aclarar aún más, si acerco una muesca en la rueda del mouse, la imagen se acerca a la posición correcta. Este comportamiento continúa para cada muesca que me acerque en la rueda del mouse, completamente según lo previsto. Sin embargo, si, después de acercar el zoom, muevo el mouse a una posición diferente, la funcionalidad se interrumpe y tengo que alejarme por completo para cambiar la posición del zoom.
El comportamiento previsto es que cualquier cambio en la posición del mouse durante el proceso de zoom se refleje correctamente en la imagen ampliada.
Las dos funciones principales que controlan el comportamiento actual son las siguientes:
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;
});
Esta función recopila la posición actual del mouse en la escala actual de la imagen ampliada.
Luego comienza mi algoritmo de desplazamiento suave que da como resultado que se llame a la siguiente función para cada interpolación:
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;
},
Esta función toma la cantidad de escala (1-10) y aplica las transformaciones css, reposicionando la imagen usando el origen de transformación.
Aunque esto funciona perfectamente para una posición estacionaria del mouse elegida cuando la imagen está completamente alejada; como se indicó anteriormente, se rompe cuando el cursor del mouse se mueve después de un zoom parcial.
Enormes gracias de antemano a cualquiera que pueda ayudar.
Antes de comprobar este violín hacia fuera; Debería mencionar:
En primer lugar , dentro de su método .zoom()
; No deberías dividir por currentscale
:
self.currentLocation.x += ((self.mouseLocation.x - self.currentLocation.x) / self.currentscale);
self.currentLocation.y += ((self.mouseLocation.y - self.currentLocation.y) / self.currentscale);
porque; ya usas ese factor al calcular la mouseLocation
del mouseLocation
dentro del método initmousewheel()
esta manera:
self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
Así que en vez; (en el método .zoom()
), deberías:
self.currentLocation.x += (self.mouseLocation.x - self.currentLocation.x);
self.currentLocation.y += (self.mouseLocation.y - self.currentLocation.y);
Pero (por ejemplo) a += b - a
siempre producirá b
por lo que el código anterior es igual a:
self.currentLocation.x = self.mouseLocation.x;
self.currentLocation.y = self.mouseLocation.y;
en breve:
self.currentLocation = self.mouseLocation;
Entonces, parece que ni siquiera necesitas una self.currentLocation
. self.currentLocation
. (2 variables para el mismo valor). Entonces, ¿por qué no usar la variable mouseLocation
en la línea donde establece el transform-origin
lugar de deshacerse de la variable currentLocation
?
newCss[compat[i] + ''transform-origin''] = self.mouseLocation.x + ''px '' + self.mouseLocation.y + ''px'';
En segundo lugar , debe incluir un mousemove
eventos mousemove
dentro del método initmousewheel()
(tal como lo sugieren otros desarrolladores aquí) pero debería actualizar la transformación continuamente, no solo cuando el usuario rueda. De lo contrario, la punta del puntero nunca se pondrá al día mientras esté alejando "cualquier" punto aleatorio.
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);
});
Asi que; no necesitarías calcular esto más dentro del controlador de eventos de mousewheel
, por lo que tu método initmousewheel()
se vería así:
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
});
}
Un problema:
Esta solución funciona como se esperaba pero con un pequeño problema. Cuando el usuario mueve el mouse a velocidad normal o rápida; mousemove
evento mousemove
parece perder la posición final (probado en Chrome). Así que el zoom será un poco fuera de la ubicación del puntero. De lo contrario, cuando mueves el mouse lentamente, obtendrás el punto exacto. Aunque debería ser fácil solucionar esto.
Otras notas y sugerencias:
- Tienes una propiedad duplicada (
prevscale
). - Le sugiero que siempre use JSLint o JSHint (que también está disponible en jsFiddle) para validar su código.
- Le sugiero que utilice cierres (a menudo denominados Expresión de función invocada inmediatamente (IIFE)) para evitar el alcance global cuando sea posible; y ocultar sus propiedades y métodos internos / privados.
El punto de zoom no es exactamente correcto debido a la escala de una imagen ( 0.9
en ratio
). De hecho, el ratón está apuntando en un punto particular en el container
pero la image
escala Ver este fiddle http://jsfiddle.net/qGGwx/99/ Añado un marker
con una posición igual a la transform-origin
. Como puede ver si el tamaño de la imagen es igual al tamaño del contenedor, no hay problema. ¿Necesita esta escala? Tal vez usted puede agregar segundo contenedor? En el violín también agregué condición en mousemove
if(self.running && self.currentscale>1 && self.currentscale != self.lastscale) return;
Eso impide que la imagen se mueva durante el zoom, pero también crea un problema. No puede cambiar el punto de zoom si el zoom
todavía se está ejecutando.
En realidad, no es demasiado complicado. Solo necesita separar la lógica de actualización de la ubicación del mouse de la lógica de actualización del zoom. Echa un vistazo a mi violín: http://jsfiddle.net/qGGwx/41/
Todo lo que he hecho aquí es agregar un oyente ''mousemove'' en el contenedor, y poner ahí la lógica de actualización self.mouseLocation. Como ya no es necesario, también saqué la lógica de actualización mouseLocation del controlador ''mousewheel''. El código de animación permanece igual, al igual que la decisión de cuándo iniciar / detener el ciclo de animación.
Aquí está el código:
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;
});
Extendiendo la respuesta de @jordancpaul, he agregado una constante mouse_coord_weight
que se multiplica al delta de las coordenadas del mouse. Esto tiene como objetivo hacer que la transición del zoom sea menos sensible al cambio en las coordenadas del mouse. Compruébelo en http://jsfiddle.net/7dWrw/
He reescrito el onmousemove
eventos onmousemove
como:
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;
}
});