Skip to content

Commit 796b2a7

Browse files
committed
Mouse Scroll Events - added support for WheelEvent, fixes
- Added support for the Wheel Event, which is the DOM3 spec. - Wheel Scroll Event (old non-FF) and DOM Mouse Wheel (old FF) are supported via a non-exported reused wrapper object, WheelEventProxy. The proxy methods are generated one-time dynamically; future changes to the Mouse class (such as requiring an opt-in for mouse scroll events) could bypass secondary stub generation. - FIX: Only ONE of the mouse wheel events is listened too, newest standard first. This fixes a bug in FF where it would use the default DOMMouseWheel.
1 parent 52a39cd commit 796b2a7

1 file changed

Lines changed: 112 additions & 9 deletions

File tree

src/input/Mouse.js

Lines changed: 112 additions & 9 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,26 @@ 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+
// (These can probably be moved out of the cocoonJS check)
250+
// See https://developer.mozilla.org/en-US/docs/Web/Events/wheel
251+
if ('onwheel' in window || 'WindowEvent' in window)
252+
{
253+
// DOM3 Wheel Event: FF 17+, IE 9+, Chrome 31+, Safari 7+
254+
this.game.canvas.addEventListener('wheel', this._onMouseWheel, true);
255+
}
256+
else if ('onmousewheel' in window)
257+
{
258+
// Non-FF legacy: IE 6-9, Chrome 1-31, Safari 5-7.
259+
this.game.canvas.addEventListener('mousewheel', this._onMouseWheel, true);
260+
this._wheelEvent = new WheelEventProxy(-1/40, 1);
261+
}
262+
else if ('MouseScrollEvent' in window)
263+
{
264+
// FF prior to 17. This should probably be scrubbed.
265+
this.game.canvas.addEventListener('DOMMouseScroll', this._onMouseWheel, true);
266+
this._wheelEvent = new WheelEventProxy(1, 1);
267+
}
241268
}
242269

243270
},
@@ -400,10 +427,14 @@ Phaser.Mouse.prototype = {
400427
* The internal method that handles the mouse wheel event from the browser.
401428
*
402429
* @method Phaser.Mouse#onMouseWheel
403-
* @param {MouseEvent} event - The native event from the browser. This gets stored in Mouse.event.
430+
* @param {MouseEvent} event - The native event from the browser.
404431
*/
405432
onMouseWheel: function (event) {
406433

434+
if (this._wheelEvent) {
435+
event = this._wheelEvent.bindEvent(event);
436+
}
437+
407438
this.event = event;
408439

409440
if (this.capture)
@@ -412,7 +443,7 @@ Phaser.Mouse.prototype = {
412443
}
413444

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

417448
if (this.mouseWheelCallback)
418449
{
@@ -531,6 +562,8 @@ Phaser.Mouse.prototype = {
531562
this.game.canvas.removeEventListener('mouseup', this._onMouseUp, true);
532563
this.game.canvas.removeEventListener('mouseover', this._onMouseOver, true);
533564
this.game.canvas.removeEventListener('mouseout', this._onMouseOut, true);
565+
566+
this.game.canvas.removeEventListener('wheel', this._onMouseWheel, true);
534567
this.game.canvas.removeEventListener('mousewheel', this._onMouseWheel, true);
535568
this.game.canvas.removeEventListener('DOMMouseScroll', this._onMouseWheel, true);
536569

@@ -563,3 +596,73 @@ Object.defineProperty(Phaser.Mouse.prototype, "disabled", {
563596
}
564597

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

0 commit comments

Comments
 (0)