saber programa posicion para las coordenadas javascript mousewheel

javascript - programa - Normalización de la velocidad del mouse en los navegadores



posicion del mouse javascript (10)

Aquí está mi loco intento de producir un delta coherente y normalizado de navegador cruzado (-1 <= delta <= 1):

var o = e.originalEvent, d = o.detail, w = o.wheelDelta, n = 225, n1 = n-1; // Normalize delta d = d ? w && (f = w/d) ? d/f : -d/1.35 : w/120; // Quadratic scale if |d| > 1 d = d < 1 ? d < -1 ? (-Math.pow(d, 2) - n1) / n : d : (Math.pow(d, 2) + n1) / n; // Delta *should* not be greater than 2... e.delta = Math.min(Math.max(d / 2, -1), 1);

Esto es totalmente empírico, pero funciona bastante bien en Safari 6, FF 16, Opera 12 (OS X) e IE 7 en XP

Para una pregunta diferente , compuse esta respuesta , incluido este código de muestra .

En ese código utilizo la rueda del mouse para acercar / alejar un lienzo HTML5. Encontré un código que normaliza las diferencias de velocidad entre Chrome y Firefox. Sin embargo, el manejo del zoom en Safari es mucho, mucho más rápido que en cualquiera de esos.

Aquí está el código que tengo actualmente:

var handleScroll = function(e){ var delta = e.wheelDelta ? e.wheelDelta/40 : e.detail ? -e.detail/3 : 0; if (delta) ... return e.preventDefault() && false; }; canvas.addEventListener(''DOMMouseScroll'',handleScroll,false); // For Firefox canvas.addEventListener(''mousewheel'',handleScroll,false); // Everyone else

¿Qué código puedo usar para obtener el mismo valor ''delta'' para la misma cantidad de ruedas del mouse en Chrome v10 / 11, Firefox v4, Safari v5, Opera v11 e IE9?

Esta pregunta está relacionada, pero no tiene una buena respuesta.

Editar : Investigaciones posteriores muestran que un evento de desplazamiento ''hacia arriba'' es:

| evt.wheelDelta | evt.detail ------------------+----------------+------------ Safari v5/Win7 | 120 | 0 Safari v5/OS X | 120 | 0 Safari v7/OS X | 12 | 0 Chrome v11/Win7 | 120 | 0 Chrome v37/Win7 | 120 | 0 Chrome v11/OS X | 3 (!) | 0 (possibly wrong) Chrome v37/OS X | 120 | 0 IE9/Win7 | 120 | undefined Opera v11/OS X | 40 | -1 Opera v24/OS X | 120 | 0 Opera v11/Win7 | 120 | -3 Firefox v4/Win7 | undefined | -3 Firefox v4/OS X | undefined | -1 Firefox v30/OS X | undefined | -1

Además, usar el trackpad de MacBook en OS X da resultados diferentes incluso cuando se mueve lentamente:

  • En Safari y Chrome, wheelDelta tiene un valor de 3 en lugar de 120 para la rueda del mouse.
  • En Firefox, el detail suele ser 2 , a veces 1 , pero cuando se desplaza muy lentamente NO HAY NINGÚN PROPÓSITO DE EVENTO .

Entonces la pregunta es:

¿Cuál es la mejor manera de diferenciar este comportamiento (idealmente sin ningún agente de usuario u olfateo de SO)?


Definitivamente no hay una forma sencilla de normalizar en todos los usuarios en todos los sistemas operativos en todos los navegadores.

Se pone peor que las variaciones enumeradas: en mi configuración de Windows XP + Firefox3.6, mi mouse hace 6 por cada desplazamiento de una sola muesca, probablemente porque en algún lugar he olvidado que aceleré la rueda del mouse, ya sea en el sistema operativo o en alguna parte: config

Sin embargo, estoy trabajando en un problema similar (con una aplicación similar por cierto, pero sin lienzo) y se me ocurre simplemente usando el signo delta de +1 / -1 y midiendo con el tiempo la última vez que disparó, lo harás. tener una tasa de aceleración, es decir. si alguien se desplaza una vez contra varias veces en unos momentos (lo que apostaría es cómo lo hace Google Maps).

El concepto parece funcionar bien en mis pruebas, solo agregue algo menos de 100ms a la aceleración.


Este es un problema con el que he estado luchando durante algunas horas hoy, y no por primera vez :(

He estado tratando de resumir los valores en lugar de "deslizar" y ver cómo los diferentes navegadores reportan valores, y varían mucho, con Safari informando órdenes de magnitud de mayor magnitud en casi todas las plataformas, Chrome informa bastante más (como 3 veces más) ) que Firefox, siendo Firefox equilibrado a largo plazo pero bastante diferente entre plataformas con pequeños movimientos (en Ubuntu gnome, casi solo +3 o -3, parece que resume eventos más pequeños y luego envía un gran "+3")

Las soluciones actuales encontradas en este momento son tres:

  1. El ya mencionado "usa solo el signo" que mata cualquier tipo de aceleración
  2. Busca el navegador hasta la versión secundaria y la plataforma, y ​​ajústalo correctamente
  3. Qooxdoo implementó recientemente un algoritmo de autoadaptación, que básicamente trata de escalar el delta en función del valor mínimo y máximo recibido hasta el momento.

La idea en Qooxdoo es buena, y funciona, y es la única solución que actualmente encuentro completamente cruzada.

Por desgracia, tiende a renormalizar también la aceleración. Si lo prueba (en sus demostraciones), y se desplaza hacia arriba y hacia abajo a la velocidad máxima durante un tiempo, notará que desplazarse extremadamente rápido o extremadamente lento básicamente produce casi la misma cantidad de movimiento. Por el contrario, si vuelves a cargar la página y solo deslizas muy lentamente, notarás que se desplazará bastante rápido ".

Esto es frustrante para un usuario de Mac (como yo) solía dar vigorosos deslizamientos de desplazamiento en el panel táctil y esperaba llegar a la parte superior o inferior de la cosa desplazada.

Aún más, dado que reduce la velocidad del mouse en función del valor máximo obtenido, cuanto más intente acelerarlo el usuario, más se ralentizará, mientras que un usuario de "desplazamiento lento" experimentará velocidades bastante rápidas.

Esto hace que esta solución (por lo demás brillante) sea una implementación ligeramente mejor de la solución 1.

Transmití la solución al plugin jquery mousewheel: http://jsfiddle.net/SimoneGianni/pXzVv/

Si juegas con él por un tiempo, verás que comenzarás a obtener resultados bastante homogéneos, pero también notarás que tiende a valores de + 1 / -1 bastante rápido.

Ahora estoy trabajando en mejorarlo para detectar mejor los picos, para que no envíen todo "fuera de escala". También sería bueno obtener un valor flotante entre 0 y 1 como valor delta, de modo que haya una salida coherente.


Hice una tabla con diferentes valores devueltos por diferentes eventos / navegadores, teniendo en cuenta el evento de wheel DOM3 que algunos navegadores ya soportan (tabla debajo).

Basado en eso hice esta función para normalizar la velocidad:

http://jsfiddle.net/mfe8J/1/

function normalizeWheelSpeed(event) { var normalized; if (event.wheelDelta) { normalized = (event.wheelDelta % 120 - 0) == -0 ? event.wheelDelta / 120 : event.wheelDelta / 12; } else { var rawAmmount = event.deltaY ? event.deltaY : event.detail; normalized = -(rawAmmount % 3 ? rawAmmount * 10 : rawAmmount / 3); } return normalized; }

Tabla para mousewheel , wheel y DOMMouseScroll :

| mousewheel | Chrome (win) | Chrome (mac) | Firefox (win) | Firefox (mac) | Safari 7 (mac) | Opera 22 (mac) | Opera 22 (win) | IE11 | IE 9 & 10 | IE 7 & 8 | |-------------------|--------------|--------------|---------------|---------------|----------------|----------------|----------------|-----------|-------------|-----------| | event.detail | 0 | 0 | - | - | 0 | 0 | 0 | 0 | 0 | undefined | | event.wheelDelta | 120 | 120 | - | - | 12 | 120 | 120 | 120 | 120 | 120 | | event.wheelDeltaY | 120 | 120 | - | - | 12 | 120 | 120 | undefined | undefined | undefined | | event.wheelDeltaX | 0 | 0 | - | - | 0 | 0 | 0 | undefined | undefined | undefined | | event.delta | undefined | undefined | - | - | undefined | undefined | undefined | undefined | undefined | undefined | | event.deltaY | -100 | -4 | - | - | undefined | -4 | -100 | undefined | undefined | undefined | | event.deltaX | 0 | 0 | - | - | undefined | 0 | 0 | undefined | undefined | undefined | | | | | | | | | | | | | | wheel | Chrome (win) | Chrome (mac) | Firefox (win) | Firefox (mac) | Safari 7 (mac) | Opera 22 (mac) | Opera 22 (win) | IE11 | IE 10 & 9 | IE 7 & 8 | | event.detail | 0 | 0 | 0 | 0 | - | 0 | 0 | 0 | 0 | - | | event.wheelDelta | 120 | 120 | undefined | undefined | - | 120 | 120 | undefined | undefined | - | | event.wheelDeltaY | 120 | 120 | undefined | undefined | - | 120 | 120 | undefined | undefined | - | | event.wheelDeltaX | 0 | 0 | undefined | undefined | - | 0 | 0 | undefined | undefined | - | | event.delta | undefined | undefined | undefined | undefined | - | undefined | undefined | undefined | undefined | - | | event.deltaY | -100 | -4 | -3 | -0,1 | - | -4 | -100 | -99,56 | -68,4 | -53 | - | | event.deltaX | 0 | 0 | 0 | 0 | - | 0 | 0 | 0 | 0 | - | | | | | | | | | | | | | | | | | | | | | | | | | | DOMMouseScroll | | | Firefox (win) | Firefox (mac) | | | | | | | | event.detail | | | -3 | -1 | | | | | | | | event.wheelDelta | | | undefined | undefined | | | | | | | | event.wheelDeltaY | | | undefined | undefined | | | | | | | | event.wheelDeltaX | | | undefined | undefined | | | | | | | | event.delta | | | undefined | undefined | | | | | | | | event.deltaY | | | undefined | undefined | | | | | | | | event.deltaX | | | undefined | undefined | | | | | | |


Nuestros amigos en Facebook armaron una gran solución a este problema.

¡He probado en una tabla de datos que estoy construyendo usando React y se desplaza como la mantequilla!

Esta solución funciona en una variedad de navegadores, en Windows / Mac, y ambos usan trackpad / mouse.

// Reasonable defaults var PIXEL_STEP = 10; var LINE_HEIGHT = 40; var PAGE_HEIGHT = 800; function normalizeWheel(/*object*/ event) /*object*/ { var sX = 0, sY = 0, // spinX, spinY pX = 0, pY = 0; // pixelX, pixelY // Legacy if (''detail'' in event) { sY = event.detail; } if (''wheelDelta'' in event) { sY = -event.wheelDelta / 120; } if (''wheelDeltaY'' in event) { sY = -event.wheelDeltaY / 120; } if (''wheelDeltaX'' in event) { sX = -event.wheelDeltaX / 120; } // side scrolling on FF with DOMMouseScroll if ( ''axis'' in event && event.axis === event.HORIZONTAL_AXIS ) { sX = sY; sY = 0; } pX = sX * PIXEL_STEP; pY = sY * PIXEL_STEP; if (''deltaY'' in event) { pY = event.deltaY; } if (''deltaX'' in event) { pX = event.deltaX; } if ((pX || pY) && event.deltaMode) { if (event.deltaMode == 1) { // delta in LINE units pX *= LINE_HEIGHT; pY *= LINE_HEIGHT; } else { // delta in PAGE units pX *= PAGE_HEIGHT; pY *= PAGE_HEIGHT; } } // Fall-back if spin cannot be determined if (pX && !sX) { sX = (pX < 1) ? -1 : 1; } if (pY && !sY) { sY = (pY < 1) ? -1 : 1; } return { spinX : sX, spinY : sY, pixelX : pX, pixelY : pY }; }

El código fuente se puede encontrar aquí: https://github.com/facebook/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js


Otra solución más o menos autónoma ...

Sin embargo, esto no lleva tiempo entre los eventos. Algunos navegadores parecen disparar siempre eventos con el mismo delta, y simplemente dispararlos más rápido al desplazarse rápidamente. Otros sí varían los deltas. Uno puede imaginar un normalizador adaptativo que tenga en cuenta el tiempo, pero que se involucrará de alguna manera y será difícil de usar.

Trabajando disponible aquí: jsbin/iqafek/2

var normalizeWheelDelta = function() { // Keep a distribution of observed values, and scale by the // 33rd percentile. var distribution = [], done = null, scale = 30; return function(n) { // Zeroes don''t count. if (n == 0) return n; // After 500 samples, we stop sampling and keep current factor. if (done != null) return n * done; var abs = Math.abs(n); // Insert value (sorted in ascending order). outer: do { // Just used for break goto for (var i = 0; i < distribution.length; ++i) { if (abs <= distribution[i]) { distribution.splice(i, 0, abs); break outer; } } distribution.push(abs); } while (false); // Factor is scale divided by 33rd percentile. var factor = scale / distribution[Math.floor(distribution.length / 3)]; if (distribution.length == 500) done = factor; return n * factor; }; }(); // Usual boilerplate scroll-wheel incompatibility plaster. var div = document.getElementById("thing"); div.addEventListener("DOMMouseScroll", grabScroll, false); div.addEventListener("mousewheel", grabScroll, false); function grabScroll(e) { var dx = -(e.wheelDeltaX || 0), dy = -(e.wheelDeltaY || e.wheelDelta || 0); if (e.detail != null) { if (e.axis == e.HORIZONTAL_AXIS) dx = e.detail; else if (e.axis == e.VERTICAL_AXIS) dy = e.detail; } if (dx) { var ndx = Math.round(normalizeWheelDelta(dx)); if (!ndx) ndx = dx > 0 ? 1 : -1; div.scrollLeft += ndx; } if (dy) { var ndy = Math.round(normalizeWheelDelta(dy)); if (!ndy) ndy = dy > 0 ? 1 : -1; div.scrollTop += ndy; } if (dx || dy) { e.preventDefault(); e.stopPropagation(); } }


Para obtener compatibilidad con el zoom en dispositivos táctiles, regístrese para los eventos geststart, geekchange y gestureend y use la propiedad event.scale. Puedes ver un código de ejemplo para esto.

Para Firefox 17, se onwheel evento onwheel sea ​​compatible con versiones de escritorio y móviles (según documentos de MDN en rueda ). También para Firefox tal vez el evento específico Gecko MozMousePixelScroll sea ​​útil (aunque, presumiblemente, esto ahora está en desuso debido a que el evento DOMMouseWheel ahora está en desuso en Firefox).

Para Windows, el controlador en sí parece generar los eventos WM_MOUSEWHEEL, WM_MOUSEHWHEEL (¿y quizás el evento WM_GESTURE para la panorámica del panel táctil?). Eso explicaría por qué Windows o el navegador no parecen normalizar los valores de evento mousewheel en sí (y podría significar que no puede escribir código confiable para normalizar los valores).

Para el soporte de eventos onwheel ( no onmousewheel) en Internet Explorer para IE9 e IE10, también puede usar el evento onwheel estándar W3C . Sin embargo, una muesca puede ser un valor diferente de 120 (por ejemplo, una sola muesca se convierte en 111 (en lugar de -120) en mi mouse usando esta página de prueba ). Escribí otro artículo con otros detalles sobre eventos de rueda que podrían ser relevantes.

Básicamente en mis propias pruebas de eventos de ruedas (estoy tratando de normalizar los valores de desplazamiento), he encontrado que obtengo valores variables para SO, proveedor de navegadores, versión de navegador, tipo de evento y dispositivo (mouse con rueda basculante de Microsoft, gestos del panel táctil del portátil , touchpad portátil con scrollzone, mouse mágico de Apple, mouseball poderoso de Apple, touchpad Mac, etc.).

Y debe ignorar una variedad de efectos secundarios de la configuración del navegador (por ejemplo, Firefox mousewheel.enable_pixel_scrolling, chrome --scroll-pixels = 150), configuración del controlador (por ejemplo, Synaptics touchpad) y configuración del sistema operativo (configuración del mouse de Windows, preferencias del mouse OSX, Configuración del botón X.org).


Solución simple y funcional:

private normalizeDelta(wheelEvent: WheelEvent):number { var delta = 0; var wheelDelta = wheelEvent.wheelDelta; var deltaY = wheelEvent.deltaY; // CHROME WIN/MAC | SAFARI 7 MAC | OPERA WIN/MAC | EDGE if (wheelDelta) { delta = -wheelDelta / 120; } // FIREFOX WIN / MAC | IE if(deltaY) { deltaY > 0 ? delta = 1 : delta = -1; } return delta; }


Editar septiembre de 2014

Dado que:

  • Las diferentes versiones del mismo navegador en OS X han arrojado valores diferentes en el pasado, y pueden hacerlo en el futuro, y eso
  • El uso del trackpad en OS X produce efectos muy similares al uso de una rueda de mouse, pero da valores de evento muy diferentes, y aun así la diferencia del dispositivo no puede ser detectada por JS

... Solo puedo recomendar el uso de este simple código de conteo basado en signos:

var handleScroll = function(evt){ if (!evt) evt = event; var direction = (evt.detail<0 || evt.wheelDelta>0) ? 1 : -1; // Use the value as you will }; someEl.addEventListener(''DOMMouseScroll'',handleScroll,false); // for Firefox someEl.addEventListener(''mousewheel'', handleScroll,false); // for everyone else

El intento original de ser correcto sigue.

Aquí está mi primer intento de un script para normalizar los valores. Tiene dos fallas en OS X: Firefox en OS X producirá valores de 1/3 de lo que debería ser, y Chrome en OS X producirá valores 1/40 de lo que deberían ser.

// Returns +1 for a single wheel roll ''up'', -1 for a single roll ''down'' var wheelDistance = function(evt){ if (!evt) evt = event; var w=evt.wheelDelta, d=evt.detail; if (d){ if (w) return w/d/40*d>0?1:-1; // Opera else return -d/3; // Firefox; TODO: do not /3 for OS X } else return w/120; // IE/Safari/Chrome TODO: /3 for Chrome OS X };

Puede probar este código en su propio navegador aquí: http://phrogz.net/JS/wheeldelta.html

Las sugerencias para detectar y mejorar el comportamiento en Firefox y Chrome en OS X son bienvenidas.

Editar : Una sugerencia de @Tom es simplemente contar cada llamada de evento como un solo movimiento, usando el signo de la distancia para ajustarlo. Esto no dará grandes resultados bajo desplazamiento suave / acelerado en OS X, ni manejará casos perfectamente cuando la rueda del mouse se mueva muy rápido (por ejemplo, wheelDelta es 240), pero esto ocurre con poca frecuencia. Este código es ahora la técnica recomendada que se muestra en la parte superior de esta respuesta, por los motivos que se describen allí.


var onMouseWheel = function(e) { e = e.originalEvent; var delta = e.wheelDelta>0||e.detail<0?1:-1; alert(delta); } $("body").bind("mousewheel DOMMouseScroll", onMouseWheel);