plotboilerplate
Version:
A simple javascript plotting boilerplate for 2d stuff.
391 lines • 13.9 kB
JavaScript
/**
* @author Ikaros Kappler
* @date 2018-03-19
* @modified 2018-04-28 Added the param 'wasDragged'.
* @modified 2018-08-16 Added the param 'dragAmount'.
* @modified 2018-08-27 Added the param 'element'.
* @modified 2018-11-11 Changed the scope from a simple global var to a member of window/_context.
* @modified 2018-11-19 Renamed the 'mousedown' function to 'down' and the 'mouseup' function to 'up'.
* @modified 2018-11-28 Added the 'wheel' listener.
* @modified 2018-12-09 Cleaned up some code.
* @modified 2019-02-10 Cleaned up some more code.
* @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
* @modified 2020-04-08 Fixed the click event (internally fired a 'mouseup' event) (1.0.10)
* @modified 2020-04-08 Added the optional 'name' property. (1.0.11)
* @modified 2020-04-08 The new version always installs internal listenrs to track drag events even
* if there is no external drag listener installed (1.1.0).
* @modified 2020-10-04 Added extended JSDoc comments.
* @modified 2020-11-25 Added the `isTouchEvent` param.
* @modified 2021-01-10 The mouse handler is now also working with SVGElements.
* @modified 2022-08-16 Fixed a bug in the mouse button detection.
* @version 1.2.1
*
* @file MouseHandler
* @public
**/
export class XMouseEvent extends MouseEvent {
}
export class XWheelEvent extends WheelEvent {
}
/**
* @classdesc A simple mouse handler for demos.
* Use to avoid load massive libraries like jQuery.
*
* @requires XYCoords
*/
export class MouseHandler {
/**
* The constructor.
*
* Pass the DOM element you want to receive mouse events from.
*
* Usage
* =====
* @example
* // Javascript
* new MouseHandler( document.getElementById('mycanvas') )
* .drag( function(e) {
* console.log( 'Mouse dragged: ' + JSON.stringify(e) );
* if( e.params.leftMouse ) ;
* else if( e.params.rightMouse ) ;
* } )
* .move( function(e) {
* console.log( 'Mouse moved: ' + JSON.stringify(e.params) );
* } )
* .up( function(e) {
* console.log( 'Mouse up. Was dragged?', e.params.wasDragged );
* } )
* .down( function(e) {
* console.log( 'Mouse down.' );
* } )
* .click( function(e) {
* console.log( 'Click.' );
* } )
* .wheel( function(e) {
* console.log( 'Wheel. delta='+e.deltaY );
* } )
*
* @example
* // Typescript
* new MouseHandler( document.getElementById('mycanvas') )
* .drag( (e:XMouseEvent) => {
* console.log( 'Mouse dragged: ' + JSON.stringify(e) );
* if( e.params.leftMouse ) ;
* else if( e.params.rightMouse ) ;
* } )
* .move( (e:XMouseEvent) => {
* console.log( 'Mouse moved: ' + JSON.stringify(e.params) );
* } )
* .up( (e:XMouseEvent) => {
* console.log( 'Mouse up. Was dragged?', e.params.wasDragged );
* } )
* .down( (e:XMouseEvent) => {
* console.log( 'Mouse down.' );
* } )
* .click( (e:XMouseEvent) => {
* console.log( 'Click.' );
* } )
* .wheel( (e:XWheelEvent) => {
* console.log( 'Wheel. delta='+e.deltaY );
* } )
*
* @constructor
* @instance
* @memberof MouseHandler
* @param {HTMLElement} element
**/
constructor(element, name) {
this.mouseDownPos = undefined;
this.mouseDragPos = undefined;
// TODO: cc
// private mousePos : { x:number, y:number }|undefined = undefined;
this.mouseButton = -1;
this.listeners = {};
this.installed = {};
this.handlers = {};
// +----------------------------------------------------------------------
// | Some private vars to store the current mouse/position/button state.
// +-------------------------------------------------
this.name = name;
this.element = element;
this.mouseDownPos = undefined;
this.mouseDragPos = undefined;
// this.mousePos = null;
this.mouseButton = -1;
this.listeners = {};
this.installed = {};
this.handlers = {};
// +----------------------------------------------------------------------
// | Define the internal event handlers.
// |
// | They will dispatch the modified event (relative mouse position,
// | drag offset, ...) to the callbacks.
// +-------------------------------------------------
const _self = this;
this.handlers["mousemove"] = (e) => {
if (_self.listeners.mousemove)
_self.listeners.mousemove(_self.mkParams(e, "mousemove"));
if (_self.mouseDragPos && _self.listeners.drag)
_self.listeners.drag(_self.mkParams(e, "drag"));
if (_self.mouseDownPos)
_self.mouseDragPos = _self.relPos(e);
};
this.handlers["mouseup"] = (e) => {
if (_self.listeners.mouseup)
_self.listeners.mouseup(_self.mkParams(e, "mouseup"));
_self.mouseDragPos = undefined;
_self.mouseDownPos = undefined;
_self.mouseButton = -1;
};
this.handlers["mousedown"] = (e) => {
_self.mouseDragPos = _self.relPos(e);
_self.mouseDownPos = _self.relPos(e);
_self.mouseButton = e.button;
if (_self.listeners.mousedown)
_self.listeners.mousedown(_self.mkParams(e, "mousedown"));
};
this.handlers["click"] = (e) => {
if (_self.listeners.click)
_self.listeners.click(_self.mkParams(e, "click"));
};
this.handlers["wheel"] = (e) => {
if (_self.listeners.wheel)
_self.listeners.wheel(_self.mkParams(e, "wheel"));
};
this.element.addEventListener("mousemove", this.handlers["mousemove"]);
this.element.addEventListener("mouseup", this.handlers["mouseup"]);
this.element.addEventListener("mousedown", this.handlers["mousedown"]);
this.element.addEventListener("click", this.handlers["click"]);
this.element.addEventListener("wheel", this.handlers["wheel"]);
}
/**
* Get relative position from the given MouseEvent.
*
* @name relPos
* @memberof MouseHandler
* @instance
* @private
* @param {MouseEvent} e - The mouse event to get the relative position for.
* @return {XYCoords} The relative mouse coordinates.
*/
relPos(e) {
return { x: e.offsetX, y: e.offsetY };
}
/**
* Build the extended event params.
*
* @name mkParams
* @memberof MouseHandler
* @instance
* @private
* @param {MouseEvent} event - The mouse event to get the relative position for.
* @param {string} eventName - The name of the firing event.
* @return {XMouseEvent}
*/
mkParams(event, eventName) {
var _a, _b;
const rel = this.relPos(event);
const xEvent = event;
xEvent.params = {
element: this.element,
name: eventName,
isTouchEvent: false,
pos: rel,
button: event.button, // this.mouseButton,
leftButton: event.button === 0, // this.mouseButton === 0,
middleButton: event.button === 1, // this.mouseButton === 1,
rightButton: event.button === 2, // this.mouseButton === 2,
mouseDownPos: (_a = this.mouseDownPos) !== null && _a !== void 0 ? _a : { x: NaN, y: NaN },
draggedFrom: (_b = this.mouseDragPos) !== null && _b !== void 0 ? _b : { x: NaN, y: NaN },
wasDragged: this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y),
dragAmount: this.mouseDragPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 }
};
return xEvent;
}
/**
* Install a new listener.
* Please note that this mouse handler can only handle one listener per event type.
*
* @name listenFor
* @memberof MouseHandler
* @instance
* @private
* @param {string} eventName - The name of the firing event to listen for.
* @return {void}
*/
listenFor(eventName) {
if (this.installed[eventName])
return;
// In the new version 1.1.0 has all internal listeners installed by default.
this.installed[eventName] = true;
}
/**
* Un-install a new listener.
*
* @name listenFor
* @memberof MouseHandler
* @instance
* @private
* @param {string} eventName - The name of the firing event to unlisten for.
* @return {void}
*/
unlistenFor(eventName) {
if (!this.installed[eventName])
return;
// In the new version 1.1.0 has all internal listeners installed by default.
delete this.installed[eventName];
}
/**
* Installer function to listen for a specific event: mouse-drag.
* Pass your callbacks here.
*
* Note: this support chaining.
*
* @name drag
* @memberof MouseHandler
* @instance
* @param {XMouseCallback} callback - The drag-callback to listen for.
* @return {MouseHandler} this
*/
drag(callback) {
if (this.listeners.drag)
this.throwAlreadyInstalled("drag");
this.listeners.drag = callback;
this.listenFor("mousedown");
this.listenFor("mousemove");
this.listenFor("mouseup");
return this;
}
/**
* Installer function to listen for a specific event: mouse-move.
* Pass your callbacks here.
*
* Note: this support chaining.
*
* @name move
* @memberof MouseHandler
* @instance
* @param {XMouseCallback} callback - The move-callback to listen for.
* @return {MouseHandler} this
*/
move(callback) {
if (this.listeners.mousemove)
this.throwAlreadyInstalled("mousemove");
this.listenFor("mousemove");
this.listeners.mousemove = callback;
return this;
}
/**
* Installer function to listen for a specific event: mouse-up.
* Pass your callbacks here.
*
* Note: this support chaining.
*
* @name up
* @memberof MouseHandler
* @instance
* @param {XMouseCallback} callback - The up-callback to listen for.
* @return {MouseHandler} this
*/
up(callback) {
if (this.listeners.mouseup)
this.throwAlreadyInstalled("mouseup");
this.listenFor("mouseup");
this.listeners.mouseup = callback;
return this;
}
/**
* Installer function to listen for a specific event: mouse-down.
* Pass your callbacks here.
*
* Note: this support chaining.
*
* @name down
* @memberof MouseHandler
* @instance
* @param {XMouseCallback} callback - The down-callback to listen for.
* @return {MouseHandler} this
*/
down(callback) {
if (this.listeners.mousedown)
this.throwAlreadyInstalled("mousedown");
this.listenFor("mousedown");
this.listeners.mousedown = callback;
return this;
}
/**
* Installer function to listen for a specific event: mouse-click.
* Pass your callbacks here.
*
* Note: this support chaining.
*
* @name click
* @memberof MouseHandler
* @instance
* @param {XMouseCallback} callback - The click-callback to listen for.
* @return {MouseHandler} this
*/
click(callback) {
if (this.listeners.click)
this.throwAlreadyInstalled("click");
this.listenFor("click");
this.listeners.click = callback;
return this;
}
/**
* Installer function to listen for a specific event: mouse-wheel.
* Pass your callbacks here.
*
* Note: this support chaining.
*
* @name wheel
* @memberof MouseHandler
* @instance
* @param {XWheelCallback} callback - The wheel-callback to listen for.
* @return {MouseHandler} this
*/
wheel(callback) {
if (this.listeners.wheel)
this.throwAlreadyInstalled("wheel");
this.listenFor("wheel");
this.listeners.wheel = callback;
return this;
}
/**
* An internal function to throw events.
*
* @name throwAlreadyInstalled
* @memberof MouseHandler
* @instance
* @private
* @param {string} name - The name of the event.
* @return {void}
*/
throwAlreadyInstalled(name) {
throw `This MouseHandler already has a '${name}' callback. To keep the code simple there is only room for one.`;
}
/**
* Call this when your work is done.
*
* The function will un-install all event listeners.
*
* @name destroy
* @memberof MouseHandler
* @instance
* @private
* @return {void}
*/
destroy() {
this.unlistenFor("mousedown");
this.unlistenFor("mousemove");
this.unlistenFor("moseup");
this.unlistenFor("click");
this.unlistenFor("wheel");
this.element.removeEventListener("mousemove", this.handlers["mousemove"]);
this.element.removeEventListener("mouseup", this.handlers["mousedown"]);
this.element.removeEventListener("mousedown", this.handlers["mousedown"]);
this.element.removeEventListener("click", this.handlers["click"]);
this.element.removeEventListener("wheel", this.handlers["wheel"]);
}
}
//# sourceMappingURL=MouseHandler.js.map