Skip to content

Commit

Permalink
Initial draft of mouse wheel support excaliburjs#808
Browse files Browse the repository at this point in the history
- Added event "wheel"
- Added sandbox pointer wheel test
- Added docs
  • Loading branch information
Kevin Gravier committed May 12, 2017
1 parent a6f90ef commit 0be0022
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 5 deletions.
4 changes: 3 additions & 1 deletion sandbox/tests/input/pointer.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
<dd id="pointer-screen-pos"></dd>
<dt>Last Pointer World Pos (x,y)</dt>
<dd id="pointer-world-pos"></dd>
<dt>Last Wheel Deltas (x,y,z,mode)</dt>
<dd id="pointer-wheel-deltas"></dd>
</dl>

<script src="../../Excalibur.js"></script>
<script src="../../excalibur.js"></script>
<script src="pointer.js"></script>
</body>
</html>
13 changes: 12 additions & 1 deletion sandbox/tests/input/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ game.input.pointers.primary.on("up", (pe: ex.Input.PointerEvent) => {
document.getElementById("pointer-btn").innerHTML = "";
});

// Wheel
game.input.pointers.primary.on("wheel", (pe: ex.Input.WheelEvent) => {
var type: string;
switch (pe.deltaMode) {
case ex.Input.WheelDeltaMode.Pixel: type = "pixel"; break;
case ex.Input.WheelDeltaMode.Line: type = "line"; break;
case ex.Input.WheelDeltaMode.Page: type = "page"; break;
}
document.getElementById("pointer-wheel-deltas").innerHTML = pe.deltaX + ", " + pe.deltaY + ", " + pe.deltaZ + ", " + type;
});

var paintBrush = {
paint: (x: number, y: number, color: ex.Color) => {
var brush = new ex.Actor(x, y, 5, 5, color);
Expand Down Expand Up @@ -104,4 +115,4 @@ game.currentScene.camera.y = 0;
game.add(box);
game.add(cursor);
game.add(uiElement);
game.start();
game.start();
13 changes: 12 additions & 1 deletion src/engine/Docs/Pointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ engine.input.pointers.primary.on("move", function (evt) { });
engine.input.pointers.primary.on("cancel", function (evt) { });
```

### Wheel Event

You can also subscribe to the mouse wheel event through `engine.input.points.on`. A [[WheelEvent]]
object is passed to your handler which offers information about the wheel event being received.

- `wheel` - When a mousewheel is activated (trackpad scroll or mouse wheel)

```js
engine.input.pointers.primary.on("wheel", function (evt) { });
```

## Last position querying

If you don't wish to subscribe to events, you can also access the [[Pointer.lastPagePos]], [[Pointer.lastScreenPos]]
Expand Down Expand Up @@ -129,4 +140,4 @@ player.capturePointer.captureMoveEvents = true;
player.on("pointerup", function (ev) {
player.logger.info("Player selected!", ev);
});
```
```
3 changes: 2 additions & 1 deletion src/engine/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type up = 'up';
export type down = 'down';
export type move = 'move';
export type cancel = 'cancel';
export type wheel = 'wheel';

export type press = 'press';
export type release = 'release';
Expand Down Expand Up @@ -336,4 +337,4 @@ export class EnterViewPortEvent extends GameEvent<Actor> {
constructor(public target: Actor) {
super();
}
}
}
117 changes: 116 additions & 1 deletion src/engine/Input/Pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ export enum PointerButton {
Unknown
}

export enum WheelDeltaMode {
Pixel,
Line,
Page
}

/**
* Determines the scope of handling mouse/touch events. See [[Pointers]] for more information.
*/
Expand Down Expand Up @@ -79,6 +85,44 @@ export class PointerEvent extends GameEvent<any> {
}
};

/**
* Wheel Events
*
* Represents a mouse wheel event. See [[Pointers]] for more information on
* handling point input.
*/
export class WheelEvent extends GameEvent<any> {

/**
* @param x The `x` coordinate of the event (in world coordinates)
* @param y The `y` coordinate of the event (in world coordinates)
* @param pageX The `x` coordinate of the event (in document coordinates)
* @param pageY The `y` coordinate of the event (in document coordinates)
* @param screenX The `x` coordinate of the event (in screen coordinates)
* @param screenY The `y` coordinate of the event (in screen coordinates)
* @param index The index of the pointer (zero-based)
* @param deltaX The type of pointer
* @param deltaY The type of pointer
* @param deltaZ The type of pointer
* @param deltaMode The type of movement [[WheelDeltaMode]]
* @param ev The raw DOM event being handled
*/
constructor(public x: number,
public y: number,
public pageX: number,
public pageY: number,
public screenX: number,
public screenY: number,
public index: number,
public deltaX: number,
public deltaY: number,
public deltaZ: number,
public deltaMode: WheelDeltaMode,
public ev: any) {
super();
}
};

/**
* Handles pointer events (mouse, touch, stylus, etc.) and normalizes to
* [W3C Pointer Events](http://www.w3.org/TR/pointerevents/).
Expand All @@ -92,6 +136,7 @@ export class Pointers extends Class {
private _pointerUp: PointerEvent[] = [];
private _pointerMove: PointerEvent[] = [];
private _pointerCancel: PointerEvent[] = [];
private _wheel: WheelEvent[] = [];
private _pointers: Pointer[] = [];
private _activePointers: number[] = [];

Expand All @@ -108,6 +153,7 @@ export class Pointers extends Class {
public on(eventName: Events.down, handler: (event?: PointerEvent) => void): void;
public on(eventName: Events.move, handler: (event?: PointerEvent) => void): void;
public on(eventName: Events.cancel, handler: (event?: PointerEvent) => void): void;
public on(eventName: Events.wheel, handler: (event?: WheelEvent) => void): void;
public on(eventName: string, handler: (event?: GameEvent<any>) => void): void;
public on(eventName: string, handler: (event?: GameEvent<any>) => void): void {
super.on(eventName, handler);
Expand Down Expand Up @@ -160,6 +206,18 @@ export class Pointers extends Class {
target.addEventListener('mouseup', this._handleMouseEvent('up', this._pointerUp));
target.addEventListener('mousemove', this._handleMouseEvent('move', this._pointerMove));
}

// MDN MouseWheelEvent
if ('onwheel' in document.createElement("div")) {
// Modern Browsers
target.addEventListener('wheel', this._handleWheelEvent('wheel', this._wheel));
} else if (document.onmousewheel !== undefined) {
// Webkit and IE
target.addEventListener('mousewheel', this._handleWheelEvent('wheel', this._wheel));
} else {
// Remaining browser and older Firefox
target.addEventListener('MozMousePixelScroll', this._handleWheelEvent('wheel', this._wheel));
}
}

public update(): void {
Expand Down Expand Up @@ -236,6 +294,14 @@ export class Pointers extends Class {
actor.eventDispatcher.emit('pointercancel', this._pointerCancel[i]);
}
}

i = 0;
len = this._wheel.length;
for (i; i < len; i++) {
if (actor.contains(this._wheel[i].x, this._wheel[i].y, !isUIActor)) {
actor.eventDispatcher.emit('wheel', this._wheel[i]);
}
}
}

private _handleMouseEvent(eventName: string, eventArr: PointerEvent[]) {
Expand Down Expand Up @@ -309,6 +375,55 @@ export class Pointers extends Class {
};
}

private _handleWheelEvent(eventName: string, eventArr: WheelEvent[]) {
return (e: MouseWheelEvent) => {
e.preventDefault(); // TODO make this optional

var x: number = e.pageX - Util.getPosition(this._engine.canvas).x;
var y: number = e.pageY - Util.getPosition(this._engine.canvas).y;
var transformedPoint = this._engine.screenToWorldCoordinates(new Vector(x, y));

var deltaX = 0;
var deltaY = 0;
var deltaZ = 0;
var deltaMode = WheelDeltaMode.Pixel;

if (e.deltaX) {
deltaX = e.deltaX;
} else if (e.wheelDeltaX) {
deltaX = e.wheelDeltaX * (-1 / 40);
}

if (e.deltaY) {
deltaY = e.deltaY;
} else if (e.wheelDeltaY) {
deltaY = e.wheelDeltaY * (-1 / 40);
} else if (e.wheelDelta) {
deltaY = e.wheelDelta * (-1 / 40);
} else {
deltaY = e.detail;
}

if (e.deltaZ) {
deltaZ = e.deltaZ;
}

if (e.deltaMode) {
if (e.deltaMode === 1) {
deltaMode = WheelDeltaMode.Line;
} else if (e.deltaMode === 2) {
deltaMode = WheelDeltaMode.Page;
}
}

var we = new WheelEvent(transformedPoint.x, transformedPoint.y,
e.pageX, e.pageY, x, y, 0, deltaX, deltaY, deltaZ, deltaMode, e);

eventArr.push(we);
this.at(0).eventDispatcher.emit(eventName, we);
};
}

/**
* Gets the index of the pointer specified for the given pointer ID or finds the next empty pointer slot available.
* This is required because IE10/11 uses incrementing pointer IDs so we need to store a mapping of ID => idx
Expand Down Expand Up @@ -399,4 +514,4 @@ interface ITouch {
rotationAngle: number;
force: number;
target: Element;
}
}

0 comments on commit 0be0022

Please sign in to comment.