Repository

js/Mobilizing/renderer/3D/three/ui/Clickable.js

import Component from "../../../../core/Component";
import Pointer from "../../../../input/Pointer";
import Mouse from "../../../../input/Mouse";
import Touch from "../../../../input/Touch";

export default class Clickable extends Component {
    /**
    Makes a Mesh clickable
    *
    @param {Object} params Parameters object, given by the constructor.
    @param {Pointer} params.pointer a Pointer input object to use for the interaction. If none provided, a Pointer is created internally by this class, but it needs a canvas reference (i.e the canvas uses by the renderer)
    @param {Camera} params.camera the camera used in the scene to compute the pick on the mesh
    @param {Mesh} params.mesh the target mesh to make clickable
    @param {Canvas} params.canvas the canvas to use for the Pointer input to work (i.e the canvas uses by the renderer)
    @param {Boolean} params.continuous set the hover (enter) behavious continuous (i.e not only once on the mesh entering, but at each pointer's move)
    @param {onPress} params.onPress onPress Handler
    @param {onRelease} params.onRelease onRelease Handler
    @param {continuous} params.continuous defines if the events triggered by this clickable should be conituous (every frame) or not (on event only)
    @param {onEnter} params.onEnter Handler
    @param {onLeave} params.onLeave Handler
    */
    constructor({
        camera = undefined,
        mesh = undefined,
        canvas = undefined,
        pointer = undefined,
        continuous = false,
        onPress = undefined,
        onRelease = undefined,
        onEnter = undefined,
        onLeave = undefined,
    } = {}) {
        super(...arguments);

        this.camera = camera;
        this.mesh = mesh;
        this.canvas = canvas;
        this.pointer = pointer;
        this.continuous = continuous;
        this.onPress = onPress;
        this.onRelease = onRelease;
        this.onEnter = onEnter;
        this.onLeave = onLeave;

        this.picked = false;
        this.hovered = false;
    }

    /**
    * Setup for this clickable instance
    *
    * @method setup
    */
    setup() {
        super.setup();

        //No pointer given, build it
        if (this.pointer === undefined) {

            const mouse = new Mouse({ "target": this.canvas });
            this.context.addComponent(mouse);
            mouse.setup();
            mouse.on();

            const touch = new Touch({ "target": this.canvas });
            this.context.addComponent(touch);
            touch.setup();
            touch.on();

            this.pointer = new Pointer();
            this.pointer.add(mouse);
            this.pointer.add(touch);
            this.context.addComponent(this.pointer);
            this.pointer.setup();
            this.pointer.on();
            //console.log(mouse,context);
        }

        this.pointer.events.on("on", (event) => {

            const pick = this.mesh.transform.pick(this.camera, event.x, event.y);

            if (pick) {
                this.picked = true;

                if (this.onPress) {
                    this.onPress(pick);
                }
            }
            else {
                this.picked = false;
            }
        });

        this.pointer.events.on("off", (event) => {

            const pick = this.mesh.transform.pick(this.camera, event.x, event.y);

            if (this.picked === true) {
                if (this.onRelease) {
                    this.onRelease(pick);
                }
            }
        });

        this.pointer.events.on("moved", (event) => {

            const pick = this.mesh.transform.pick(this.camera, event.x, event.y);

            if (pick) {
                this.picked = true;

                if (!this.continuous) {

                    if (!this.hovered) {
                        if (this.onEnter) {
                            this.onEnter(pick);
                        }
                    }
                }
                else {
                    if (this.onEnter) {
                        this.onEnter(pick);
                    }
                }
                this.hovered = true;

            }
            else {
                //avoid useless recall
                if (this.picked) {
                    if (this.onLeave) {
                        this.onLeave();
                    }

                    this.hovered = false;
                    this.picked = false;
                }
            }
        });
    }
}