webgl / three-musketeers

A simple module to introspect, debug and test any THREE.js application.
https://webgl.github.io/three-musketeers/
Other
34 stars 3 forks source link

Issue with click event #1

Closed 4zuko closed 6 years ago

4zuko commented 6 years ago

Hi @FarhadG. Following case didn't work as expected on my local environment. Cursor position was invalid once simulation of click event is performed:

$$$.find(`${item-name}`).click(); // locates the item in the 3D scene and clicks the item

It seems that function getWorldPosition doesn't work as expected. I made a quick fix that works perfectly. You can check it and test it as well:

// dependencies
import _ from 'lodash';
import * as THREE from 'three';

// local dependencies
import store from '../../store/store';
import C from '../../constants/constants';
import { simulate } from '../../rootComponents/rootComponents';
import { getCallbackID, worldToScreenSpace } from '../../util/helpers';

export default node =>
  /**
   * Click the position (center) of a given existing node. You can pass `debug` to see cursor.
   *
   * @module click
   * @param {boolean} [debug=false] - Allows to turn on the visuals for the `click` action.
   * @returns {self} - Chainable api by returning the node.
   *
   * @example
   * $$$
   * .find('Cube_1') // an element in the scene with a name of `Cube_1`
   * .click(); // clicks the node
   *
   *  $$$
   * .find('Cube_1')
   * .click(true); // you can also pass in `debug` as `true` to see the cursor
   */
  (debug = false) => {
    // Find the centre point of the 3D node
    node.updateMatrixWorld();
    const box = new THREE.Box3().setFromObject(node);
    const position = box.getCenter(new THREE.Vector3());
    position.applyMatrix4(node.matrixWorld);
    const canvas = store.get(C.RENDERER).domElement;

    const screenSpace = worldToScreenSpace(position.x, position.y, position.z, canvas.clientWidth, canvas.clientHeight);

    const offset = {
      left: canvas.getBoundingClientRect().left + window.scrollX,
      top: canvas.getBoundingClientRect().top + window.scrollY
    };

    const eventData = {
      clientX: screenSpace.x + offset.left,
      clientY: screenSpace.y + offset.top
    };

    simulate(C.MOUSE_MOVE, eventData, debug);
    simulate(C.CLICK, eventData, debug);

    // trigger all associated events
    const callbackID = getCallbackID(node, C.CLICK);
    const callbacks = store.get(callbackID);

    if (callbacks) {
      _.each(callbacks, cb => cb(node));
    }

    return node;
  };
FarhadG commented 6 years ago

Thanks for the issue and PR, @4zuko!

I assume we need this, as the current code assumes canvas takes up the entire screen space. With these changes, we can ensure we target the canvas size regardless of its position and size within the DOM. is that correct?

If so, this is a great addition. We should generalize this function, similar to worldToScreenSpace and include it as a helper. That way, we can use it throughout the application, as the canvas is often retrieved.

I've left my review in the PR (I assume we need this, as the current code assumes canvas takes up the entire screen space. With these changes, we can ensure we target the canvas size regardless of its position and size within the DOM. is that correct?

If so, this is a great addition. We should generalize this function, similar to worldToScreenSpace and include it as a helper. That way, we can use it throughout the application, as the canvas is often retrieved.

I've left my reviews in your PR: https://github.com/webgl/three-musketeers/pull/2

FarhadG commented 6 years ago

Thanks for the PR, @4zuko. It has been merged into master 👍