브라우저에서 마우스 휠 속도 정상화
대한 다른 질문 나는 구성 이 답변 을 포함하여, 이 샘플 코드를 .
이 코드에서 마우스 휠을 사용하여 HTML5 Canvas를 확대 / 축소합니다. Chrome과 Firefox의 속도 차이를 정상화하는 코드가 있습니다. 그러나 Safari의 확대 / 축소 처리는 그 어느 것보다 훨씬 빠릅니다.
현재 가지고있는 코드는 다음과 같습니다.
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
Chrome v10 / 11, Firefox v4, Safari v5, Opera v11 및 IE9에서 동일한 양의 마우스 휠 롤링에 대해 동일한 '델타'값을 얻는 데 어떤 코드를 사용할 수 있습니까?
이 질문 은 관련이 있지만 정답은 없습니다.
편집 : 추가 조사에 따르면 하나의 스크롤 이벤트 '위로'는 다음과 같습니다.
| evt.wheelDelta | evt.detail
------------------ + ---------------- + ------------
사파리 v5 / Win7 | 120 | 0
Safari v5 / OS X | 120 | 0
Safari v7 / OS X | 12 | 0
크롬 v11 / Win7 | 120 | 0
크롬 v37 / Win7 | 120 | 0
Chrome v11 / OS X | 3 (!) | 0 (아마도 틀렸다)
Chrome v37 / OS X | 120 | 0
IE9 / Win7 | 120 | 찾으시는 주소가 없습니다
오페라 v11 / OS X | 40 | -1
오페라 v24 / OS X | 120 | 0
오페라 v11 / Win7 | 120 | -삼
Firefox v4 / Win7 | 미정의 | -삼
Firefox v4 / OS X | 미정의 | -1
Firefox v30 / OS X | 미정의 | -1
또한 OS X에서 MacBook 트랙 패드를 사용하면 느리게 움직일 때도 다른 결과를 얻을 수 있습니다.
- Safari 및 Chrome에서
wheelDelta마우스 휠의 값은 120이 아니라 3입니다. - 파이어 폭스에서는
detail보통2때로 사용1하지만 때로는 매우 느리게 스크롤 할 때 이벤트 핸들러가 전혀 발생하지 않습니다 .
따라서 질문은 다음과 같습니다.
이 동작을 차별화하는 가장 좋은 방법은 무엇입니까 (이상적으로 사용자 에이전트 또는 OS 스니핑 없음)?
2014 년 9 월 수정
을 고려하면:
- OS X에서 동일한 브라우저의 다른 버전은 과거에 다른 값을 산출했으며 앞으로 그렇게 할 수도 있습니다.
- OS X에서 트랙 패드 를 사용하면 마우스 휠을 사용하는 것과 매우 유사한 효과 를 얻을 수 있지만 매우 다른 이벤트 값을 제공 하지만 장치 차이는 JS에서 감지 할 수 없습니다
…이 간단한 부호 기반 계산 코드 만 사용하는 것이 좋습니다.
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
올바른 시도는 다음과 같습니다.
다음은 값을 정규화하기위한 스크립트의 첫 번째 시도입니다. OS X에는 두 가지 결함이 있습니다. OS X의 Firefox는 1/3의 값을 생성하고, OS X의 Chrome은 1/4의 값을 생성합니다.
// 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
};
http://phrogz.net/JS/wheeldelta.html 여기에서 자신의 브라우저에서이 코드를 테스트 할 수 있습니다.
OS X의 Firefox 및 Chrome에서 동작을 감지하고 개선하기위한 제안을 환영합니다.
편집 : @Tom의 제안 중 하나는 거리의 부호를 사용하여 각 이벤트 호출을 단일 이동으로 계산하여 조정하는 것입니다. 이로 인해 OS X에서 부드럽게 / 가속 스크롤 할 때 큰 결과를 얻지 못하고 마우스 휠이 매우 빠르게 움직일 때 (예 : wheelDelta240) 완벽하게 처리 할 수는 없지만 드물게 발생합니다. 이 코드는 이제 여기에 설명 된 이유로이 답변의 맨 위에 표시되는 권장 기술입니다.
크로스 브라우저 일관성 있고 표준화 된 델타 (-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);
이것은 완전히 경험적이지만 XP의 Safari 6, FF 16, Opera 12 (OS X) 및 IE 7에서 잘 작동합니다.
Facebook의 친구들은이 문제에 대한 훌륭한 해결책을 모았습니다.
React를 사용하여 빌드하는 데이터 테이블에서 테스트했으며 버터처럼 스크롤됩니다!
이 솔루션은 다양한 브라우저, Windows / Mac 및 트랙 패드 / 마우스를 사용하여 작동합니다.
// 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 };
}
소스 코드는 https://github.com/facebook/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js 에서 찾을 수 있습니다.
일부 브라우저에서 이미 지원 하는 DOM3 wheel 이벤트 (아래 표) 를 고려하여 다른 이벤트 / 브라우저에서 반환 한 다른 값으로 테이블을 만들었습니다 .
이를 바탕으로 속도를 정규화하기 위해이 기능을 만들었습니다.
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;
}
표 mousewheel, wheel및 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 | | | | | | |
어느 정도 독립적 인 솔루션 ...
This doesn't take time between events into account though. Some browsers seem to always fire events with the same delta, and just fire them faster when scrolling quickly. Others do vary the deltas. One can imagine an adaptive normalizer that takes time into account, but that'd get somewhat involved and awkward to use.
Working available here: 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(); }
}
For zoom support on touch devices, register for the gesturestart, gesturechange and gestureend events and use the event.scale property. You can see example code for this.
For Firefox 17 the onwheel event is planned to be supported by desktop and mobile versions (as per MDN docs on onwheel). Also for Firefox maybe the Gecko specific MozMousePixelScroll event is useful (although presumably this is now deprecated since the DOMMouseWheel event is now deprecated in Firefox).
For Windows, the driver itself seems to generate the WM_MOUSEWHEEL, WM_MOUSEHWHEEL events (and maybe the WM_GESTURE event for touchpad panning?). That would explain why Windows or the browser doesn't seem to normalise the mousewheel event values itself (and might mean you cannot write reliable code to normalise the values).
For onwheel (not onmousewheel) event support in Internet Explorer for IE9 and IE10, you can also use the W3C standard onwheel event. However one notch can be a value different from 120 (e.g. a single notch becomes 111 (instead of -120) on my mouse using this test page). I wrote another article with other details wheel events that might be relevant.
Basically in my own testing for wheel events (I am trying to normalise the values for scrolling), I have found that I get varying values for OS, browser vendor, browser version, event type, and device (Microsoft tiltwheel mouse, laptop touchpad gestures, laptop touchpad with scrollzone, Apple magic mouse, Apple mighty mouse scrollball, Mac touchpad, etc etc).
And have to ignore a variety of side-effects from browser configuration (e.g. Firefox mousewheel.enable_pixel_scrolling, chrome --scroll-pixels=150), driver settings (e.g. Synaptics touchpad), and OS configuration (Windows mouse settings, OSX Mouse preferences, X.org button settings).
This is a problem I've been fighting with for some hours today, and not for the first time :(
I've been trying to sum up values over a "swipe" and see how different browsers report values, and they vary a lot, with Safari reporting order of magnitude bigger numbers on almost all platforms, Chrome reporting quite more (like 3 times more) than firefox, firefox being balanced on the long run but quite different among platforms on small movements (on Ubuntu gnome, nearly only +3 or -3, seems like it sums up smaller events and then send a big "+3")
The current solutions found right now are three :
- The already mentioned "use only the sign" which kills any kind of acceleration
- Sniff the browser up to minor version and platform, and adjust properly
- Qooxdoo recently implemented a self adapting algorithm, which basically tries to scale the delta based on minimum and maximum value received so far.
The idea in Qooxdoo is good, and works, and is the only solution I've currently found to be completely consistent cross browser.
Unfortunately it tends to renormalize also the acceleration. If you try it (in their demos), and scroll up and down at maximum speed for a while, you'll notice that scrolling extremely fast or extremely slow basically produce nearly the same amount of movement. On the opposite if you reload the page and only swipe very slowly, you'll notice that it will scroll quite fast".
This is frustrating for a Mac user (like me) used to give vigorous scroll swipes on the touchpad and expecting to get to the top or bottom of the scrolled thing.
Even more, since it scales down the mouse speed based on the maximum value obtained, the more your user tries to speed it up, the more it will slow down, while a "slow scrolling" user will experience quite fast speeds.
This makes this (otherwise brilliant) solution a slightly better implementation of solution 1.
I ported the solution to the jquery mousewheel plugin : http://jsfiddle.net/SimoneGianni/pXzVv/
If you play with it for a while, You'll see that you'll start getting quite homogeneous results, but you'll also notice that it tend to +1/-1 values quite fast.
I'm now working on enhancing it to detect peaks better, so that they don't send everything "out of scale". It would also be nice to also obtain a float value between 0 and 1 as the delta value, so that there is a coherent output.
There is definitely no simple way to normalize across all users in all OS in all browsers.
It gets worse than your listed variations - on my WindowsXP+Firefox3.6 setup my mousewheel does 6 per one-notch scroll - probably because somewhere I've forgotten I've accelerated the mouse wheel, either in the OS or somewhere in about:config
However I am working on a similar problem (with a similar app btw, but non-canvas) and it occurs to me by just using the delta sign of +1 / -1 and measuring over time the last time it fired, you'll have a rate of acceleration, ie. if someone scrolls once vs several times in a few moments (which I would bet is how google maps does it).
The concept seems to work well in my tests, just make anything less than 100ms add to the acceleration.
Simple and working solution:
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;
}
var onMouseWheel = function(e) {
e = e.originalEvent;
var delta = e.wheelDelta>0||e.detail<0?1:-1;
alert(delta);
}
$("body").bind("mousewheel DOMMouseScroll", onMouseWheel);
참고URL : https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers
'Programming' 카테고리의 다른 글
| 왜 Kotlin에서 Java 정적 필드를 대체하기 위해“companion object”를 사용합니까? (0) | 2020.06.23 |
|---|---|
| PDO가있는 PHP에서 최종 SQL 매개 변수화 쿼리를 확인하는 방법은 무엇입니까? (0) | 2020.06.23 |
| `void_t`는 어떻게 작동합니까 (0) | 2020.06.23 |
| .net 4에서 async-await 사용 (0) | 2020.06.23 |
| 기본 인코딩이 ASCII 일 때 파이썬이 유니 코드 문자를 인쇄하는 이유는 무엇입니까? (0) | 2020.06.23 |