UNPKG

plotboilerplate

Version:

A simple javascript plotting boilerplate for 2d stuff.

391 lines 13.9 kB
/** * @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