Source: PointerLockControl.js

import Camera from "./Camera";
class PointerLockControl {
    /**
     * 
     * @param {Camera} camera the camera this controller control
     * @param {HTMLElement} ele  the element this controller bind to
     */
    constructor(camera, ele) {
        this.camera = camera;
        this.targetElement = ele;
        this.pointerSpeed = 0.002;
        this.pointerLocked = false;
        this.mouseIsDown = false;
        this.mouseButton = -1;
        this.invertedX = false;
        this.invertedY = false;
        this.switchXY = false;
        this.regControl();
    }

    regControl() {
        this.targetElement.ownerDocument.addEventListener("mousemove", this.mouseMove.bind(this));
        this.targetElement.ownerDocument.addEventListener("pointerlockchange", this.pointerLockChange.bind(this));
        this.targetElement.ownerDocument.addEventListener("pointerlockerror", this.pointerLockError.bind(this));
        this.targetElement.ownerDocument.addEventListener("mouseup", this.mouseUp.bind(this));
        this.targetElement.ownerDocument.addEventListener("mousedown", this.mouseDown.bind(this));
    }

    removeControl() {
        this.targetElement.ownerDocument.removeEventListener("mousemove", this.mouseMove.bind(this));
        this.targetElement.ownerDocument.removeEventListener("pointerlockchange", this.pointerLockChange.bind(this));
        this.targetElement.ownerDocument.removeEventListener("pointerlockerror", this.pointerLockError.bind(this));
        this.targetElement.ownerDocument.removeEventListener("mouseup", this.mouseUp.bind(this));
        this.targetElement.ownerDocument.removeEventListener("mousedown", this.mouseDown.bind(this));
    }

    lock() {
        this.targetElement.requestPointerLock();
    }

    unlock() {
        this.targetElement.ownerDocument.exitPointerLock();
    }

    /**
     * 
     * @param {number} speed 
     */
    setPointerSpeed(speed) {
        this.pointerSpeed = speed;
    }

    pointerLockChange() {
        if (this.targetElement.ownerDocument.pointerLockElement === this.targetElement) {
            this.pointerLocked = true;
        } else {
            this.pointerLocked = false;
        }
    }

    pointerLockError() {
        console.error("pointerLock unavailable");
    }

    /**
     * 
     * @param {MouseEvent} ev 
     * 
     */
    mouseMove(ev) {
        if (!this.pointerLocked) return;
        const camera = this.camera;
        const mx = ev.movementX * (this.invertedX ? 1 : -1);
        const my = ev.movementY * (this.invertedY ? 1 : -1);
        camera.rotate((this.switchXY ? my : mx) * this.pointerSpeed);
        camera.tilt((this.switchXY ? mx : my) * this.pointerSpeed);
    }

    mouseDown(ev) {
        this.mouseIsDown = true;
        this.mouseButton = ev.button;
    }

    mouseUp(ev) {
        this.mouseIsDown = false;
    }

}

export default PointerLockControl;