Itee/three-full

TrackballControls - zoom works, pan and rotate don't

Closed this issue · 6 comments

Hello,

First off thanks for this version of ThreeJS. It's great the work you've done on this. I've got a simple use case of using the trackballcontrols module. The zoom works, but the pan/rotate functionality does not work. No errors, it just isn't working in my Nuxt project (a framework for Vue). Here's a snippet of the method that adds trackballcontrols:

setupTrackballControls() {
      this.trackballControls = new THREE.TrackballControls(
        this.camera,
        this.renderer.domElement
      );
      this.trackballControls.rotateSpeed = 1.0;
      this.trackballControls.zoomSpeed = 1.2;
      this.trackballControls.panSpeed = 0.8;
      this.trackballControls.noZoom = false;
      this.trackballControls.noPan = false;
      this.trackballControls.staticMoving = false;
      this.trackballControls.dynamicDampingFactor = 0.3;
      this.trackballControls.keys = [65, 83, 68];
    },

Any advice on what might be going wrong? I had this issue same issue using three-trackballcontrols before I discovered your fork of three while reading the giant threejs modules of examples folder here.

From an old github issue from 2012 in ThreeJS I was able to whip up some camera rotate functionality that works for my use case (for now). Still bummed for some reason that pan/rotate doesn't work from TrackballControls and I'm not sure why. Here's the code I'm using if it is helpful for anyone else in the future:

changeCameraPosition(e) {
      const theta = 0.2; //the speed of rotation
      const x = this.camera.position.x;
      const y = this.camera.position.y;
      const z = this.camera.position.z;

      e.preventDefault();

      switch (e.key) {
        case "a":
          this.camera.position.x = x * Math.cos(theta) + z * Math.sin(theta);
          this.camera.position.z = z * Math.cos(theta) - x * Math.sin(theta);
          break;
        case "w":
          this.camera.position.y = y * Math.cos(theta) - z * Math.sin(theta);
          this.camera.position.z = z * Math.cos(theta) + y * Math.sin(theta);
          break;
        case "s":
          this.camera.position.y = y * Math.cos(theta) + z * Math.sin(theta);
          this.camera.position.z = z * Math.cos(theta) - y * Math.sin(theta);
          break;
        case "d":
          this.camera.position.x = x * Math.cos(theta) - z * Math.sin(theta);
          this.camera.position.z = z * Math.cos(theta) + x * Math.sin(theta);
          break;
        default:
          break;
      }

      this.camera.lookAt(this.scene.position);
    },

Lastly, I was able to get mouse rotating working. I had to pass document instead of this.renderer.domElement to get it working. Key events still aren't functional though :(

Itee commented

Hello and thanks for feedback.

I had a similar issue using VueJs. It depend on the Dom initialization order make by VueJs.
Did you try the vuejs $el itself using a ref to the element ? Like:

mounted () {
        'use strict'

        const viewport3DElement = this.$refs.viewport3D.$el
        this.cameraControl.setDomElement( viewport3DElement )

    },

For key events are you sure that you canvas or container is focusable ?

Secondly, did you try to output some debug log in key event handlers ?

		window.removeEventListener( 'keydown', keydown, false );
		window.removeEventListener( 'keyup', keyup, false );

Hi! Thanks for the reply!

If I try using setDomElement on TrackballControls it throws an error about that not being a function (and I dont see it in TrackballControls.js).

My div for the threejs contents is:

<div id="three-element" ref="threeElement" tabindex="0"/>

I tried using $el like you suggest, instead of just the $ref but I still get the same result and W/A/S/D keys dont work.

setupTrackballControls() {
      this.trackballControls = new THREE.TrackballControls(
        this.camera,
        this.$refs.threeElement.$el
      );
      //this.trackballControls.domElement = this.$refs.threeElement.$el;
      this.trackballControls.rotateSpeed = 1.7;
    },

I also added in a console log to the keydown event in TrackballControls.js file but I don't see any console log being printed out 😢

Itee commented

I will close this issue due to long time. This would be fixed in current threejs package.

For any requirement, please reopen.

Internally TrackballControls uses const box = domElement.getBoundingClientRect() to define a coordinate system for the event locations. However, before domElement is placed on the page, box contains zero values only, which gives zero divides inside the module and makes the controls fail. As a workaround, I create and store the Trackballcontrols inside the render() function, after domElement.getBoundingClientRect() returns a non-zero box:

let controls;
render() {
                if (controls) {
                        controls.update();
                }
                else {
                        const box = domElement.getBoundingClientRect();
                        if (box.left != box.right && box.bottom != box.top) {
                                controls = new TrackballControls(camera, domElement);
                                controls.update();
                        }
                }
                renderer.render(scene, camera);
        }
}