대한 다른 질문 나는 구성 이 답변 을 포함하여, 이 샘플 코드를 .
이 코드에서 마우스 휠을 사용하여 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에서 부드럽게 / 가속 스크롤 할 때 큰 결과를 얻지 못하고 마우스 휠이 매우 빠르게 움직일 때 (예 : wheelDelta
240) 완벽하게 처리 할 수는 없지만 드물게 발생합니다. 이 코드는 이제 여기에 설명 된 이유로이 답변의 맨 위에 표시되는 권장 기술입니다.
답변
크로스 브라우저 일관성 있고 표준화 된 델타 (-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 | | | | | | |
답변
어느 정도 독립적 인 솔루션 …
그러나 이벤트 사이에는 시간이 걸리지 않습니다. 일부 브라우저는 항상 동일한 델타로 이벤트를 발생시키는 것으로 보이며 빠르게 스크롤 할 때 더 빠르게 작동합니다. 다른 사람들은 델타를 변경합니다. 시간을 고려한 적응 형 노멀 라이저를 상상할 수 있지만 다소 복잡하고 사용하기 어려울 수 있습니다.
여기서 작업 가능 : 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(); }
}
답변
간단하고 효과적인 솔루션 :
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;
}
답변
터치 장치에서 확대 / 축소를 지원하려면 동작 시작, 동작 변경 및 동작 종료 이벤트를 등록하고 event.scale 속성을 사용하십시오. 이에 대한 예제 코드 를 볼 수 있습니다 .
Firefox 17의 onwheel
경우 , 이벤트는 데스크탑 및 모바일 버전에서 지원 될 예정입니다 ( onwheel의 MDN 문서에 따라 ). 또한 Firefox의 경우 Gecko 특정 MozMousePixelScroll
이벤트가 유용 할 수 있습니다 (DOMMouseWheel 이벤트는 이제 Firefox에서 더 이상 사용되지 않으므로이 기능은 더 이상 사용되지 않음).
Windows의 경우 드라이버 자체가 WM_MOUSEWHEEL, WM_MOUSEHWHEEL 이벤트 (및 터치 패드 패닝에 대한 WM_GESTURE 이벤트)를 생성하는 것 같습니다. Windows 또는 브라우저가 마우스 휠 이벤트 값 자체를 정규화하지 않는 이유를 설명합니다 (값을 정규화하기 위해 신뢰할 수있는 코드를 작성할 수 없음을 의미 할 수 있음).
들어 onwheel
( 하지 으로 onMouseWheel) 이벤트 Internet Explorer에서 지원 IE9와 IE10에 대한, 당신은 또한 사용할 수있는 W3C 표준을 onwheel
이벤트를. 그러나 하나의 노치는 120과 다른 값일 수 있습니다 (예 : 이 테스트 페이지를 사용하여 마우스에서 단일 노치가 마우스에서 -120 대신 111 이 됨 ). 관련된 다른 휠 이벤트와 함께 다른 기사 를 썼습니다 .
기본적으로 휠 이벤트에 대한 자체 테스트 (스크롤 값을 정규화하려고합니다)에서 OS, 브라우저 공급 업체, 브라우저 버전, 이벤트 유형 및 장치 (Microsoft 틸트 휠 마우스, 랩톱 터치 패드 제스처)에 대해 다양한 값을 얻습니다. 스크롤 영역이있는 노트북 터치 패드, Apple 매직 마우스, Apple 강력한 마우스 스크롤 볼, Mac 터치 패드 등).
브라우저 구성 (예 : Firefox mousewheel.enable_pixel_scrolling, chrome –scroll-pixels = 150), 드라이버 설정 (예 : Synaptics 터치 패드) 및 OS 구성 (Windows 마우스 설정, OSX 마우스 환경 설정, X.org 버튼 설정).