js/Mobilizing/input/Mouse.js
import * as debug from '../core/util/Debug';
import Time from '../time/Time';
import Device from '../core/util/Device';
import * as _DOM from '../core/util/Dom';
import Component from '../core/Component';
// Events
/**
* Fired when the mouse postupdate is called
* @event mouseupdate
*/
const EVT_MOUSE_UPDATE = "mouseupdate";
/**
* Fired when a mouse move is detected
* @event mousemove
*/
const EVT_MOUSE_MOVE = 'mousemove';
/**
* Fired when the pointer moves onto the target element
* @event mouseover
*/
const EVT_MOUSE_OVER = 'mouseover';
/**
* Fired when the pointer moves off the target element
* @event mouseout
*/
const EVT_MOUSE_OUT = 'mouseout';
/**
* Fired when a button is pressed
* @event mousepress
* @param {Number} button The button number pressed
*/
const EVT_MOUSE_PRESS = 'mousepress';
/**
* Fired when a mouse move is detected and a button is being pressed
* @event mousedrag
*/
const EVT_MOUSE_DRAG = 'mousedrag';
/**
* Fired when a button is released
* @event mouserelease
*/
const EVT_MOUSE_RELEASE = 'mouserelease';
/**
* Fired when a button is pressed and released on the target element
* @event mouseclick
* @param {Number} button The button number pressed
*/
const EVT_MOUSE_CLICK = 'mouseclick';
/**
* Fired when a button is clicked twice on the target element
* @event mousedblclick
* @param {Number} button The button number pressed
*/
const EVT_MOUSE_DBLCLICK = 'mousedblclick';
/**
* Fired when the wheel button is rotated
* @event mousewheel
* @param {Number} deltaX The scroll amount for the x-axis
* @param {Number} deltaY The scroll amount for the y-axis
* @param {Number} deltaZ The scroll amount for the z-axis
*/
const EVT_MOUSE_WHEEL = 'mousewheel';
const EVT_SWIPE_UP = "swipeup";
const EVT_SWIPE_DOWN = "swipedown";
const EVT_SWIPE_LEFT = "swipeleft";
const EVT_SWIPE_RIGHT = "swiperight";
/**
* Give simple access to mouse events
*/
export default class Mouse extends Component {
/**
* @param {Object} params Parameters object, given by the constructor.
* @param {DOMElement} params.target The DOM element that will be used to attach mouse events on
*/
constructor({
target = window,
} = {}) {
super(...arguments);
this.target = target;
this._time = new Time();
this.chain(this._time);
//window.addEventListener("resize", (event) => this.onWindowResize(event), false);
}
setup() {
if (!this._setupDone) {
this._time.setup();
this._time.on();
this._x = null;
this._y = null;
this._pX = null;
this._pY = null;
this._dragStartX = null;
this._dragStartY = null;
// keeps track of total wheel deltas between two updates
this._wheelDeltaX = 0;
this._wheelDeltaY = 0;
this._wheelDeltaZ = 0;
// keeps track of whether a button is being pressed
this._pressed = false;
// keeps track of whether the wheel has been activated since last update
this._wheelActivated = false;
// keeps track of whether the wheel values should be reset during next update
this._resetWheel = false;
this._swipeMaxTime = 250;
this._swipeMinDist = 100;
super.setup();
}
}
on() {
super.on();
if (!this.target) {
debug.error("Can't activate the mouse input component without a target");
return;
}
this.target.addEventListener("mousemove", (event) => this.onMouseMove(event));
this.target.addEventListener("mouseover", (event) => this.onMouseOver(event));
this.target.addEventListener("mouseout", (event) => this.onMouseOut(event));
this.target.addEventListener("mousedown", (event) => this.onMouseDown(event));
this.target.addEventListener("mouseup", (event) => this.onMouseUp(event));
this.target.addEventListener("click", (event) => this.onClick(event));
this.target.addEventListener("dblclick", (event) => this.onDblClick(event));
this.target.addEventListener("wheel", (event) => this.onWheel(event));
}
off() {
super.off();
if (!this.target) {
debug.error("Can't deactivate the mouse input component without a target");
return;
}
this.target.removeEventListener("mousemove", (event) => this.onMouseMove(event));
this.target.removeEventListener("mouseover", (event) => this.onMouseOver(event));
this.target.removeEventListener("mouseout", (event) => this.onMouseOut(event));
this.target.removeEventListener("mousedown", (event) => this.onMouseDown(event));
this.target.removeEventListener("mouseup", (event) => this.onMouseUp(event));
this.target.removeEventListener("click", (event) => this.onClick(event));
this.target.removeEventListener("dblclick", (event) => this.onDblClick(event));
this.target.removeEventListener("wheel", (event) => this.onWheel(event));
}
preUpdate() {
// check if the wheel was already active at previous update and if it needs to be reset
if (this._wheelActivated) {
if (this._resetWheel) {
this._wheelActivated = false;
this._resetWheel = false;
this._wheelDeltaX = 0;
this._wheelDeltaY = 0;
this._wheelDeltaZ = 0;
}
else {
this._resetWheel = true;
}
}
}
// update()
// {
// }
postUpdate() {
// update the previous x and y coordinates
this._pX = this._x;
this._pY = this._y;
this.events.trigger(EVT_MOUSE_UPDATE, {
"pX": this.getPX(),
"pY": this.getPY(),
"x": this.getX(),
"y": this.getY()
});
}
/**
mousemove event handler
Fires a mousemove event and possibly a mousedrag event
@private
*/
onMouseMove(event) {
if (!(this.target instanceof Window)) {
const position = _DOM.getElementPosition(this.target);
this._x = event.clientX - position.x;
this._y = event.clientY - position.y;
}
else {
this._x = event.clientX;
this._y = event.clientY;
}
this.events.trigger(EVT_MOUSE_MOVE, {
"pX": this.getPX(),
"pY": this.getPY(),
"x": this.getX(),
"y": this.getY()
});
if (this.isPressed()) {
this.events.trigger(EVT_MOUSE_DRAG, {
"pX": this.getPX(),
"pY": this.getPY(),
"x": this.getX(),
"y": this.getY()
});
}
event.preventDefault();
}
/**
mouseover event handler
Fires a mouseover event
@private
*/
onMouseOver(event) {
this.events.trigger(EVT_MOUSE_OVER);
event.preventDefault();
}
/**
mouseover event handler
Fires a mouseout event
@private
*/
onMouseOut(event) {
this.events.trigger(EVT_MOUSE_OUT);
event.preventDefault();
}
/**
mousedown event handler
Fires a mousepress event and updates the pressed state
@private
*/
onMouseDown(event) {
this._pressed = true;
this._dragStartX = this.getX();
this._dragStartY = this.getY();
this.events.trigger(EVT_MOUSE_PRESS, event.button, this.getX(), this.getY());
//swipe management
this._swipeStartTime = this._time.currentTime;
event.preventDefault();
}
/**
mouseup event handler
Fires a mouserelease event and updates the pressed state
@private
*/
onMouseUp(event) {
//swipe
let swiping = false;
this._swipeCurrentTime = this._time.currentTime;
this._swipeTime = this._swipeCurrentTime - this._swipeStartTime;
if (this._swipeTime < this._swipeMaxTime) {
let xAxisValidated = false;
//x + axis validation
if (this.getDragOffsetX() > this.getDragOffsetY()) {
if (this.getDragOffsetX() > this._swipeMinDist) {
//console.log("swipeX+");
this.events.trigger(EVT_SWIPE_RIGHT);
xAxisValidated = true;
swiping = true;
}
}
//x - axis validated
else if (this.getDragOffsetX() < this.getDragOffsetY()) {
if (this.getDragOffsetX() < -this._swipeMinDist) {
//console.log("swipeX-");
this.events.trigger(EVT_SWIPE_LEFT);
xAxisValidated = true;
swiping = true;
}
}
//avoid double axis swipe
if (!xAxisValidated) {
//y + axis validation
if (this.getDragOffsetY() > this.getDragOffsetX()) {
if (this.getDragOffsetY() > this._swipeMinDist) {
//console.log("swipeY+");
this.events.trigger(EVT_SWIPE_DOWN);
swiping = true;
}
}
//y - axis validated
else if (this.getDragOffsetY() < -this.getDragOffsetX()) {
if (this.getDragOffsetY() < -this._swipeMinDist) {
//console.log("swipeY-");
this.events.trigger(EVT_SWIPE_UP);
swiping = true;
}
}
}
}
this._pressed = false;
this._dragStartX = null;
this._dragStartY = null;
//to avoid unwanted double behavior : swipe is activated, but release also. "up" is not fired if swipe is ongoing
if (!swiping) {
this.events.trigger(EVT_MOUSE_RELEASE);
}
event.preventDefault();
}
/**
cick event handler
Fires a mouseclick event
@private
*/
onClick(event) {
this.events.trigger(EVT_MOUSE_CLICK, event.button, this.getX(), this.getY());
//swipe management
this._swipeStartTime = this._time.currentTime;
event.preventDefault();
}
/**
dblcick event handler
Fires a mousedblclick event
@private
*/
onDblClick(event) {
this.events.trigger(EVT_MOUSE_DBLCLICK, event.button, this.getX(), this.getY());
event.preventDefault();
}
/**
wheel event handler
Fires a mousewheel event
@private
*/
onWheel(event) {
this._wheelActivated = true;
this._wheelDeltaX += event.deltaX;
this._wheelDeltaY += event.deltaY;
this._wheelDeltaZ += event.deltaZ;
this.events.trigger(EVT_MOUSE_WHEEL, event.deltaX, event.deltaY, event.deltaZ);
//event.preventDefault();
}
/**
returns whether a mouse button is currently pressed or not
@return {Boolean} True if a mouse button is currently pressed
*/
isPressed() {
return this._pressed;
}
/**
returns the current x coordinate of the mouse
@return {Number} The x coordinate of the mouse position
*/
getX() {
return this._x;
}
/**
returns the current y coordinate of the mouse
@return {Number} The y coordinate of the mouse position
*/
getY() {
return this._y;
}
/**
returns the previous x coordinate of the mouse
@return {Number} The x coordinate of the previous mouse position
*/
getPX() {
return this._pX;
}
/**
returns the previous y coordinate of the mouse
@return {Number} The y coordinate of the previous mouse position
*/
getPY() {
return this._pY;
}
/**
returns the x delta between the previous and current mouse positions
@return {Number} The x delta value
*/
getDeltaX() {
return this._x - this._pX;
}
/**
returns the y delta between the previous and current mouse positions
@return {Number} The y delta value
*/
getDeltaY() {
return this._y - this._pY;
}
/**
returns the x and y deltas between the previous and current mouse positions
@return {Object} The x and y delta values
*/
getDelta() {
return {
"x": this.getDeltaX(),
"y": this.getDeltaY()
};
}
/**
returns the x offset between the current mouse position and the position at the begining of the drag
@return {Number} The x offset value
*/
getDragOffsetX() {
if (!this.isPressed()) {
return 0;
}
return this.getX() - this._dragStartX;
}
/**
returns the y offset between the current mouse position and the position at the begining of the drag
@return {Number} The y offset value
*/
getDragOffsetY() {
if (!this.isPressed()) {
return 0;
}
return this.getY() - this._dragStartY;
}
/**
returns the x and y offsets between the current mouse position and the position at the begining of the drag
@return {Object} The x and y offset values
*/
getDragOffset() {
return {
'x': this.getDragOffsetX(),
'y': this.getDragOffsetY()
};
}
/**
helper method to check if the wheel is supported on the device
@return {Boolean} True if the wheel is supported, false otherwise
*/
isWheelSupported() {
return (Device.getType() === "desktop") && (window.WheelEvent !== undefined);
}
/**
helper method to check if the wheel has been rotated
@return {Boolean} True if the wheel has been rotated, false otherwise
*/
isWheelActivated() {
return this._wheelActivated;
}
/**
returns the scroll amount for the x-axis
@return {Number} The scroll amount for the x-axis
*/
getWheelDeltaX() {
return this._wheelDeltaX;
}
/**
returns the scroll amount for the y-axis
@return {Number} The scroll amount for the y-axis
*/
getWheelDeltaY() {
return this._wheelDeltaY;
}
/**
returns the scroll amount for the z-axis
@return {Number} The scroll amount for the z-axis
*/
getWheelDeltaZ() {
return this._wheelDeltaZ;
}
/**
returns the scroll amounts for the x, y and z axes
@return {Object} The scroll amounts for the x, y and z axes
*/
getWheelDelta() {
return {
"x": this.getWheelDeltaX(),
"y": this.getWheelDeltaY(),
"z": this.getWheelDeltaZ()
};
}
}