Skip to content

Commit 824c0e2

Browse files
committed
Merge pull request #1318 from pnstickne/wip-wheel-scroll-updates
Mouse Scroll Events - added support for WheelEvent, fixes
2 parents d786d4e + 7004d68 commit 824c0e2

File tree

2 files changed

+170
-29
lines changed

2 files changed

+170
-29
lines changed

src/input/Mouse.js

Lines changed: 111 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Phaser.Mouse = function (game) {
6868
this.button = -1;
6969

7070
/**
71-
* @property {number} wheelDelta - The direction of the mousewheel usage 1 for up -1 for down
71+
* @property {number} wheelDelta - The direction of the _last_ mousewheel usage 1 for up -1 for down
7272
*/
7373
this.wheelDelta = 0;
7474

@@ -98,7 +98,9 @@ Phaser.Mouse = function (game) {
9898
this.pointerLock = new Phaser.Signal();
9999

100100
/**
101-
* @property {MouseEvent} event - The browser mouse DOM event. Will be set to null if no mouse event has ever been received.
101+
* The browser mouse DOM event. Will be null if no mouse event has ever been received.
102+
* Access this property only inside a Mouse event handler and do not keep references to it.
103+
* @property {MouseEvent|null} event
102104
* @default
103105
*/
104106
this.event = null;
@@ -134,11 +136,18 @@ Phaser.Mouse = function (game) {
134136
this._onMouseOver = null;
135137

136138
/**
137-
* @property {function} _onMouseWheel - Internal event handler reference.
138-
* @private
139-
*/
139+
* @property {function} _onMouseWheel - Internal event handler reference.
140+
* @private
141+
*/
140142
this._onMouseWheel = null;
141143

144+
/**
145+
* Wheel proxy event object, if required. Shared for all wheel events for this mouse.
146+
* @property {Phaser.Mouse~WheelEventProxy} _wheelEvent
147+
* @private
148+
*/
149+
this._wheelEvent = null;
150+
142151
};
143152

144153
/**
@@ -236,8 +245,21 @@ Phaser.Mouse.prototype = {
236245
window.addEventListener('mouseup', this._onMouseUpGlobal, true);
237246
this.game.canvas.addEventListener('mouseover', this._onMouseOver, true);
238247
this.game.canvas.addEventListener('mouseout', this._onMouseOut, true);
239-
this.game.canvas.addEventListener('mousewheel', this._onMouseWheel, true);
240-
this.game.canvas.addEventListener('DOMMouseScroll', this._onMouseWheel, true);
248+
}
249+
250+
var wheelEvent = this.game.device.wheelEvent;
251+
if (wheelEvent)
252+
{
253+
this.game.canvas.addEventListener(wheelEvent, this._onMouseWheel, true);
254+
255+
if (wheelEvent === 'mousewheel')
256+
{
257+
this._wheelEvent = new WheelEventProxy(-1/40, 1);
258+
}
259+
else if (wheelEvent === 'DOMMouseScroll')
260+
{
261+
this._wheelEvent = new WheelEventProxy(1, 1);
262+
}
241263
}
242264

243265
},
@@ -400,10 +422,14 @@ Phaser.Mouse.prototype = {
400422
* The internal method that handles the mouse wheel event from the browser.
401423
*
402424
* @method Phaser.Mouse#onMouseWheel
403-
* @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
425+
* @param {MouseEvent} event - The native event from the browser.
404426
*/
405427
onMouseWheel: function (event) {
406428

429+
if (this._wheelEvent) {
430+
event = this._wheelEvent.bindEvent(event);
431+
}
432+
407433
this.event = event;
408434

409435
if (this.capture)
@@ -412,7 +438,7 @@ Phaser.Mouse.prototype = {
412438
}
413439

414440
// reverse detail for firefox
415-
this.wheelDelta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
441+
this.wheelDelta = Phaser.Math.clamp(-event.deltaY, -1, 1);
416442

417443
if (this.mouseWheelCallback)
418444
{
@@ -531,8 +557,12 @@ Phaser.Mouse.prototype = {
531557
this.game.canvas.removeEventListener('mouseup', this._onMouseUp, true);
532558
this.game.canvas.removeEventListener('mouseover', this._onMouseOver, true);
533559
this.game.canvas.removeEventListener('mouseout', this._onMouseOut, true);
534-
this.game.canvas.removeEventListener('mousewheel', this._onMouseWheel, true);
535-
this.game.canvas.removeEventListener('DOMMouseScroll', this._onMouseWheel, true);
560+
561+
var wheelEvent = this.game.device.wheelEvent;
562+
if (wheelEvent)
563+
{
564+
this.game.canvas.removeEventListener(wheelEvent, this._onMouseWheel, true);
565+
}
536566

537567
window.removeEventListener('mouseup', this._onMouseUpGlobal, true);
538568

@@ -563,3 +593,73 @@ Object.defineProperty(Phaser.Mouse.prototype, "disabled", {
563593
}
564594

565595
});
596+
597+
/* jshint latedef:nofunc */
598+
/**
599+
* A purely internal event support class to proxy 'wheelscroll' and 'DOMMouseWheel'
600+
* events to 'wheel'-like events.
601+
*
602+
* See https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel for choosing a scale and delta mode.
603+
*
604+
* @class Phaser.Mouse~WheelEventProxy
605+
* @private
606+
* @param {number} scaleFactor - Scale factor as applied to wheelDelta/wheelDeltaX or details.
607+
* @param {integer} deltaMode - The reported delta mode.
608+
*/
609+
function WheelEventProxy (scaleFactor, deltaMode) {
610+
611+
this._scaleFactor = scaleFactor;
612+
613+
this._deltaMode = deltaMode;
614+
615+
/**
616+
* The original event _currently_ being proxied; the getters will follow suit.
617+
*/
618+
this.originalEvent = null;
619+
}
620+
621+
WheelEventProxy.prototype = {};
622+
WheelEventProxy.prototype.constructor = WheelEventProxy;
623+
624+
WheelEventProxy.prototype.bindEvent = function (event) {
625+
626+
// Generate stubs automatically
627+
if (!WheelEventProxy._stubsGenerated && event)
628+
{
629+
var makeBinder = function (name) {
630+
return function () {
631+
var v = this.originalEvent[name];
632+
return typeof v !== 'function' ? v : v.bind(this.originalEvent);
633+
};
634+
};
635+
for (var prop in event) {
636+
if (!(prop in WheelEventProxy.prototype))
637+
{
638+
Object.defineProperty(WheelEventProxy.prototype, prop, {
639+
get: makeBinder(prop)
640+
});
641+
}
642+
}
643+
WheelEventProxy._stubsGenerated = true;
644+
}
645+
646+
this.originalEvent = event;
647+
return this;
648+
649+
};
650+
651+
Object.defineProperties(WheelEventProxy.prototype, {
652+
"type": { value: "wheel" },
653+
"deltaMode": { get: function () { return this._deltaMode; } },
654+
"deltaY": {
655+
get: function () {
656+
return (this._scaleFactor * (this.originalEvent.wheelDelta || this.originalEvent.detail)) || 0;
657+
}
658+
},
659+
"deltaX": {
660+
get: function () {
661+
return (this._scaleFactor * this.originalEvent.wheelDeltaX) || 0;
662+
}
663+
},
664+
"deltaZ": { value: 0 }
665+
});

src/system/Device.js

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,6 @@ Phaser.Device = function (game) {
147147
*/
148148
this.worker = false;
149149

150-
/**
151-
* @property {boolean} touch - Is touch available?
152-
* @default
153-
*/
154-
this.touch = false;
155-
156-
/**
157-
* @property {boolean} mspointer - Is mspointer available?
158-
* @default
159-
*/
160-
this.mspointer = false;
161-
162150
/**
163151
* @property {boolean} css3D - Is css3D available?
164152
* @default
@@ -195,6 +183,27 @@ Phaser.Device = function (game) {
195183
*/
196184
this.quirksMode = false;
197185

186+
// Input
187+
188+
/**
189+
* @property {boolean} touch - Is touch available?
190+
* @default
191+
*/
192+
this.touch = false;
193+
194+
/**
195+
* @property {boolean} mspointer - Is mspointer available?
196+
* @default
197+
*/
198+
this.mspointer = false;
199+
200+
/**
201+
* @property {string|null} wheelType - The newest type of Wheel/Scroll event supported: 'wheel', 'mousewheel', 'DOMMouseScroll'
202+
* @default
203+
* @protected
204+
*/
205+
this.wheelEvent = null;
206+
198207
// Browser
199208

200209
/**
@@ -401,6 +410,7 @@ Phaser.Device = function (game) {
401410
this._checkCSS3D();
402411
this._checkDevice();
403412
this._checkFeatures();
413+
this._checkInput();
404414

405415
};
406416

@@ -500,7 +510,24 @@ Phaser.Device.prototype = {
500510

501511
this.worker = !!window['Worker'];
502512

503-
if ('ontouchstart' in document.documentElement || (window.navigator.maxTouchPoints && window.navigator.maxTouchPoints > 1))
513+
this.pointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
514+
515+
this.quirksMode = (document.compatMode === 'CSS1Compat') ? false : true;
516+
517+
this.getUserMedia = !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
518+
519+
},
520+
521+
/**
522+
* Checks/configures various input.
523+
*
524+
* @method Phaser.Device#checkInput
525+
* @private
526+
*/
527+
_checkInput: function () {
528+
529+
if ('ontouchstart' in document.documentElement ||
530+
(window.navigator.maxTouchPoints && window.navigator.maxTouchPoints > 1))
504531
{
505532
this.touch = true;
506533
}
@@ -510,11 +537,25 @@ Phaser.Device.prototype = {
510537
this.mspointer = true;
511538
}
512539

513-
this.pointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
514-
515-
this.quirksMode = (document.compatMode === 'CSS1Compat') ? false : true;
516-
517-
this.getUserMedia = !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
540+
if (!this.cocoonJS)
541+
{
542+
// See https://developer.mozilla.org/en-US/docs/Web/Events/wheel
543+
if ('onwheel' in window || (this.ie && 'WheelEvent' in window))
544+
{
545+
// DOM3 Wheel Event: FF 17+, IE 9+, Chrome 31+, Safari 7+
546+
this.wheelEvent = 'wheel';
547+
}
548+
else if ('onmousewheel' in window)
549+
{
550+
// Non-FF legacy: IE 6-9, Chrome 1-31, Safari 5-7.
551+
this.wheelEvent = 'mousewheel';
552+
}
553+
else if (this.firefox && 'MouseScrollEvent' in window)
554+
{
555+
// FF prior to 17. This should probably be scrubbed.
556+
this.wheelEvent = 'DOMMouseScroll';
557+
}
558+
}
518559

519560
},
520561

0 commit comments

Comments
 (0)