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


los wheel evento en Firefox> = 17 tiene un deltaMode propiedad. Con el OS / mouse que estoy usando, está configurado para 1 (o DOM_DELTA_LINE) Esta configuración significa que el deltaX y deltaY los valores de evento 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 una deltaMode de 0 (o DOM_DELTA_PIXEL), lo 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". Intenté cambiar el font-size y line-height en Firefox, que no cambió el comportamiento de 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

MDN wheel

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

Problema de cromo: implementar un evento de rueda DOM3

Error de Bugzilla: implementar un evento de rueda DOM3

Actualizar: Desplazarse por simples marcas de una rueda del mouse en Firefox donde deltaMode es DOM_DELTA_LINE, el pixel delta depende del CSS font-size, pero no en line-height. Ver 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 proporcionadas en DOM_DELTA_LINE modo.

En DOM_DELTA_PIXEL modo, el comportamiento es casi perfecto como un píxel. 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 el mismo violín.

yo archivó un error con Mozilla, argumentando que el comportamiento de wheel evento en DOM_DELTA_LINE modo 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 para el wheel evento para pasar a través de los deltas nativos proporcionados por el sistema operativo, a pesar del hecho de que Firefox en sí no cumple estos deltas.

Dejaré esta pregunta abierta con la esperanza de que DOM_DELTA_LINE será definido por una especificación en alguna parte. Por lo que sé, la dependencia de font-size (y no line-height) aún no se describe en ninguna parte.


32
2017-11-21 00:41


origen


Respuestas:


Visión de conjunto:

Mientras que el valor de desplazamiento resultante de DOM_DELTA_LINE puede no estar específicamente definido por ninguna especificación, basado en 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 no sea deltaModecomo DOM_DELTA_PIXEL (0)

Comentario del problema de Chromium Implementar 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 ciertos (dado que el elemento puede ser   desplazado).

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 establecimos el deltaMode a cualquier otra cosa 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 informará 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.

Firefox fonts preferences options

Eso significa que para detectar correctamente la altura de línea utilizada en el desplazamiento, usted 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 DOM_DELTA_LINE eventos de desplazamiento activados:

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 solamente 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 otros, 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 evento de desplazamiento vertical. mousewheel.system_scroll_override_on_root_content.horizontal.factor es para eventos de desplazamiento horizontal. Los valores se utilizan 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 desplazar una raíz vista desplazable 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 es aplicable por defecto a la raíz del documento, desplazando elementos dentro del documento como un textarea no se ven afectados (excepto tal vez iframes?). Tampoco hay manera 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 de agente de usuario, quizás con el estándar técnicamente no popular pero popular. navigator.platform.

Qué pasa 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 casi página completa. Para aclarar, este es el diálogo con la configuración "Una pantalla a la vez" que controla esto en Windows 7.

Windows 7 wheel settings

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, pero esto debería proporcionar una visión general bastante buena de cómo DOM_DELTA_PAGE modo también funciona, además de la DOM_DELTA_LINE sobre lo cual pregunta esta pregunta.


12
2018-05-27 03:10



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 aún no ha terminado, entonces 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 desplazamiento suave está apagado, entonces 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 medida ($("#line2").position().top - $("#line1").position().top) entonces 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>

3
2017-11-24 14:48



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.


-3
2018-01-27 17:31



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);
}

Dónde e es WheelEvent objeto.


-3
2018-05-24 09:16