On this page

# Mouse.js

    /**
     * A NetLogo-like mouse handler.
     *
     * **TODO: Example usage.**
     */
    class Mouse {
        /**
         * Create and start mouse obj, args: a model, and a callback method.
         *
         * @param {Canvas|String} canvas The canvas upon which we track the mouse.
         *      If a string is given, get the HTML element by that name
         * @param {world} world World instance
         * @param {Function} callback callback(evt, mouse) called on every mouse action
         */
        constructor(canvas, world, callback = (evt, mouse) => {}) {
            if (typeof canvas === 'string') {
                canvas = document.getElementById(canvas)
            }
            Object.assign(this, { canvas, world, callback })

            // instance event handlers: arrow fcns to insure "this" is us.
            // I.e. doesn't work to just use handleXXX in addEventListener.
            this.mouseDown = e => this.handleMouseDown(e)
            this.mouseUp = e => this.handleMouseUp(e)
            this.mouseMove = e => this.handleMouseMove(e)
        }

        resetParams() {
            this.x = this.y = NaN
            this.moved = this.down = false
        }

        /**
         * Start/stop the mouseListeners.  Note that NetLogo's model is to have
         * mouse move events always on, rather than starting/stopping them
         * on mouse down/up.  We may want do make that optional, using the
         * more standard down/up enabling move events.
         * @returns this Return this instance for chaining
         */
        start() {
            // Note: multiple calls safe
            this.canvas.addEventListener('mousedown', this.mouseDown)
            document.body.addEventListener('mouseup', this.mouseUp)
            this.canvas.addEventListener('mousemove', this.mouseMove)
            this.resetParams()
            return this // chaining
        }
        stop() {
            // Note: multiple calls safe
            this.canvas.removeEventListener('mousedown', this.mouseDown)
            document.body.removeEventListener('mouseup', this.mouseUp)
            this.canvas.removeEventListener('mousemove', this.mouseMove)
            this.resetParams()
            return this // chaining
        }

        get running() {
            return !isNaN(this.x)
        }
        run(on = true) {
            if (on) this.start()
            else this.stop()
        }
        // set run(on = true) {
        //     if (on) this.start()
        //     else this.stop()
        // }
        // toggle() {
        //     if (isNaN(this.x)) this.start()
        //     else this.stop()
        // }

        // Handlers for eventListeners
        generalHandler(e, down, moved) {
            this.down = down
            this.moved = moved
            this.setXY(e)
            this.callback(this, e) // callback generally doesn't use e
        }
        handleMouseDown(e) {
            this.action = 'down'
            this.generalHandler(e, true, false)
        }
        handleMouseUp(e) {
            this.action = 'up'
            this.generalHandler(e, false, false)
        }
        handleMouseMove(e) {
            this.action = this.down ? 'drag' : 'move'
            this.generalHandler(e, this.down, true)
        }

        // Event locations, clientX/Y, screenX/Y, offsetX/Y, pageX/Y .. confusing!
        // Stack Overflowhttps://tinyurl.com/y5k9rwhb

        // set x, y to be event location in turtle coordinates, floats.
        setXY(e) {
            const { canvas, world } = this
            const patchSize = world.patchSize(canvas)
            const rect = this.canvas.getBoundingClientRect()
            const pixX = e.clientX - rect.left
            const pixY = e.clientY - rect.top

            // const [x, y] = world.pixelXYtoPatchXY(pixX, pixY, patchSize)
            // Object.assign(this, { x, y })
            ;[this.x, this.y] = world.pixelXYtoPatchXY(pixX, pixY, patchSize)
        }
    }

    export default Mouse

Type anything to view search result