import InputHandler from "./input_handler.js"; import EventHandlerLayer from "../../event/event_handler_layer.js"; import Vec2 from "../../game/vector/vec2.js"; /** * @module MouseHandler * @fileoverview Contains MouseHandler class. */ /** * Mouse input handler. * @class * @extends InputHandler */ class MouseHandler extends InputHandler { /** * Create a new mouse input handler. * @param {EventHandler|EventHandlerLayer} parentHandler Parent event handler or layer * @param {function} condition Function for checking whether events should run * @constructor */ constructor(parentHandler, condition = () => { return true; }) { const handler = new EventHandlerLayer(parentHandler, "mouse/"); super(handler, "", condition); this._other = handler; this._pos = new Vec2(); this._captured = false; this._downHandler = this._handleDown.bind(this); this._upHandler = this._handleUp.bind(this); this._moveHandler = this._handleMove.bind(this); this._wheelHandler = this._handleWheel.bind(this); this._blurHandler = this._handleBlur.bind(this); this._init(); } destructor() { super.destructor(); document.removeEventListener("mousedown", this._downHandler); document.removeEventListener("mouseup", this._upHandler); document.removeEventListener("mousemove", this._moveHandler); document.removeEventListener("wheel", this._wheelHandler); document.removeEventListener("blur", this._blurHandler); } /** * Set up mouse input listening. * @private */ _init() { document.addEventListener("mousedown", this._downHandler); document.addEventListener("mouseup", this._upHandler); document.addEventListener("mousemove", this._moveHandler); document.addEventListener("wheel", this._wheelHandler); window.addEventListener("blur", this._blurHandler); } // Getters /** * Get the current position of the mouse. * @returns {Vec2} Current position of mouse. */ get pos() { return this._pos.copy(); } /** * Check if the mouse is currently within the canvas. * @returns {boolean} Whether mouse is within canvas */ isInWindow() { const pos = this.pos; const c = $$.canvas; return pos.x >= 0 && pos.x <= c.width && pos.y >= 0 && pos.y <= c.height; } // Mouse movement /** * Add a function to listen for mouse movement. * @param {function} func Function to run upon mouse movement */ onMove(func = () => {}) { this._other.on("move", func); } /** * Handle mouse movement. * @param {number} x Current mouse position along the x-axis * @param {number} y Current mouse position along the y-axis * @private */ _doMove(x, y) { if (!this._condition()) return; const newPos = new Vec2(x, y); const d = newPos.sub(this._pos); this._pos = newPos; this._other.do("move", d); } // Mouse scroll wheel /** * Add a function to listen for the mouse scroll wheel. * @param {function} func Function to run upon scrolling */ onScroll(func = () => {}) { this._other.on("scroll", func); } /** * Handle scrolling. * @param {number} val Scroll value * @private */ _doScroll(val) { if (!this._condition()) return; this._other.do("scroll", val); } // Cursor /** * Set the mouse cursor ("default" by default). * @param {string} cursor New cursor */ setCursor(cursor = "default") { if (!this._condition()) return; document.body.style.cursor = cursor; } // Handling button presses /** * Handle the event of pressing down a button. * @param {MouseEvent} event Event from document * @private */ _handleDown(event) { if (!this.gameFocused()) return; const button = event.button; if (!this._currentlyDown.has(button)) this._doPress(button); this._currentlyDown.add(button); this._doDown(button); } /** * Handle the event of releasing a button. * @param {MouseEvent} event Event from document * @private */ _handleUp(event) { const button = event.button; if (!this.gameFocused()) { this._currentlyDown.delete(button); return; } this._currentlyDown.delete(button); this._doRelease(button); } /** * Handle the event of mouse movement. * @param {MouseEvent} event Event from document * @private */ _handleMove(event) { this._doMove(event.pageX - $$.app.canvas.offsetLeft, event.pageY - $$.app.canvas.offsetTop); } /** * Handle the event of pressing down a button. * @param {WheelEvent} event Event from document * @private */ _handleWheel(event) { this._doScroll(-Math.sign(event.deltaY)); } /** * Handle the event of the page losing focus. * @private */ _handleBlur() { this._currentlyDown.clear(); } // Capture mouse /** * Capture and "claim" the mouse * @returns {boolean} Whether capture was successful */ capture() { if (this._captured) return false; this._captured = true; return true; } /** * Release the mouse. */ release() { this._captured = false; } /** * Check if the mouse is currently captured. * @returns {boolean} Whether the mouse is captured */ isCaptured() { return this._captured; } } export default MouseHandler;