Matthias Mullie has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/390437 )
Change subject: Replace OrbitControls with TrackballControls
......................................................................
Replace OrbitControls with TrackballControls
OrbitControls limits rotation around the poles, but
TrackballControls will let you rotate around the
object any way you want.
I also had to move some code around to get TrackballControls
working. Not all these changes are necessary, but I also
find it a bit clearer.
Bug: T179823
Change-Id: I4bcf6516b7438381ff347a61c05139be3edfe07c
---
M extension.json
M modules/mmv.3d.js
D modules/three/OrbitControls.js
A modules/three/TrackballControls.js
4 files changed, 713 insertions(+), 1,129 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/3D
refs/changes/37/390437/1
diff --git a/extension.json b/extension.json
index c6cf346..cb7e571 100644
--- a/extension.json
+++ b/extension.json
@@ -38,7 +38,7 @@
"mmv.3d.js",
"three/three.js",
"three/STLLoader.js",
- "three/OrbitControls.js"
+ "three/TrackballControls.js"
],
"styles": [
"mmv.3d.less"
diff --git a/modules/mmv.3d.js b/modules/mmv.3d.js
index 4d2e0ec..d810113 100644
--- a/modules/mmv.3d.js
+++ b/modules/mmv.3d.js
@@ -28,40 +28,43 @@
TD = ThreeD.prototype;
- TD.createScene = function () {
- var threed = this,
- dimensions = this.dimensionsFunc(),
- ambient = new THREE.AmbientLight( 0x666666 ),
- dlight = new THREE.DirectionalLight( 0x999999 );
+ TD.init = function () {
+ var dimensions = this.getDimensions(),
+ directionalLight;
- dlight.position.set( 0, 0, 1 );
- dlight.castShadow = true;
+ this.renderer = new THREE.WebGLRenderer();
+ this.renderer.setClearColor( 0x222222 );
+ this.renderer.setPixelRatio( window.devicePixelRatio );
+ this.renderer.setSize( dimensions.width, dimensions.height );
+ this.$container.html( this.renderer.domElement );
- this.scene = new THREE.Scene();
- this.camera = new THREE.PerspectiveCamera( 60,
dimensions.ratio, 1, 5000 );
this.manager = new THREE.LoadingManager();
+ this.camera = new THREE.PerspectiveCamera( 60,
dimensions.ratio, 1, 5000 );
this.camera.up.set( 0, 0, 1 );
this.camera.add( new THREE.PointLight( 0xffffff, 0.4 ) );
- this.scene.add( ambient );
- this.scene.add( dlight );
+ this.controls = new THREE.TrackballControls( this.camera,
this.renderer.domElement );
+ this.controls.rotateSpeed = 4;
+ this.controls.zoomSpeed = 4;
+ this.controls.panSpeed = 4;
+ this.controls.addEventListener( 'change', this.render.bind(
this ) );
+ this.controls.addEventListener( 'start',
this.controlsStart.bind( this ) );
+ this.controls.addEventListener( 'end', this.controlsEnd.bind(
this ) );
+
+ this.scene = new THREE.Scene();
this.scene.add( this.camera );
- this.renderer = new THREE.WebGLRenderer();
+ this.scene.add( new THREE.AmbientLight( 0x666666 ) );
- this.renderer.setClearColor( 0x222222 );
+ directionalLight = new THREE.DirectionalLight( 0x999999 );
+ directionalLight.position.set( 0, 0, 1 );
+ directionalLight.castShadow = true;
+ this.scene.add( directionalLight );
- this.controls = new THREE.OrbitControls( this.camera,
this.renderer.domElement );
- this.controls.addEventListener( 'change', $.proxy( function ()
{ threed.render(); }, threed ) );
- this.controls.addEventListener( 'start', $.proxy( function () {
threed.controlsStart(); }, threed ) );
- this.controls.addEventListener( 'end', $.proxy( function () {
threed.controlsEnd(); }, threed ) );
- this.controls.enableKeys = false;
- this.controls.update();
+ $( window ).on( 'resize.3d', $.debounce( 100,
this.onWindowResize.bind( this ) ) );
- $( window ).on( 'resize.3d', $.debounce( 100, $.proxy( function
() { threed.onWindowResize(); }, threed ) ) );
-
- this.animate();
+ this.render();
};
TD.center = function ( object ) {
@@ -91,6 +94,63 @@
return new THREE.Mesh( geometry, material );
};
+ TD.render = function () {
+ this.renderer.render( this.scene, this.camera );
+ };
+
+ TD.animate = function () {
+ requestAnimationFrame( this.animate.bind( this ) );
+ this.controls.update();
+ };
+
+ TD.onWindowResize = function () {
+ var dimensions = this.getDimensions();
+
+ this.camera.aspect = dimensions.width / dimensions.height;
+ this.camera.updateProjectionMatrix();
+
+ this.renderer.setSize( dimensions.width, dimensions.height );
+
+ this.controls.handleResize();
+
+ this.render( this.renderer, this.scene, this.camera );
+ };
+
+ TD.load = function ( extension, url ) {
+ var threed = this;
+
+ // Abort any loading that might still be happening
+ if ( this.promise ) {
+ this.promise.reject();
+ }
+
+ this.promise = this.loadFile( extension, url );
+
+ this.progressBar.jumpTo( 0 );
+ this.progressBar.animateTo( 5 );
+
+ this.promise.then( function ( object ) {
+ delete threed.promise;
+
+ threed.progressBar.hide();
+
+ object.castShadow = true;
+
+ threed.center( object );
+ threed.scene.add( object );
+
+ threed.camera.lookAt( threed.scene.position );
+ threed.render( threed.renderer, threed.scene,
threed.camera );
+
+ mw.threed.attachBadge( threed.$container );
+ } ).progress( function ( progress ) {
+ threed.progressBar.animateTo( progress );
+ } ).fail( function ( /* error */ ) {
+ threed.progressBar.hide();
+ delete threed.promise;
+ } );
+ };
+
TD.loadFile = function ( extension, url ) {
var threed = this,
deferred = $.Deferred(),
@@ -108,12 +168,7 @@
object = threed.geometryToObject( data );
}
- object.castShadow = true;
-
- threed.center( object );
- threed.scene.add( object );
-
- deferred.resolve();
+ deferred.resolve( object );
}, function ( progress ) {
deferred.notify( ( progress.loaded / progress.total ) *
100 );
}, function ( error ) {
@@ -126,64 +181,7 @@
}
} );
- return deferred;
- };
-
- TD.render = function () {
- this.renderer.render( this.scene, this.camera );
- };
-
- TD.animate = function () {
- if ( this.renderer && this.scene && this.camera ) {
- this.render( this.renderer, this.scene, this.camera );
- }
-
- requestAnimationFrame( $.proxy( function () { this.animate();
}, this ) );
- };
-
- TD.onWindowResize = function () {
- var dimensions = this.dimensionsFunc();
-
- if ( !this.camera || !this.renderer || !this.scene ) {
- return;
- }
-
- this.camera.aspect = dimensions.width / dimensions.height;
- this.camera.updateProjectionMatrix();
- this.renderer.setSize( dimensions.width, dimensions.height );
- this.render( this.renderer, this.scene, this.camera );
- };
-
- TD.load = function ( extension, url ) {
- var threed = this;
-
- // Abort any loading that might still be happening
- if ( this.promise ) {
- this.promise.reject();
- }
-
- this.promise = this.loadFile( extension, url );
-
- this.progressBar.jumpTo( 0 );
- this.progressBar.animateTo( 5 );
-
- this.promise.then( function () {
- var dimensions = threed.dimensionsFunc();
- delete threed.promise;
-
- threed.progressBar.hide();
- threed.renderer.setSize( dimensions.width,
dimensions.height );
- threed.$container.html( threed.renderer.domElement );
- threed.camera.lookAt( threed.scene.position );
- threed.render( threed.renderer, threed.scene,
threed.camera );
-
- mw.threed.attachBadge( threed.$container );
- } ).progress( function ( progress ) {
- threed.progressBar.animateTo( progress );
- } ).fail( function ( /* error */ ) {
- threed.progressBar.hide();
- delete threed.promise;
- } );
+ return deferred.promise();
};
TD.controlsStart = function () {
@@ -194,7 +192,7 @@
$( this.renderer.domElement ).removeClass( 'mousedown' );
};
- TD.dimensionsFunc = function () {
+ TD.getDimensions = function () {
var width = $( window ).width(),
height = this.viewer.ui.canvas.$imageWrapper.height();
@@ -213,10 +211,8 @@
singleton = new ThreeD( e.viewer );
}
- // Clear any state, create objects for render.
- singleton.createScene();
-
- // Complete load.
+ singleton.init();
+ singleton.animate();
singleton.load( extension, e.imageInfo.url );
} );
diff --git a/modules/three/OrbitControls.js b/modules/three/OrbitControls.js
deleted file mode 100644
index 45d1b41..0000000
--- a/modules/three/OrbitControls.js
+++ /dev/null
@@ -1,1037 +0,0 @@
-/**
- * @author qiao / https://github.com/qiao
- * @author mrdoob / http://mrdoob.com
- * @author alteredq / http://alteredqualia.com/
- * @author WestLangley / http://github.com/WestLangley
- * @author erich666 / http://erichaines.com
- */
-
-// This set of controls performs orbiting, dollying (zooming), and panning.
-// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by
default).
-//
-// Orbit - left mouse / touch: one finger move
-// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
-// Pan - right mouse, or arrow keys / touch: three finter swipe
-
-THREE.OrbitControls = function ( object, domElement ) {
-
- this.object = object;
-
- this.domElement = ( domElement !== undefined ) ? domElement : document;
-
- // Set to false to disable this control
- this.enabled = true;
-
- // "target" sets the location of focus, where the object orbits around
- this.target = new THREE.Vector3();
-
- // How far you can dolly in and out ( PerspectiveCamera only )
- this.minDistance = 0;
- this.maxDistance = Infinity;
-
- // How far you can zoom in and out ( OrthographicCamera only )
- this.minZoom = 0;
- this.maxZoom = Infinity;
-
- // How far you can orbit vertically, upper and lower limits.
- // Range is 0 to Math.PI radians.
- this.minPolarAngle = 0; // radians
- this.maxPolarAngle = Math.PI; // radians
-
- // How far you can orbit horizontally, upper and lower limits.
- // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI
].
- this.minAzimuthAngle = - Infinity; // radians
- this.maxAzimuthAngle = Infinity; // radians
-
- // Set to true to enable damping (inertia)
- // If damping is enabled, you must call controls.update() in your
animation loop
- this.enableDamping = false;
- this.dampingFactor = 0.25;
-
- // This option actually enables dollying in and out; left as "zoom" for
backwards compatibility.
- // Set to false to disable zooming
- this.enableZoom = true;
- this.zoomSpeed = 1.0;
-
- // Set to false to disable rotating
- this.enableRotate = true;
- this.rotateSpeed = 1.0;
-
- // Set to false to disable panning
- this.enablePan = true;
- this.keyPanSpeed = 7.0; // pixels moved per arrow key push
-
- // Set to true to automatically rotate around the target
- // If auto-rotate is enabled, you must call controls.update() in your
animation loop
- this.autoRotate = false;
- this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
-
- // Set to false to disable use of the keys
- this.enableKeys = true;
-
- // The four arrow keys
- this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
-
- // Mouse buttons
- this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM:
THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
-
- // for reset
- this.target0 = this.target.clone();
- this.position0 = this.object.position.clone();
- this.zoom0 = this.object.zoom;
-
- //
- // public methods
- //
-
- this.getPolarAngle = function () {
-
- return phi;
-
- };
-
- this.getAzimuthalAngle = function () {
-
- return theta;
-
- };
-
- this.reset = function () {
-
- scope.target.copy( scope.target0 );
- scope.object.position.copy( scope.position0 );
- scope.object.zoom = scope.zoom0;
-
- scope.object.updateProjectionMatrix();
- scope.dispatchEvent( changeEvent );
-
- scope.update();
-
- state = STATE.NONE;
-
- };
-
- // this method is exposed, but perhaps it would be better if we can
make it private...
- this.update = function() {
-
- var offset = new THREE.Vector3();
-
- // so camera.up is the orbit axis
- var quat = new THREE.Quaternion().setFromUnitVectors(
object.up, new THREE.Vector3( 0, 1, 0 ) );
- var quatInverse = quat.clone().inverse();
-
- var lastPosition = new THREE.Vector3();
- var lastQuaternion = new THREE.Quaternion();
-
- return function () {
-
- var position = scope.object.position;
-
- offset.copy( position ).sub( scope.target );
-
- // rotate offset to "y-axis-is-up" space
- offset.applyQuaternion( quat );
-
- // angle from z-axis around y-axis
- spherical.setFromVector3( offset );
-
- if ( scope.autoRotate && state === STATE.NONE ) {
-
- rotateLeft( getAutoRotationAngle() );
-
- }
-
- spherical.theta += sphericalDelta.theta;
- spherical.phi += sphericalDelta.phi;
-
- // restrict theta to be between desired limits
- spherical.theta = Math.max( scope.minAzimuthAngle,
Math.min( scope.maxAzimuthAngle, spherical.theta ) );
-
- // restrict phi to be between desired limits
- spherical.phi = Math.max( scope.minPolarAngle,
Math.min( scope.maxPolarAngle, spherical.phi ) );
-
- spherical.makeSafe();
-
-
- spherical.radius *= scale;
-
- // restrict radius to be between desired limits
- spherical.radius = Math.max( scope.minDistance,
Math.min( scope.maxDistance, spherical.radius ) );
-
- // move target to panned location
- scope.target.add( panOffset );
-
- offset.setFromSpherical( spherical );
-
- // rotate offset back to "camera-up-vector-is-up" space
- offset.applyQuaternion( quatInverse );
-
- position.copy( scope.target ).add( offset );
-
- scope.object.lookAt( scope.target );
-
- if ( scope.enableDamping === true ) {
-
- sphericalDelta.theta *= ( 1 -
scope.dampingFactor );
- sphericalDelta.phi *= ( 1 - scope.dampingFactor
);
-
- } else {
-
- sphericalDelta.set( 0, 0, 0 );
-
- }
-
- scale = 1;
- panOffset.set( 0, 0, 0 );
-
- // update condition is:
- // min(camera displacement, camera rotation in
radians)^2 > EPS
- // using small-angle approximation cos(x/2) = 1 - x^2 /
8
-
- if ( zoomChanged ||
- lastPosition.distanceToSquared(
scope.object.position ) > EPS ||
- 8 * ( 1 - lastQuaternion.dot(
scope.object.quaternion ) ) > EPS ) {
-
- scope.dispatchEvent( changeEvent );
-
- lastPosition.copy( scope.object.position );
- lastQuaternion.copy( scope.object.quaternion );
- zoomChanged = false;
-
- return true;
-
- }
-
- return false;
-
- };
-
- }();
-
- this.dispose = function() {
-
- scope.domElement.removeEventListener( 'contextmenu',
onContextMenu, false );
- scope.domElement.removeEventListener( 'mousedown', onMouseDown,
false );
- scope.domElement.removeEventListener( 'mousewheel',
onMouseWheel, false );
- scope.domElement.removeEventListener( 'MozMousePixelScroll',
onMouseWheel, false ); // firefox
-
- scope.domElement.removeEventListener( 'touchstart',
onTouchStart, false );
- scope.domElement.removeEventListener( 'touchend', onTouchEnd,
false );
- scope.domElement.removeEventListener( 'touchmove', onTouchMove,
false );
-
- document.removeEventListener( 'mousemove', onMouseMove, false );
- document.removeEventListener( 'mouseup', onMouseUp, false );
- document.removeEventListener( 'mouseout', onMouseUp, false );
-
- window.removeEventListener( 'keydown', onKeyDown, false );
-
- //scope.dispatchEvent( { type: 'dispose' } ); // should this be
added here?
-
- };
-
- //
- // internals
- //
-
- var scope = this;
-
- var changeEvent = { type: 'change' };
- var startEvent = { type: 'start' };
- var endEvent = { type: 'end' };
-
- var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE
: 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
-
- var state = STATE.NONE;
-
- var EPS = 0.000001;
-
- // current position in spherical coordinates
- var spherical = new THREE.Spherical();
- var sphericalDelta = new THREE.Spherical();
-
- var scale = 1;
- var panOffset = new THREE.Vector3();
- var zoomChanged = false;
-
- var rotateStart = new THREE.Vector2();
- var rotateEnd = new THREE.Vector2();
- var rotateDelta = new THREE.Vector2();
-
- var panStart = new THREE.Vector2();
- var panEnd = new THREE.Vector2();
- var panDelta = new THREE.Vector2();
-
- var dollyStart = new THREE.Vector2();
- var dollyEnd = new THREE.Vector2();
- var dollyDelta = new THREE.Vector2();
-
- function getAutoRotationAngle() {
-
- return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
-
- }
-
- function getZoomScale() {
-
- return Math.pow( 0.95, scope.zoomSpeed );
-
- }
-
- function rotateLeft( angle ) {
-
- sphericalDelta.theta -= angle;
-
- }
-
- function rotateUp( angle ) {
-
- sphericalDelta.phi -= angle;
-
- }
-
- var panLeft = function() {
-
- var v = new THREE.Vector3();
-
- return function panLeft( distance, objectMatrix ) {
-
- v.setFromMatrixColumn( objectMatrix, 0 ); // get X
column of objectMatrix
- v.multiplyScalar( - distance );
-
- panOffset.add( v );
-
- };
-
- }();
-
- var panUp = function() {
-
- var v = new THREE.Vector3();
-
- return function panUp( distance, objectMatrix ) {
-
- v.setFromMatrixColumn( objectMatrix, 1 ); // get Y
column of objectMatrix
- v.multiplyScalar( distance );
-
- panOffset.add( v );
-
- };
-
- }();
-
- // deltaX and deltaY are in pixels; right and down are positive
- var pan = function() {
-
- var offset = new THREE.Vector3();
-
- return function( deltaX, deltaY ) {
-
- var element = scope.domElement === document ?
scope.domElement.body : scope.domElement;
-
- if ( scope.object instanceof THREE.PerspectiveCamera ) {
-
- // perspective
- var position = scope.object.position;
- offset.copy( position ).sub( scope.target );
- var targetDistance = offset.length();
-
- // half of the fov is center to top of screen
- targetDistance *= Math.tan( ( scope.object.fov
/ 2 ) * Math.PI / 180.0 );
-
- // we actually don't use screenWidth, since
perspective camera is fixed to screen height
- panLeft( 2 * deltaX * targetDistance /
element.clientHeight, scope.object.matrix );
- panUp( 2 * deltaY * targetDistance /
element.clientHeight, scope.object.matrix );
-
- } else if ( scope.object instanceof
THREE.OrthographicCamera ) {
-
- // orthographic
- panLeft( deltaX * ( scope.object.right -
scope.object.left ) / scope.object.zoom / element.clientWidth,
scope.object.matrix );
- panUp( deltaY * ( scope.object.top -
scope.object.bottom ) / scope.object.zoom / element.clientHeight,
scope.object.matrix );
-
- } else {
-
- // camera neither orthographic nor perspective
- console.warn( 'WARNING: OrbitControls.js
encountered an unknown camera type - pan disabled.' );
- scope.enablePan = false;
-
- }
-
- };
-
- }();
-
- function dollyIn( dollyScale ) {
-
- if ( scope.object instanceof THREE.PerspectiveCamera ) {
-
- scale /= dollyScale;
-
- } else if ( scope.object instanceof THREE.OrthographicCamera ) {
-
- scope.object.zoom = Math.max( scope.minZoom, Math.min(
scope.maxZoom, scope.object.zoom * dollyScale ) );
- scope.object.updateProjectionMatrix();
- zoomChanged = true;
-
- } else {
-
- console.warn( 'WARNING: OrbitControls.js encountered an
unknown camera type - dolly/zoom disabled.' );
- scope.enableZoom = false;
-
- }
-
- }
-
- function dollyOut( dollyScale ) {
-
- if ( scope.object instanceof THREE.PerspectiveCamera ) {
-
- scale *= dollyScale;
-
- } else if ( scope.object instanceof THREE.OrthographicCamera ) {
-
- scope.object.zoom = Math.max( scope.minZoom, Math.min(
scope.maxZoom, scope.object.zoom / dollyScale ) );
- scope.object.updateProjectionMatrix();
- zoomChanged = true;
-
- } else {
-
- console.warn( 'WARNING: OrbitControls.js encountered an
unknown camera type - dolly/zoom disabled.' );
- scope.enableZoom = false;
-
- }
-
- }
-
- //
- // event callbacks - update the object state
- //
-
- function handleMouseDownRotate( event ) {
-
- //console.log( 'handleMouseDownRotate' );
-
- rotateStart.set( event.clientX, event.clientY );
-
- }
-
- function handleMouseDownDolly( event ) {
-
- //console.log( 'handleMouseDownDolly' );
-
- dollyStart.set( event.clientX, event.clientY );
-
- }
-
- function handleMouseDownPan( event ) {
-
- //console.log( 'handleMouseDownPan' );
-
- panStart.set( event.clientX, event.clientY );
-
- }
-
- function handleMouseMoveRotate( event ) {
-
- //console.log( 'handleMouseMoveRotate' );
-
- rotateEnd.set( event.clientX, event.clientY );
- rotateDelta.subVectors( rotateEnd, rotateStart );
-
- var element = scope.domElement === document ?
scope.domElement.body : scope.domElement;
-
- // rotating across whole screen goes 360 degrees around
- rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth *
scope.rotateSpeed );
-
- // rotating up and down along whole screen attempts to go 360,
but limited to 180
- rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight *
scope.rotateSpeed );
-
- rotateStart.copy( rotateEnd );
-
- scope.update();
-
- }
-
- function handleMouseMoveDolly( event ) {
-
- //console.log( 'handleMouseMoveDolly' );
-
- dollyEnd.set( event.clientX, event.clientY );
-
- dollyDelta.subVectors( dollyEnd, dollyStart );
-
- if ( dollyDelta.y > 0 ) {
-
- dollyIn( getZoomScale() );
-
- } else if ( dollyDelta.y < 0 ) {
-
- dollyOut( getZoomScale() );
-
- }
-
- dollyStart.copy( dollyEnd );
-
- scope.update();
-
- }
-
- function handleMouseMovePan( event ) {
-
- //console.log( 'handleMouseMovePan' );
-
- panEnd.set( event.clientX, event.clientY );
-
- panDelta.subVectors( panEnd, panStart );
-
- pan( panDelta.x, panDelta.y );
-
- panStart.copy( panEnd );
-
- scope.update();
-
- }
-
- function handleMouseUp( event ) {
-
- //console.log( 'handleMouseUp' );
-
- }
-
- function handleMouseWheel( event ) {
-
- //console.log( 'handleMouseWheel' );
-
- var delta = 0;
-
- if ( event.wheelDelta !== undefined ) {
-
- // WebKit / Opera / Explorer 9
-
- delta = event.wheelDelta;
-
- } else if ( event.detail !== undefined ) {
-
- // Firefox
-
- delta = - event.detail;
-
- }
-
- if ( delta > 0 ) {
-
- dollyOut( getZoomScale() );
-
- } else if ( delta < 0 ) {
-
- dollyIn( getZoomScale() );
-
- }
-
- scope.update();
-
- }
-
- function handleKeyDown( event ) {
-
- //console.log( 'handleKeyDown' );
-
- switch ( event.keyCode ) {
-
- case scope.keys.UP:
- pan( 0, scope.keyPanSpeed );
- scope.update();
- break;
-
- case scope.keys.BOTTOM:
- pan( 0, - scope.keyPanSpeed );
- scope.update();
- break;
-
- case scope.keys.LEFT:
- pan( scope.keyPanSpeed, 0 );
- scope.update();
- break;
-
- case scope.keys.RIGHT:
- pan( - scope.keyPanSpeed, 0 );
- scope.update();
- break;
-
- }
-
- }
-
- function handleTouchStartRotate( event ) {
-
- //console.log( 'handleTouchStartRotate' );
-
- rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0
].pageY );
-
- }
-
- function handleTouchStartDolly( event ) {
-
- //console.log( 'handleTouchStartDolly' );
-
- var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
- var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
-
- var distance = Math.sqrt( dx * dx + dy * dy );
-
- dollyStart.set( 0, distance );
-
- }
-
- function handleTouchStartPan( event ) {
-
- //console.log( 'handleTouchStartPan' );
-
- panStart.set( event.touches[ 0 ].pageX, event.touches[ 0
].pageY );
-
- }
-
- function handleTouchMoveRotate( event ) {
-
- //console.log( 'handleTouchMoveRotate' );
-
- rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0
].pageY );
- rotateDelta.subVectors( rotateEnd, rotateStart );
-
- var element = scope.domElement === document ?
scope.domElement.body : scope.domElement;
-
- // rotating across whole screen goes 360 degrees around
- rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth *
scope.rotateSpeed );
-
- // rotating up and down along whole screen attempts to go 360,
but limited to 180
- rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight *
scope.rotateSpeed );
-
- rotateStart.copy( rotateEnd );
-
- scope.update();
-
- }
-
- function handleTouchMoveDolly( event ) {
-
- //console.log( 'handleTouchMoveDolly' );
-
- var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
- var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
-
- var distance = Math.sqrt( dx * dx + dy * dy );
-
- dollyEnd.set( 0, distance );
-
- dollyDelta.subVectors( dollyEnd, dollyStart );
-
- if ( dollyDelta.y > 0 ) {
-
- dollyOut( getZoomScale() );
-
- } else if ( dollyDelta.y < 0 ) {
-
- dollyIn( getZoomScale() );
-
- }
-
- dollyStart.copy( dollyEnd );
-
- scope.update();
-
- }
-
- function handleTouchMovePan( event ) {
-
- //console.log( 'handleTouchMovePan' );
-
- panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY
);
-
- panDelta.subVectors( panEnd, panStart );
-
- pan( panDelta.x, panDelta.y );
-
- panStart.copy( panEnd );
-
- scope.update();
-
- }
-
- function handleTouchEnd( event ) {
-
- //console.log( 'handleTouchEnd' );
-
- }
-
- //
- // event handlers - FSM: listen for events and reset state
- //
-
- function onMouseDown( event ) {
-
- if ( scope.enabled === false ) return;
-
- event.preventDefault();
-
- if ( event.button === scope.mouseButtons.ORBIT ) {
-
- if ( scope.enableRotate === false ) return;
-
- handleMouseDownRotate( event );
-
- state = STATE.ROTATE;
-
- } else if ( event.button === scope.mouseButtons.ZOOM ) {
-
- if ( scope.enableZoom === false ) return;
-
- handleMouseDownDolly( event );
-
- state = STATE.DOLLY;
-
- } else if ( event.button === scope.mouseButtons.PAN ) {
-
- if ( scope.enablePan === false ) return;
-
- handleMouseDownPan( event );
-
- state = STATE.PAN;
-
- }
-
- if ( state !== STATE.NONE ) {
-
- document.addEventListener( 'mousemove', onMouseMove,
false );
- document.addEventListener( 'mouseup', onMouseUp, false
);
- document.addEventListener( 'mouseout', onMouseUp, false
);
-
- scope.dispatchEvent( startEvent );
-
- }
-
- }
-
- function onMouseMove( event ) {
-
- if ( scope.enabled === false ) return;
-
- event.preventDefault();
-
- if ( state === STATE.ROTATE ) {
-
- if ( scope.enableRotate === false ) return;
-
- handleMouseMoveRotate( event );
-
- } else if ( state === STATE.DOLLY ) {
-
- if ( scope.enableZoom === false ) return;
-
- handleMouseMoveDolly( event );
-
- } else if ( state === STATE.PAN ) {
-
- if ( scope.enablePan === false ) return;
-
- handleMouseMovePan( event );
-
- }
-
- }
-
- function onMouseUp( event ) {
-
- if ( scope.enabled === false ) return;
-
- handleMouseUp( event );
-
- document.removeEventListener( 'mousemove', onMouseMove, false );
- document.removeEventListener( 'mouseup', onMouseUp, false );
- document.removeEventListener( 'mouseout', onMouseUp, false );
-
- scope.dispatchEvent( endEvent );
-
- state = STATE.NONE;
-
- }
-
- function onMouseWheel( event ) {
-
- if ( scope.enabled === false || scope.enableZoom === false ||
state !== STATE.NONE ) return;
-
- event.preventDefault();
- event.stopPropagation();
-
- handleMouseWheel( event );
-
- scope.dispatchEvent( startEvent ); // not sure why these are
here...
- scope.dispatchEvent( endEvent );
-
- }
-
- function onKeyDown( event ) {
-
- if ( scope.enabled === false || scope.enableKeys === false ||
scope.enablePan === false ) return;
-
- handleKeyDown( event );
-
- }
-
- function onTouchStart( event ) {
-
- if ( scope.enabled === false ) return;
-
- switch ( event.touches.length ) {
-
- case 1: // one-fingered touch: rotate
-
- if ( scope.enableRotate === false ) return;
-
- handleTouchStartRotate( event );
-
- state = STATE.TOUCH_ROTATE;
-
- break;
-
- case 2: // two-fingered touch: dolly
-
- if ( scope.enableZoom === false ) return;
-
- handleTouchStartDolly( event );
-
- state = STATE.TOUCH_DOLLY;
-
- break;
-
- case 3: // three-fingered touch: pan
-
- if ( scope.enablePan === false ) return;
-
- handleTouchStartPan( event );
-
- state = STATE.TOUCH_PAN;
-
- break;
-
- default:
-
- state = STATE.NONE;
-
- }
-
- if ( state !== STATE.NONE ) {
-
- scope.dispatchEvent( startEvent );
-
- }
-
- }
-
- function onTouchMove( event ) {
-
- if ( scope.enabled === false ) return;
-
- event.preventDefault();
- event.stopPropagation();
-
- switch ( event.touches.length ) {
-
- case 1: // one-fingered touch: rotate
-
- if ( scope.enableRotate === false ) return;
- if ( state !== STATE.TOUCH_ROTATE ) return; //
is this needed?...
-
- handleTouchMoveRotate( event );
-
- break;
-
- case 2: // two-fingered touch: dolly
-
- if ( scope.enableZoom === false ) return;
- if ( state !== STATE.TOUCH_DOLLY ) return; //
is this needed?...
-
- handleTouchMoveDolly( event );
-
- break;
-
- case 3: // three-fingered touch: pan
-
- if ( scope.enablePan === false ) return;
- if ( state !== STATE.TOUCH_PAN ) return; // is
this needed?...
-
- handleTouchMovePan( event );
-
- break;
-
- default:
-
- state = STATE.NONE;
-
- }
-
- }
-
- function onTouchEnd( event ) {
-
- if ( scope.enabled === false ) return;
-
- handleTouchEnd( event );
-
- scope.dispatchEvent( endEvent );
-
- state = STATE.NONE;
-
- }
-
- function onContextMenu( event ) {
-
- event.preventDefault();
-
- }
-
- //
-
- scope.domElement.addEventListener( 'contextmenu', onContextMenu, false
);
-
- scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
- scope.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
- scope.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel,
false ); // firefox
-
- scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
- scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
- scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
-
- window.addEventListener( 'keydown', onKeyDown, false );
-
- // force an update at start
-
- this.update();
-
-};
-
-THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype
);
-THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
-
-Object.defineProperties( THREE.OrbitControls.prototype, {
-
- center: {
-
- get: function () {
-
- console.warn( 'THREE.OrbitControls: .center has been
renamed to .target' );
- return this.target;
-
- }
-
- },
-
- // backward compatibility
-
- noZoom: {
-
- get: function () {
-
- console.warn( 'THREE.OrbitControls: .noZoom has been
deprecated. Use .enableZoom instead.' );
- return ! this.enableZoom;
-
- },
-
- set: function ( value ) {
-
- console.warn( 'THREE.OrbitControls: .noZoom has been
deprecated. Use .enableZoom instead.' );
- this.enableZoom = ! value;
-
- }
-
- },
-
- noRotate: {
-
- get: function () {
-
- console.warn( 'THREE.OrbitControls: .noRotate has been
deprecated. Use .enableRotate instead.' );
- return ! this.enableRotate;
-
- },
-
- set: function ( value ) {
-
- console.warn( 'THREE.OrbitControls: .noRotate has been
deprecated. Use .enableRotate instead.' );
- this.enableRotate = ! value;
-
- }
-
- },
-
- noPan: {
-
- get: function () {
-
- console.warn( 'THREE.OrbitControls: .noPan has been
deprecated. Use .enablePan instead.' );
- return ! this.enablePan;
-
- },
-
- set: function ( value ) {
-
- console.warn( 'THREE.OrbitControls: .noPan has been
deprecated. Use .enablePan instead.' );
- this.enablePan = ! value;
-
- }
-
- },
-
- noKeys: {
-
- get: function () {
-
- console.warn( 'THREE.OrbitControls: .noKeys has been
deprecated. Use .enableKeys instead.' );
- return ! this.enableKeys;
-
- },
-
- set: function ( value ) {
-
- console.warn( 'THREE.OrbitControls: .noKeys has been
deprecated. Use .enableKeys instead.' );
- this.enableKeys = ! value;
-
- }
-
- },
-
- staticMoving : {
-
- get: function () {
-
- console.warn( 'THREE.OrbitControls: .staticMoving has
been deprecated. Use .enableDamping instead.' );
- return ! this.constraint.enableDamping;
-
- },
-
- set: function ( value ) {
-
- console.warn( 'THREE.OrbitControls: .staticMoving has
been deprecated. Use .enableDamping instead.' );
- this.constraint.enableDamping = ! value;
-
- }
-
- },
-
- dynamicDampingFactor : {
-
- get: function () {
-
- console.warn( 'THREE.OrbitControls:
.dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
- return this.constraint.dampingFactor;
-
- },
-
- set: function ( value ) {
-
- console.warn( 'THREE.OrbitControls:
.dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );
- this.constraint.dampingFactor = value;
-
- }
-
- }
-
-} );
diff --git a/modules/three/TrackballControls.js
b/modules/three/TrackballControls.js
new file mode 100755
index 0000000..5d45829
--- /dev/null
+++ b/modules/three/TrackballControls.js
@@ -0,0 +1,625 @@
+/**
+ * @author Eberhard Graether / http://egraether.com/
+ * @author Mark Lundin / http://mark-lundin.com
+ * @author Simone Manini / http://daron1337.github.io
+ * @author Luca Antiga / http://lantiga.github.io
+ */
+
+THREE.TrackballControls = function ( object, domElement ) {
+
+ var _this = this;
+ var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3,
TOUCH_ZOOM_PAN: 4 };
+
+ this.object = object;
+ this.domElement = ( domElement !== undefined ) ? domElement : document;
+
+ // API
+
+ this.enabled = true;
+
+ this.screen = { left: 0, top: 0, width: 0, height: 0 };
+
+ this.rotateSpeed = 1.0;
+ this.zoomSpeed = 1.2;
+ this.panSpeed = 0.3;
+
+ this.noRotate = false;
+ this.noZoom = false;
+ this.noPan = false;
+
+ this.staticMoving = false;
+ this.dynamicDampingFactor = 0.2;
+
+ this.minDistance = 0;
+ this.maxDistance = Infinity;
+
+ this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
+
+ // internals
+
+ this.target = new THREE.Vector3();
+
+ var EPS = 0.000001;
+
+ var lastPosition = new THREE.Vector3();
+
+ var _state = STATE.NONE,
+ _prevState = STATE.NONE,
+
+ _eye = new THREE.Vector3(),
+
+ _movePrev = new THREE.Vector2(),
+ _moveCurr = new THREE.Vector2(),
+
+ _lastAxis = new THREE.Vector3(),
+ _lastAngle = 0,
+
+ _zoomStart = new THREE.Vector2(),
+ _zoomEnd = new THREE.Vector2(),
+
+ _touchZoomDistanceStart = 0,
+ _touchZoomDistanceEnd = 0,
+
+ _panStart = new THREE.Vector2(),
+ _panEnd = new THREE.Vector2();
+
+ // for reset
+
+ this.target0 = this.target.clone();
+ this.position0 = this.object.position.clone();
+ this.up0 = this.object.up.clone();
+
+ // events
+
+ var changeEvent = { type: 'change' };
+ var startEvent = { type: 'start' };
+ var endEvent = { type: 'end' };
+
+
+ // methods
+
+ this.handleResize = function () {
+
+ if ( this.domElement === document ) {
+
+ this.screen.left = 0;
+ this.screen.top = 0;
+ this.screen.width = window.innerWidth;
+ this.screen.height = window.innerHeight;
+
+ } else {
+
+ var box = this.domElement.getBoundingClientRect();
+ // adjustments come from similar code in the jquery
offset() function
+ var d = this.domElement.ownerDocument.documentElement;
+ this.screen.left = box.left + window.pageXOffset -
d.clientLeft;
+ this.screen.top = box.top + window.pageYOffset -
d.clientTop;
+ this.screen.width = box.width;
+ this.screen.height = box.height;
+
+ }
+
+ };
+
+ this.handleEvent = function ( event ) {
+
+ if ( typeof this[ event.type ] == 'function' ) {
+
+ this[ event.type ]( event );
+
+ }
+
+ };
+
+ var getMouseOnScreen = ( function () {
+
+ var vector = new THREE.Vector2();
+
+ return function getMouseOnScreen( pageX, pageY ) {
+
+ vector.set(
+ ( pageX - _this.screen.left ) /
_this.screen.width,
+ ( pageY - _this.screen.top ) /
_this.screen.height
+ );
+
+ return vector;
+
+ };
+
+ }() );
+
+ var getMouseOnCircle = ( function () {
+
+ var vector = new THREE.Vector2();
+
+ return function getMouseOnCircle( pageX, pageY ) {
+
+ vector.set(
+ ( ( pageX - _this.screen.width * 0.5 -
_this.screen.left ) / ( _this.screen.width * 0.5 ) ),
+ ( ( _this.screen.height + 2 * (
_this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional
+ );
+
+ return vector;
+
+ };
+
+ }() );
+
+ this.rotateCamera = ( function() {
+
+ var axis = new THREE.Vector3(),
+ quaternion = new THREE.Quaternion(),
+ eyeDirection = new THREE.Vector3(),
+ objectUpDirection = new THREE.Vector3(),
+ objectSidewaysDirection = new THREE.Vector3(),
+ moveDirection = new THREE.Vector3(),
+ angle;
+
+ return function rotateCamera() {
+
+ moveDirection.set( _moveCurr.x - _movePrev.x,
_moveCurr.y - _movePrev.y, 0 );
+ angle = moveDirection.length();
+
+ if ( angle ) {
+
+ _eye.copy( _this.object.position ).sub(
_this.target );
+
+ eyeDirection.copy( _eye ).normalize();
+ objectUpDirection.copy( _this.object.up
).normalize();
+ objectSidewaysDirection.crossVectors(
objectUpDirection, eyeDirection ).normalize();
+
+ objectUpDirection.setLength( _moveCurr.y -
_movePrev.y );
+ objectSidewaysDirection.setLength( _moveCurr.x
- _movePrev.x );
+
+ moveDirection.copy( objectUpDirection.add(
objectSidewaysDirection ) );
+
+ axis.crossVectors( moveDirection, _eye
).normalize();
+
+ angle *= _this.rotateSpeed;
+ quaternion.setFromAxisAngle( axis, angle );
+
+ _eye.applyQuaternion( quaternion );
+ _this.object.up.applyQuaternion( quaternion );
+
+ _lastAxis.copy( axis );
+ _lastAngle = angle;
+
+ } else if ( ! _this.staticMoving && _lastAngle ) {
+
+ _lastAngle *= Math.sqrt( 1.0 -
_this.dynamicDampingFactor );
+ _eye.copy( _this.object.position ).sub(
_this.target );
+ quaternion.setFromAxisAngle( _lastAxis,
_lastAngle );
+ _eye.applyQuaternion( quaternion );
+ _this.object.up.applyQuaternion( quaternion );
+
+ }
+
+ _movePrev.copy( _moveCurr );
+
+ };
+
+ }() );
+
+
+ this.zoomCamera = function () {
+
+ var factor;
+
+ if ( _state === STATE.TOUCH_ZOOM_PAN ) {
+
+ factor = _touchZoomDistanceStart /
_touchZoomDistanceEnd;
+ _touchZoomDistanceStart = _touchZoomDistanceEnd;
+ _eye.multiplyScalar( factor );
+
+ } else {
+
+ factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) *
_this.zoomSpeed;
+
+ if ( factor !== 1.0 && factor > 0.0 ) {
+
+ _eye.multiplyScalar( factor );
+
+ }
+
+ if ( _this.staticMoving ) {
+
+ _zoomStart.copy( _zoomEnd );
+
+ } else {
+
+ _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) *
this.dynamicDampingFactor;
+
+ }
+
+ }
+
+ };
+
+ this.panCamera = ( function() {
+
+ var mouseChange = new THREE.Vector2(),
+ objectUp = new THREE.Vector3(),
+ pan = new THREE.Vector3();
+
+ return function panCamera() {
+
+ mouseChange.copy( _panEnd ).sub( _panStart );
+
+ if ( mouseChange.lengthSq() ) {
+
+ mouseChange.multiplyScalar( _eye.length() *
_this.panSpeed );
+
+ pan.copy( _eye ).cross( _this.object.up
).setLength( mouseChange.x );
+ pan.add( objectUp.copy( _this.object.up
).setLength( mouseChange.y ) );
+
+ _this.object.position.add( pan );
+ _this.target.add( pan );
+
+ if ( _this.staticMoving ) {
+
+ _panStart.copy( _panEnd );
+
+ } else {
+
+ _panStart.add( mouseChange.subVectors(
_panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
+
+ }
+
+ }
+
+ };
+
+ }() );
+
+ this.checkDistances = function () {
+
+ if ( ! _this.noZoom || ! _this.noPan ) {
+
+ if ( _eye.lengthSq() > _this.maxDistance *
_this.maxDistance ) {
+
+ _this.object.position.addVectors( _this.target,
_eye.setLength( _this.maxDistance ) );
+ _zoomStart.copy( _zoomEnd );
+
+ }
+
+ if ( _eye.lengthSq() < _this.minDistance *
_this.minDistance ) {
+
+ _this.object.position.addVectors( _this.target,
_eye.setLength( _this.minDistance ) );
+ _zoomStart.copy( _zoomEnd );
+
+ }
+
+ }
+
+ };
+
+ this.update = function () {
+
+ _eye.subVectors( _this.object.position, _this.target );
+
+ if ( ! _this.noRotate ) {
+
+ _this.rotateCamera();
+
+ }
+
+ if ( ! _this.noZoom ) {
+
+ _this.zoomCamera();
+
+ }
+
+ if ( ! _this.noPan ) {
+
+ _this.panCamera();
+
+ }
+
+ _this.object.position.addVectors( _this.target, _eye );
+
+ _this.checkDistances();
+
+ _this.object.lookAt( _this.target );
+
+ if ( lastPosition.distanceToSquared( _this.object.position ) >
EPS ) {
+
+ _this.dispatchEvent( changeEvent );
+
+ lastPosition.copy( _this.object.position );
+
+ }
+
+ };
+
+ this.reset = function () {
+
+ _state = STATE.NONE;
+ _prevState = STATE.NONE;
+
+ _this.target.copy( _this.target0 );
+ _this.object.position.copy( _this.position0 );
+ _this.object.up.copy( _this.up0 );
+
+ _eye.subVectors( _this.object.position, _this.target );
+
+ _this.object.lookAt( _this.target );
+
+ _this.dispatchEvent( changeEvent );
+
+ lastPosition.copy( _this.object.position );
+
+ };
+
+ // listeners
+
+ function keydown( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ window.removeEventListener( 'keydown', keydown );
+
+ _prevState = _state;
+
+ if ( _state !== STATE.NONE ) {
+
+ return;
+
+ } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !
_this.noRotate ) {
+
+ _state = STATE.ROTATE;
+
+ } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !
_this.noZoom ) {
+
+ _state = STATE.ZOOM;
+
+ } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !
_this.noPan ) {
+
+ _state = STATE.PAN;
+
+ }
+
+ }
+
+ function keyup( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ _state = _prevState;
+
+ window.addEventListener( 'keydown', keydown, false );
+
+ }
+
+ function mousedown( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ if ( _state === STATE.NONE ) {
+
+ _state = event.button;
+
+ }
+
+ if ( _state === STATE.ROTATE && ! _this.noRotate ) {
+
+ _moveCurr.copy( getMouseOnCircle( event.pageX,
event.pageY ) );
+ _movePrev.copy( _moveCurr );
+
+ } else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
+
+ _zoomStart.copy( getMouseOnScreen( event.pageX,
event.pageY ) );
+ _zoomEnd.copy( _zoomStart );
+
+ } else if ( _state === STATE.PAN && ! _this.noPan ) {
+
+ _panStart.copy( getMouseOnScreen( event.pageX,
event.pageY ) );
+ _panEnd.copy( _panStart );
+
+ }
+
+ document.addEventListener( 'mousemove', mousemove, false );
+ document.addEventListener( 'mouseup', mouseup, false );
+
+ _this.dispatchEvent( startEvent );
+
+ }
+
+ function mousemove( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ if ( _state === STATE.ROTATE && ! _this.noRotate ) {
+
+ _movePrev.copy( _moveCurr );
+ _moveCurr.copy( getMouseOnCircle( event.pageX,
event.pageY ) );
+
+ } else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
+
+ _zoomEnd.copy( getMouseOnScreen( event.pageX,
event.pageY ) );
+
+ } else if ( _state === STATE.PAN && ! _this.noPan ) {
+
+ _panEnd.copy( getMouseOnScreen( event.pageX,
event.pageY ) );
+
+ }
+
+ }
+
+ function mouseup( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ _state = STATE.NONE;
+
+ document.removeEventListener( 'mousemove', mousemove );
+ document.removeEventListener( 'mouseup', mouseup );
+ _this.dispatchEvent( endEvent );
+
+ }
+
+ function mousewheel( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ switch ( event.deltaMode ) {
+
+ case 2:
+ // Zoom in pages
+ _zoomStart.y -= event.deltaY * 0.025;
+ break;
+
+ case 1:
+ // Zoom in lines
+ _zoomStart.y -= event.deltaY * 0.01;
+ break;
+
+ default:
+ // undefined, 0, assume pixels
+ _zoomStart.y -= event.deltaY * 0.00025;
+ break;
+
+ }
+
+ _this.dispatchEvent( startEvent );
+ _this.dispatchEvent( endEvent );
+
+ }
+
+ function touchstart( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ switch ( event.touches.length ) {
+
+ case 1:
+ _state = STATE.TOUCH_ROTATE;
+ _moveCurr.copy( getMouseOnCircle(
event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
+ _movePrev.copy( _moveCurr );
+ break;
+
+ default: // 2 or more
+ _state = STATE.TOUCH_ZOOM_PAN;
+ var dx = event.touches[ 0 ].pageX -
event.touches[ 1 ].pageX;
+ var dy = event.touches[ 0 ].pageY -
event.touches[ 1 ].pageY;
+ _touchZoomDistanceEnd = _touchZoomDistanceStart
= Math.sqrt( dx * dx + dy * dy );
+
+ var x = ( event.touches[ 0 ].pageX +
event.touches[ 1 ].pageX ) / 2;
+ var y = ( event.touches[ 0 ].pageY +
event.touches[ 1 ].pageY ) / 2;
+ _panStart.copy( getMouseOnScreen( x, y ) );
+ _panEnd.copy( _panStart );
+ break;
+
+ }
+
+ _this.dispatchEvent( startEvent );
+
+ }
+
+ function touchmove( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ switch ( event.touches.length ) {
+
+ case 1:
+ _movePrev.copy( _moveCurr );
+ _moveCurr.copy( getMouseOnCircle(
event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
+ break;
+
+ default: // 2 or more
+ var dx = event.touches[ 0 ].pageX -
event.touches[ 1 ].pageX;
+ var dy = event.touches[ 0 ].pageY -
event.touches[ 1 ].pageY;
+ _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy
* dy );
+
+ var x = ( event.touches[ 0 ].pageX +
event.touches[ 1 ].pageX ) / 2;
+ var y = ( event.touches[ 0 ].pageY +
event.touches[ 1 ].pageY ) / 2;
+ _panEnd.copy( getMouseOnScreen( x, y ) );
+ break;
+
+ }
+
+ }
+
+ function touchend( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ switch ( event.touches.length ) {
+
+ case 0:
+ _state = STATE.NONE;
+ break;
+
+ case 1:
+ _state = STATE.TOUCH_ROTATE;
+ _moveCurr.copy( getMouseOnCircle(
event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
+ _movePrev.copy( _moveCurr );
+ break;
+
+ }
+
+ _this.dispatchEvent( endEvent );
+
+ }
+
+ function contextmenu( event ) {
+
+ if ( _this.enabled === false ) return;
+
+ event.preventDefault();
+
+ }
+
+ this.dispose = function() {
+
+ this.domElement.removeEventListener( 'contextmenu',
contextmenu, false );
+ this.domElement.removeEventListener( 'mousedown', mousedown,
false );
+ this.domElement.removeEventListener( 'wheel', mousewheel, false
);
+
+ this.domElement.removeEventListener( 'touchstart', touchstart,
false );
+ this.domElement.removeEventListener( 'touchend', touchend,
false );
+ this.domElement.removeEventListener( 'touchmove', touchmove,
false );
+
+ document.removeEventListener( 'mousemove', mousemove, false );
+ document.removeEventListener( 'mouseup', mouseup, false );
+
+ window.removeEventListener( 'keydown', keydown, false );
+ window.removeEventListener( 'keyup', keyup, false );
+
+ };
+
+ this.domElement.addEventListener( 'contextmenu', contextmenu, false );
+ this.domElement.addEventListener( 'mousedown', mousedown, false );
+ this.domElement.addEventListener( 'wheel', mousewheel, false );
+
+ this.domElement.addEventListener( 'touchstart', touchstart, false );
+ this.domElement.addEventListener( 'touchend', touchend, false );
+ this.domElement.addEventListener( 'touchmove', touchmove, false );
+
+ window.addEventListener( 'keydown', keydown, false );
+ window.addEventListener( 'keyup', keyup, false );
+
+ this.handleResize();
+
+ // force an update at start
+ this.update();
+
+};
+
+THREE.TrackballControls.prototype = Object.create(
THREE.EventDispatcher.prototype );
+THREE.TrackballControls.prototype.constructor = THREE.TrackballControls;
--
To view, visit https://gerrit.wikimedia.org/r/390437
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4bcf6516b7438381ff347a61c05139be3edfe07c
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/3D
Gerrit-Branch: master
Gerrit-Owner: Matthias Mullie <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits