wheel event crossbrowser javascript firefox javascript-events mousewheel

javascript mousewheel event crossbrowser



¿Cuál es la altura de una "línea" en un evento de rueda?(deltaMode=DOM_DELTA_LINE) (4)

El evento de wheel en Firefox> = 17 tiene una propiedad deltaMode . Con el OS / mouse que estoy usando, está configurado en 1 (o DOM_DELTA_LINE ). Esta configuración significa que los valores del evento deltaX y deltaY se miden en líneas y no en píxeles. Efectivamente, si pretendo que los deltas son píxeles, las velocidades de desplazamiento son mucho más lentas de lo que normalmente son en Firefox.

Chrome 31 por el contrario usa un deltaMode de 0 (o DOM_DELTA_PIXEL ), que me permite simular el desplazamiento con velocidades normales.

Si pudiera convertir los valores de línea en valores de píxel, estaría todo listo. Pero no puedo encontrar un trozo de documentación sobre lo que es una "línea". Traté de cambiar el font-size la font-size y line-height en Firefox, lo que no cambió el comportamiento del desplazamiento.

¿Alguien sabe cómo se define una "línea"? W3C simplemente dice: "Este es el caso para muchos controles de formulario".

W3C deltaMode

MDN WheelEvent

wheel MDN

Editar: aquí hay un violín para demostrar la rareza. Cuando Firefox está en el modo DOM_DELTA_LINE , no hay una proporción constante entre píxeles y líneas; está por todos lados. Y cuando cambio a usar un panel táctil en lugar de un mouse, lo que provoca que Firefox cambie al modo DOM_DELTA_PIXEL , tampoco hay una proporción constante. Por otro lado, en Chrome 31, la relación casi siempre es muy cercana a 1: 1 en el modo DOM_DELTA_PIXEL .

Problema de cromo: implementar un evento de rueda DOM3

Error de Bugzilla: implementar un evento de rueda DOM3

Actualización: al desplazarse por simples marcas de una rueda del mouse en Firefox, donde deltaMode es DOM_DELTA_LINE , el delta del píxel depende del font-size CSS, pero no line-height . Mira este violín para una demostración. Este comportamiento solo se cumple cuando se hace tictac la rueda muy lentamente. Con la velocidad o el momento, la relación de línea a píxel no es predecible en ninguna instancia en particular ni en conjunto. Por lo que puedo decir, no hay forma de emular el comportamiento de desplazamiento de Firefox usando las medidas delta provistas en el modo DOM_DELTA_LINE .

En el modo DOM_DELTA_PIXEL , el comportamiento es casi perfecto. Es decir, la relación entre los píxeles reales desplazados y el valor delta de píxeles informado es casi exactamente 1, lo que se demuestra en el mismo violín .

Archivé un error con Mozilla , argumentando que el comportamiento del evento de wheel en el modo DOM_DELTA_LINE no es útil porque no es predecible (es decir, es una ecuación donde tanto la unidad como la magnitud son variables). El problema se marcó como no válido porque el comportamiento esperado es que el evento wheel pase a través de los deltas nativos proporcionados por el sistema operativo, a pesar de que Firefox en sí no respeta estos deltas.

DOM_DELTA_LINE esta pregunta abierta con la esperanza de que DOM_DELTA_LINE sea ​​definido por una especificación en alguna parte. Hasta donde yo sé, la dependencia font-size (y no line-height ) todavía no se describe en ninguna parte.


Visión de conjunto:

Si bien el valor de desplazamiento resultante de DOM_DELTA_LINE puede no estar definido específicamente por ninguna especificación, según el siguiente comentario del rastreador de problemas de Chromium y mis propias observaciones, parece que Firefox es actualmente el único navegador que informará los eventos de rueda con cualquier otra cosa que deltaMode como DOM_DELTA_PIXEL ( 0 ).

Comment del problema de Chromium Implementar el evento de rueda DOM3 :

Terminamos haciendo lo que IE hace e informamos el número exacto de píxeles que desplazaríamos el elemento.

Los siguientes asertos son siempre verdaderos (dado que el elemento se puede desplazar).

element.scrollTop = 0; element.addEventListener(''wheel'', function(e) { assert(e.deltaMode === MouseEvent. DOM_DELTA_PIXEL); assert(element.scrollTop === e.deltaY); }); // scroll

De esta forma sabrá exactamente cuánto desplazarse en todo momento.

Nunca configuramos deltaMode para nada más que DOM_DELTA_PIXEL .

Según ese comentario, Chromium coincide con los deltas de un solo píxel de IE. Aunque no está cubierto, esto casi seguramente se extiende directamente a la Opera y Safari modernos. Mis propias observaciones de las pruebas en Windows, Mac y Linux con múltiples dispositivos de entrada no desmintieron esto.

Entonces, dado que Firefox es el único navegador que reportará un deltaMode de DOM_DELTA_LINE ( 1 ) o DOM_DELTA_PAGE ( 2 ), por el momento de todos modos, solo necesitamos saber cómo Firefox calcula estos valores. Bueno, ahí es donde las cosas se ponen un poco complicadas, pero a través de la búsqueda a través de la fuente de Firefox y algunas pruebas y errores, he determinado que corresponde directamente a la fuente predeterminada y al tamaño de fuente predeterminado. Específicamente aquellos configurados en las siguientes preferencias, ignorando cualquier CSS en la página.

Eso significa que para detectar correctamente la altura de línea utilizada en el desplazamiento, debe tener un elemento en línea completamente sin estilo para detectar la altura de representación computada. Dado que CSS en la página casi seguramente interferirá, debemos crear una ventana nueva y limpia en un iframe para hacer la detección.

Detectando la altura de línea utilizada por los eventos de desplazamiento desencadenados DOM_DELTA_LINE :

Para este propósito, he creado la siguiente pequeña función para detectar de forma síncrona la línea de altura pura, inalterada.

function getScrollLineHeight() { var r; var iframe = document.createElement(''iframe''); iframe.src = ''#''; document.body.appendChild(iframe); var iwin = iframe.contentWindow; var idoc = iwin.document; idoc.open(); idoc.write(''<!DOCTYPE html><html><head></head><body><span>a</span></body></html>''); idoc.close(); var span = idoc.body.firstElementChild; r = span.offsetHeight; document.body.removeChild(iframe); return r; } // Get the native croll line height. console.log(getScrollLineHeight());

Ok, ahora sabemos hasta qué punto un delta de altura de línea debe traducirse en píxeles. Sin embargo, en Window, hay otra cosa que quizás deba tener en cuenta. En Windows, la velocidad de desplazamiento predeterminada se anula para que sea 2 veces más rápida de forma predeterminada, pero solo para el elemento raíz.

Anular el sistema de velocidad de desplazamiento del sistema:

Estamos proporcionando un mecanismo de anulación de la velocidad de desplazamiento del sistema porque la velocidad de desplazamiento del sistema predeterminada de Windows es más lenta que la velocidad de desplazamiento de WebKit. Esto fue sugerido por una forma alternativa del sistema de aceleración (ver la siguiente sección).

Esto está habilitado en la configuración predeterminada solo en Windows. mousewheel.system_scroll_override_on_root_content.enabled puede cambiarlo.

En Windows , solo cuando la configuración de velocidad de desplazamiento del sistema no está personalizada por el usuario o el controlador del mouse, esto anula la velocidad de desplazamiento. En los demás , esto siempre anula la velocidad.

La relación puede ser especificada por preferencias ocultas. mousewheel.system_scroll_override_on_root_content.vertical.factor es para eventos de desplazamiento vertical. mousewheel.system_scroll_override_on_root_content.horizontal.factor es para eventos de desplazamiento horizontal. Los valores se usan como 1/100 (es decir, el valor predeterminado 200 significa 2.0).

nsEventStateManager multiplica la velocidad de desplazamiento por la relación cuando se ejecuta para desplazarse por una vista de desplazamiento de la raíz de un documento. Por lo tanto, el valor delta del evento DOMMouseScroll nunca ha sido sobrescrito por esto.

Ver también error 513817 .

Esto solo se aplica por defecto a la raíz del documento, los elementos desplazables dentro del documento como un área de textarea no se ven afectados (excepto tal vez iframes?). Tampoco hay forma de obtener el valor especificado si el valor 2x predeterminado se reconfigura, por lo que si considera que este valor es importante, deberá recurrir a la detección de SO del agente de usuario, quizás con la plataforma navigator.platform técnicamente no estándar pero popular.

¿Qué pasa con DOM_DELTA_PAGE ?

Windows también tiene una configuración alternativa para el desplazamiento vertical donde, en lugar de desplazarse por el número de líneas, se desplaza por una página casi completa. Para aclarar, este es el diálogo con la configuración "Una pantalla a la vez" que controla esto en Windows 7.

Cuando esto se activa, un solo clic recorrerá casi una página completa, lo que significa la altura del panel de desplazamiento, menos las barras de desplazamiento. Digo casi, porque Firefox tiene en cuenta otras cosas para reducir la cantidad de desplazamiento. A saber, reduciendo algunas líneas, un porcentaje y de alguna manera restando los encabezados y pies de página de posición fija. Vea el siguiente bloque de código para algo de la lógica.

Extracto de layout/generic/nsGfxScrollFrame.cpp :

nsSize ScrollFrameHelper::GetPageScrollAmount() const { nsSize lineScrollAmount = GetLineScrollAmount(); nsSize effectiveScrollPortSize; if (mIsRoot) { // Reduce effective scrollport height by the height of any fixed-pos // headers or footers nsIFrame* root = mOuter->PresContext()->PresShell()->GetRootFrame(); effectiveScrollPortSize = GetScrollPortSizeExcludingHeadersAndFooters(root, mScrollPort); } else { effectiveScrollPortSize = mScrollPort.Size(); } // The page increment is the size of the page, minus the smaller of // 10% of the size or 2 lines. return nsSize( effectiveScrollPortSize.width - std::min(effectiveScrollPortSize.width/10, 2*lineScrollAmount.width), effectiveScrollPortSize.height - std::min(effectiveScrollPortSize.height/10, 2*lineScrollAmount.height)); }

No estoy 100% seguro de qué se detecta exactamente como un elemento de encabezado y pie de página de posición fija y lo que no es, pero esto debería proporcionar una visión general bastante buena de cómo DOM_DELTA_PAGE también el modo DOM_DELTA_PAGE , además del DOM_DELTA_LINE que esta pregunta acerca de.


Descubrí que usar el siguiente fragmento resuelve el problema. Normaliza el deltaX y deltaY. Prueba este.

function onWheel(e) { var deltaX = Math.max(-1, Math.min(1, (e.deltaX))); var deltaY = Math.max(-1, Math.min(1, (e.deltaY))); console.log(''deltaX: '' + deltaX + '', deltaY: '' + deltaY); }

Donde e es el objeto WheelEvent .


No he revisado tu código, pero así es como resolví mi problema, que me llevó hasta aquí.

Puede intentar anular el desplazamiento del navegador con el personalizado.

window.addEventListener("wheel", function(e){ if(e.deltaY > 0) window.scroll(0,20); else window.scroll(0,-20) e.preventDefault(); });

De esta manera, siempre estará seguro de la cantidad de píxeles desplazados.


Probé tu violín con Firefox 25 (en Linux) y lo extendí para rastrear scrollTop solo en eventos de rueda. En su violín, el delta de desplazamiento se calcula en el evento de desplazamiento que se activa con mucha más frecuencia que el evento de rueda. Además, los eventos de desplazamiento en modo de desplazamiento suave parecen retrasarse en comparación con los eventos de rueda. (Es decir, si mides mientras el desplazamiento suave no ha terminado aún, obtienes valores "intermedios" para scrollTop ()). Creo que estas son las razones por las que no obtienes una buena correlación entre los eventos scroll delta y wheel. (Nota: el evento de rueda parece manejarse antes de los eventos de desplazamiento asociados).

Si el desplazamiento suave está desactivado, hay al menos un evento de rueda por evento de desplazamiento. Tu violín me da un "px / DOM_DELTA_LINE" perfectamente constante durante el "giro" para mí. Si agrego un div con dos tramos <span id="lineN">N</span> y un <br/> entre y mida ($("#line2").position().top - $("#line1").position().top) luego obtengo exactamente 18.

Resumen: el evento rueda permite calcular la distancia de desplazamiento en píxeles, al menos en mi entorno. Espero que esto también sea verdad para los tuyos.

Aquí está el código de JavaScript de mi violín extendido para su violín con mis extensiones:

var DeltaModes = { 0: "DOM_DELTA_PIXEL", 1: "DOM_DELTA_LINE", 2: "DOM_DELTA_PAGE" }; var statsPane = $(".stats-pane"); var scrollTop = $(window).scrollTop(); var scrollDelta = 0; var wheelEvents = 0; var scrollEvents = 0; var scrollTopOnWheel = 0; $(window).scroll(function(){ scrollEvents++; var newScrollTop = $(window).scrollTop(); scrollDelta = scrollTop - newScrollTop; scrollTop = newScrollTop; }); $(window).on("wheel", function(e){ wheelEvents++; var wheelScrollTop = $(window).scrollTop(); var wheelScrollDelta = wheelScrollTop - scrollTopOnWheel; e = e.originalEvent; var pxPerDeltaUnit = Math.abs(scrollDelta) / Math.abs(e.deltaY); var deltaMode = DeltaModes[e.deltaMode]; var stats = [deltaMode + ": " + e.deltaY]; stats.push("px delta: " + scrollDelta); stats.push("px/" + deltaMode + ": " + pxPerDeltaUnit); stats.push("wheel scroll top (prev): " + scrollTopOnWheel); stats.push("wheel scroll top: " + wheelScrollTop); stats.push("wheel scroll delta: " + wheelScrollDelta); stats.push("line height: " + ($("#line2").position().top - $("#line1").position().top)); stats.push("wheel event#: " + wheelEvents); stats.push("scroll event#: " + scrollEvents); statsPane.html(''<div>'' + stats.join(''</div><div>'') + ''</div>''); scrollTopOnWheel = wheelScrollTop; //scrollTop = newScrollTop; });

Y el HTML:

<div class="stats-pane"></div> <div>Hey.</div> <div>Hi.</div> <div>Hello.</div> <div> <span id="line1">1</span><br/> <span id="line2">2</span><br/> </div>