Pertanyaan Berapa tinggi "garis" dalam suatu peristiwa roda? (deltaMode = DOM_DELTA_LINE)


Itu wheel acara di Firefox> = 17 memiliki deltaMode milik. Dengan OS / mouse yang saya gunakan, itu diatur ke 1 (atau DOM_DELTA_LINE). Pengaturan ini berarti bahwa deltaX dan deltaY nilai acara diukur dalam garis dan bukan piksel. Benar saja, jika saya berpura-pura delta adalah piksel, kecepatan gulir jauh lebih lambat daripada yang biasanya ada di Firefox.

Chrome 31 sebaliknya menggunakan a deltaMode dari 0 (atau DOM_DELTA_PIXEL), yang memungkinkan saya untuk mensimulasikan bergulir dengan kecepatan normal.

Jika saya dapat mengonversi nilai garis ke nilai piksel, saya akan siap. Tapi saya tidak dapat menemukan secarik dokumentasi tentang apa itu "garis". Saya mencoba mengubah font-size dan line-height di Firefox, yang tidak mengubah perilaku pengguliran.

Ada yang tahu bagaimana "garis" didefinisikan? W3C hanya mengatakan, "Ini adalah kasus untuk banyak bentuk kontrol."

W3C deltaMode

MDN WheelEvent

MDN wheel

Edit: ini sebuah biola untuk menunjukkan keanehan. Saat Firefox aktif DOM_DELTA_LINE mode, tidak ada rasio yang konsisten antara piksel dan garis - semuanya ada di mana-mana. Dan ketika saya beralih menggunakan trackpad bukan mouse, menyebabkan Firefox untuk beralih ke DOM_DELTA_PIXEL mode, juga tidak ada rasio yang konsisten. Di sisi lain, di Chrome 31, rasio hampir selalu sangat dekat dengan 1: 1 di DOM_DELTA_PIXEL mode.

Masalah Chromium: implementasikan kejadian roda DOM3

Bug Bugzilla: mengimplementasikan event roda DOM3

Memperbarui: Bergulir dengan kutu tunggal roda mouse di Firefox tempat deltaMode aku s DOM_DELTA_LINE, delta piksel tergantung pada CSS font-size, tapi tidak aktif line-height. Lihat biola ini untuk demonstrasi. Perilaku ini hanya berlaku ketika mencentang roda sangat lambat. Dengan kecepatan atau momentum, rasio garis terhadap piksel tidak dapat diprediksi pada contoh tertentu atau secara keseluruhan. Sejauh yang saya tahu, tidak ada cara untuk meniru perilaku gulir Firefox menggunakan pengukuran delta yang disediakan DOM_DELTA_LINE mode.

Di DOM_DELTA_PIXEL mode, perilaku hampir pixel-sempurna. Artinya, rasio antara piksel aktual yang digulir dan nilai delta piksel yang dilaporkan hampir sama dengan 1, yang ditunjukkan dalam biola yang sama.

saya mengajukan bug dengan Mozilla, dengan alasan bahwa perilaku wheel acara di DOM_DELTA_LINE mode tidak berguna karena tidak dapat diprediksi (yaitu persamaan di mana kedua unit dan besarnya adalah variabel). Masalah ini telah ditandai tidak valid karena perilaku yang diharapkan adalah untuk wheel acara untuk melewati delta asli yang disediakan oleh OS, meskipun fakta bahwa Firefox sendiri tidak menghormati delta ini.

Saya akan membiarkan pertanyaan ini terbuka dengan harapan DOM_DELTA_LINE akan ditentukan oleh spesifikasi di suatu tempat. Sejauh yang saya tahu, ketergantungan pada font-size (dan tidak line-height) belum dijelaskan di mana pun.


32
2017-11-21 00:41


asal


Jawaban:


Ringkasan:

Sedangkan nilai gulir yang dihasilkan dari DOM_DELTA_LINE mungkin tidak secara spesifik ditentukan oleh spesifikasi apa pun, berdasarkan komentar berikut dari pelacak masalah Chromium dan pengamatan saya sendiri, tampaknya bahwa Firefox saat ini adalah satu-satunya browser yang akan melaporkan peristiwa roda dengan hal lain selain deltaModesebagai DOM_DELTA_PIXEL (0).

Komentar dari masalah Chromium Terapkan acara roda DOM3:

Kami akhirnya melakukan apa yang dilakukan IE dan melaporkan jumlah piksel yang tepat, kami akan menggulir elemen.

Penegasan berikut ini selalu benar (mengingat bahwa elemen dapat menjadi   digulir).

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

Dengan cara ini Anda tahu persis berapa banyak yang harus digulir sepanjang waktu.

Kami tidak pernah mengatur deltaMode untuk hal lain tapi DOM_DELTA_PIXEL.

Menurut komentar itu, Chromium cocok dengan delta piksel-satunya IE. Meskipun tidak tertutup, ini hampir pasti meluas langsung ke Opera dan Safari modern. Pengamatan saya sendiri dari pengujian pada Window, Mac, dan Linux dengan beberapa perangkat input tidak membantah hal ini.

Jadi karena Firefox adalah satu-satunya browser yang akan melaporkan deltaMode dari DOM_DELTA_LINE (1) atau DOM_DELTA_PAGE (2), untuk sementara waktu, kita hanya perlu tahu apa yang dihitung oleh Firefox sebagai nilai-nilai ini. Nah, di situlah hal-hal menjadi sedikit rumit, tetapi melalui pencarian melalui sumber Firefox dan beberapa trial and error, saya telah memutuskan itu langsung sesuai font default dan ukuran font default. Khususnya yang dikonfigurasi dalam preferensi berikut, mengabaikan CSS apa pun di halaman.

Firefox fonts preferences options

Itu berarti bahwa untuk mendeteksi tinggi garis yang digunakan dalam gulir, Anda harus memiliki elemen inline yang benar-benar tidak bergaya untuk mendeteksi tinggi render yang dihitung dari. Karena CSS pada halaman hampir pasti akan mengganggu, kita harus membuat jendela baru dan bersih dalam iframe untuk melakukan deteksi.

Mendeteksi garis ketinggian yang digunakan oleh DOM_DELTA_LINE acara gulir terpicu:

Untuk tujuan ini, saya telah membuat fungsi kecil berikut untuk secara sinkron mendeteksi garis-tinggi yang murni dan tidak berubah.

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, jadi sekarang kita tahu berapa banyak garis ketinggian delta harus diterjemahkan ke dalam piksel. Namun, di Jendela, ada satu hal lain yang mungkin perlu Anda pertimbangkan. Pada Windows, kecepatan gulir default ditimpa untuk membuatnya 2x lebih cepat secara default, tetapi hanya untuk elemen root.

Timpa sistem kecepatan gulir sistem:

Kami menyediakan mekanisme menimpa kecepatan gulir sistem karena kecepatan pengguliran sistem default Windows lebih lambat daripada kecepatan gulir WebKit. Ini disarankan untuk cara alternatif dari sistem percepatan (lihat bagian berikutnya).

Ini diaktifkan dalam pengaturan default hanya di Windows. mousewheel.system_scroll_override_on_root_content.enabled dapat mengubahnya.

Di Windows, hanya ketika pengaturan kecepatan gulir sistem tidak disesuaikan oleh pengguna atau driver mouse, ini menimpa kecepatan bergulir. Di sisi lain, ini selalu menimpa kecepatan.

Rasio dapat ditentukan oleh prefs tersembunyi. mousewheel.system_scroll_override_on_root_content.vertical.factor adalah untuk acara pengguliran vertikal. mousewheel.system_scroll_override_on_root_content.horizontal.factor adalah untuk gulir horizontal. Nilai-nilai digunakan sebagai 1/100 (yaitu, nilai standar 200 berarti 2.0).

nsEventStateManager mengalikan kecepatan bergulir dengan rasio saat dijalankan untuk menggulir akar tampilan dokumen yang dapat digulirkan. Jadi, nilai delta acara DOMMouseScroll tidak pernah ditimpa oleh ini.

Lihat juga bug 513817.

Ini hanya berlaku secara default ke akar dokumen, menggulir elemen dalam dokumen seperti a textarea tidak terpengaruh (kecuali mungkin iframes?). Juga tidak ada cara untuk mendapatkan nilai yang ditentukan jika default 2x dikonfigurasi ulang, jadi jika Anda menganggap nilai ini penting, Anda harus menggunakan OS pengguna-agen mengendus, mungkin dengan teknis non-standar namun populer navigator.platform.

Bagaimana dengan DOM_DELTA_PAGE?:

Windows juga memiliki pengaturan alternatif untuk pengguliran vertikal di mana alih-alih bergulir dengan jumlah baris, gulir dengan sebuah hampir halaman penuh. Untuk memperjelas, ini adalah dialog dengan pengaturan "Satu layar pada satu waktu" yang mengendalikan ini di Windows 7.

Windows 7 wheel settings

Ketika ini diaktifkan, satu klik akan menggulir hampir satu halaman penuh, di sini yang berarti ketinggian panel bergulir, minus scroll bar. Saya katakan hampir, karena Firefox mempertimbangkan beberapa hal lain untuk mengurangi jumlah pengguliran. Yakni, mengurangi beberapa baris, persentase, dan entah bagaimana mengurangi header dan footer posisi tetap. Lihat blok kode berikut untuk beberapa logika.

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

Saya tidak 100% yakin apa sebenarnya yang dideteksi sebagai header posisi tetap dan elemen footer dan apa yang tidak, tetapi ini harus memberikan gambaran yang cukup bagus tentang bagaimana DOM_DELTA_PAGE mode juga berfungsi, selain DOM_DELTA_LINE yang ditanyakan pertanyaan ini.


12
2018-05-27 03:10



Saya mencoba biola Anda dengan Firefox 25 (di Linux) - dan memperpanjangnya untuk melacak scrollTop hanya pada peristiwa roda. Dalam biola Anda, delta bergulir dihitung dalam peristiwa gulir yang dipicu lebih sering daripada peristiwa roda. Juga, bergulir peristiwa dalam mode soft scrolling tampaknya tertinggal dibandingkan dengan peristiwa roda. (Yaitu jika Anda mengukur sementara soft scrolling belum selesai maka Anda mendapatkan nilai "menengah" untuk scrollTop ().) Saya pikir ini adalah alasan mengapa Anda tidak mendapatkan korelasi yang baik antara delta gulir dan peristiwa roda. (Catatan: Peristiwa roda tampaknya ditangani sebelum acara gulir terkait.)

Jika bergulir lembut dimatikan maka setidaknya ada satu peristiwa roda per acara gulir. Biola Anda memberikan konstanta "px / DOM_DELTA_LINE: 18" selama "roda" untuk saya. Jika saya menambahkan div dengan dua rentang <span id="lineN">N</span> dan a <br/> antara dan mengukur ($("#line2").position().top - $("#line1").position().top) maka saya mendapatkan tepat 18.

Ringkasan: Peristiwa roda memungkinkan untuk menghitung jarak gulir dalam piksel - setidaknya di lingkungan saya. Saya harap ini juga berlaku untuk Anda.

Ini adalah kode JavaScript dari biola saya yang diperpanjang untuk biola Anda dengan ekstensi saya:

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

Dan 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



Saya belum melihat kode Anda, tetapi ini adalah bagaimana saya memecahkan masalah saya, yang membawa saya ke sini.

Anda dapat mencoba menimpa gulir browser dengan gulir kustom Anda.

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

 e.preventDefault();
});

Dengan cara ini Anda akan selalu yakin tentang jumlah piksel yang digulir.


-3
2018-01-27 17:31



Saya menemukan bahwa menggunakan cuplikan berikut menyelesaikan masalah. Ini menormalkan deltaX dan deltaY. Coba yang ini.

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

Dimana e aku s WheelEvent obyek.


-3
2018-05-24 09:16