Prevent click when dragging - javascript

Im using Three.js to display a 3d model which users can drag the camera around and click objects to zoom in on them. The issue I'm having is that when you click and drag it reads it as a click and triggers the animation, I need to prevent clicking when dragging, so clicks are only registered when it is just a click and no mouse movement.
function onClick(event) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children, true );
if ( intersects.length > 0 && intersects[0].object.name==="Tree006") {
var object = intersects[0].object;
gsap.to( camera.position, {
duration: 1,
x: mesh["Tree006"].position.x,
y: mesh["Tree006"].position.y,
z: mesh["Tree006"].position.z,
onUpdate: function() {
controls.enabled = false;
camera.lookAt(0,0,0);
}
} );
console.log( 'Intersection:', intersects[ 0 ] );
}
if ( intersects.length > 0 && intersects[0].object.name!=="Tree006") {
var object = intersects[0].object;
gsap.to( camera.position, {
duration: 1, // seconds
x: 6,
y: 4,
z: 6,
onUpdate: function() {
controls.enabled = true;
camera.lookAt( 0,0,0 );
}
} );
}
}

Event click is only fired when you release the mouse button over the element. So you can set some flag on mousedown and reset that flag on mouseup. This flag would tell the click handler not to do anything.
var btn1 = document.querySelector("#btn1");
var flag = false;
btn1.addEventListener('click', function(ev) {
if (!flag) {
alert(1);
}
ev.preventDefault();
})
btn1.addEventListener('mousedown', function(ev) {
flag = true;
console.log("flag to disable click is true");
})
btn1.addEventListener('mouseup', function(ev) {
// this is dirty hack, until i find a better solution:
setTimeout(function() {
flag = false
console.log("flag to disable click is false");
});
})
<button id="btn1">no click</button>
<button id="btn2" onclick="alert(2)">click</button>

Related

Raycaster object undefined mouseover Three.js

So I have the raycaster set up with mousemove to change the cursor It works great!
However it only works as intended when the mouse is either over the model or over the box themselves if you hover into blank space where there is nothing it kind of breaks and an undefined error occurs… So if I am hovering over the box which changes the cursor to a pointer and then move off it but the mouse then hovers over the model behind the box it works and the cursor changes to auto but if I hover into blank space after hovering on the box where there is nothing the cursor still remains a pointer instead of changing to auto
function onDocumentMouseMove(event) {
event.preventDefault();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children, true);
if (intersects[0].object.name == 'MaBox') {
container.style.cursor = 'pointer';
console.log('Mouse is over')
} else {
container.style.cursor = 'auto';
console.log('Mouse is off')
}
}
Error:
Uncaught TypeError: Cannot read property ‘object’ of undefined at
HTMLDocument.onDocumentMouseMove
Any suggestions?
You need to check that the array of intersects is not empty. Otherwise, there is no element of index 0.
Something like this:
var intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) { // check the array
if (intersects[0].object.name == 'MaBox') {
container.style.cursor = 'pointer';
console.log('Mouse is over')
} else {
container.style.cursor = 'auto';
console.log('Mouse is off')
}
}

THREE.JS: How can I disable the dragControls after activating them on group of elements?

I have a function that activates the dragControls, while the "m" key is pressed. For some reason it is not deactivated when the "m" is unpressed. How can I disable the dragControls?
I have tried to encapsulate the dragControls to be activated if the statement is true, else dragControls = null. But whenever the first activation happens, it is not deactivated, even when the statement is false.
While and do while loops are just freezing the browser.
init() {
// EVENT LISTENERS:
map.addEventListener('mousedown', this.movePoi, false);
document.addEventListener('keydown', this.onDocumentKeyDown, false);
document.addEventListener('keyup', this.onDocumentKeyUp, false);
},
// HELPER FUNCTIONS:
onDocumentKeyDown(event) {
let keycode = event.which;
if (keycode === 77) {
this.moveIt = true;
this.controls.enabled = false;
console.log("Key is pressed");
console.log(this.moveIt);
}
},
onDocumentKeyUp(event){
let keycode = event.which;
console.log(keycode);
if (keycode === 77) {
this.moveIt = false;
this.controls.enabled = true;
console.log("Key is unpressed");
console.log(this.moveIt);
}
},
mouseOverScene (event) {
event.preventDefault();
let rect = event.target.getBoundingClientRect();
let x = event.clientX - rect.left;
let y = event.clientY - rect.top;
this.mouse.x = ( x / this.mapWidth) * 2 - 1;
this.mouse.y = - ( y / this.mapHeight ) * 2 + 1;
this.rayCaster.setFromCamera(this.mouse, this.camera);
},
//POI movement around the scene:
movePoi (event) {
event.preventDefault();
let controlsDrag;
if (this.moveIt) {
controlsDrag = new DragControls(this.spheres, this.camera, this.renderer.domElement);
} else {
controlsDrag = null;
}
}
EXPECTED: the objects should be dragged around by the left-click mouse, while the "m" key is pressed (the orbitControls are also disabled when this happens. This part works fine). When the "m" is not pressed, they should return the undraggable state and the orbitControls are enabled again.
ACTUAL: All of the above happens, BUT the objects are still draggable after the "m" is unpressed. The orbitControls are obviously enabled, which brings the whole next level of haywireness happening on the screen.
Not tested but you should try calling the movePoi function at the end of onDocumentKeyUp. At a glance it seems like the verification of whether "m" is pressed or not is only made when the mouse left button is clicked and not when the "m" key is unpresssed. Hope that helps.
So the solution goes as following:
init() {
this.controlsDrag = new DragControls(this.spheres, this.camera, this.renderer.domElement);
this.controlsDrag.deactivate();
// EVENT LISTENERS:
map.addEventListener('mousedown', this.startMovePoi, false);
this.controlsDrag.addEventListener('mouseup', this.stopMovePoi,false);
},
//POI movement around the scene:
startMovePoi () {
let controls = this.controls;
this.controlsDrag.activate();
this.controlsDrag.addEventListener('dragstart', function () {
controls.enabled = false;
});
this.controlsDrag.addEventListener('dragend', function () {
controls.enabled = true;
});
},
stopMovePoi(){
this.controlsDrag.deactivate();
}
Needed some code refactoring before.

JQuery trigger function if element is in viewport

I'm trying to make a function openAnimation() working, when the element is "in viewport"!
Now, this particular function is GSAP. Every time I run openAnimation() doesn't work as aspected.
Runs twice and repeats each time the in-view class is been added.
-So how can I run my GSAP function with this plug in?
https://codepen.io/davide77/pen/qPLoKP
function inView( opt ) {
if( opt.selector === undefined ) {
console.log( 'Valid selector required for inView' );
return false;
}
var elems = [].slice.call( document.querySelectorAll( opt.selector ) ),
once = opt.once === undefined ? true : opt.once,
offsetTop = opt.offsetTop === undefined ? 0 : opt.offsetTop,
offsetBot = opt.offsetBot === undefined ? 0 : opt.offsetBot,
count = elems.length,
winHeight = 0,
ticking = false;
function update() {
var i = count;
while( i-- ) {
var elem = elems[ i ],
rect = elem.getBoundingClientRect();
if( rect.bottom >= offsetTop && rect.top <= winHeight - offsetBot ) {
elem.classList.add( 'in-view' );
if( once ) {
count--;
elems.splice( i, 1 );
}
} else {
elem.classList.remove( 'in-view' );
}
}
ticking = false;
}
function onResize() {
winHeight = window.innerHeight;
requestTick();
}
function onScroll() {
requestTick();
}
function requestTick() {
if( !ticking ) {
requestAnimationFrame( update );
ticking = true;
}
}
window.addEventListener( 'resize', onResize, false );
document.addEventListener( 'scroll', onScroll, false );
document.addEventListener( 'touchmove', onScroll, false );
onResize();
}
inView({
selector: '.view-poll', // an .in-view class will get toggled on these elements
once: true, // set this to false to have the .in-view class be toggled on AND off
offsetTop: 0, // top threshold to be considered "in view"
offsetBot: 0 // bottom threshold to be considered "in view"
});
// HOW CAN I RUN THIS FUNCTION NOW?
function openAnimation() {
var rotate = $('.rotate.in-view');
var scale = $('.scale.in-view');
var translate = $('.translate.in-view');
//feature Left
TweenLite.from(rotate, 1.2, {y:-400, opacity: 0.0, delay:0.0, }, 0.05);
TweenLite.from(scale, 1.2, {y:-400, opacity: 0.0, delay:0.0, }, 0.05);
TweenLite.from(translate, 1.2, {y:-400, opacity: 0.0, delay:0.0, }, 0.05);
}
You can use the library jQuery-visible. With its help, you can create a window event onScroll and check if your element is "visible", then call your function.
You can use http://scrollmagic.io/. With this you can initiate any function on scroll or when its in view.

jquery animate if element is in viewport

What I need here is to trigger the animation when the element is visible (in viewport).
I have a function called openAnimation() that runs a GSPA TweenMax.
that should animate nicely my elements, but it does't work.
Basically I need to trigger the openAnimation() when my element in inview.
Demo-codepen
function inView( opt ) {
if( opt.selector === undefined ) {
console.log( 'Valid selector required for inView' );
return false;
}
var elems = [].slice.call( document.querySelectorAll( opt.selector ) ),
once = opt.once === undefined ? true : opt.once,
offsetTop = opt.offsetTop === undefined ? 0 : opt.offsetTop,
offsetBot = opt.offsetBot === undefined ? 0 : opt.offsetBot,
count = elems.length,
winHeight = 0,
ticking = false;
function update() {
var i = count;
while( i-- ) {
var elem = elems[ i ],
rect = elem.getBoundingClientRect();
if( rect.bottom >= offsetTop && rect.top <= winHeight - offsetBot ) {
elem.classList.add( 'in-view' );
if( once ) {
count--;
elems.splice( i, 1 );
}
} else {
elem.classList.remove( 'in-view' );
}
}
ticking = false;
}
function onResize() {
winHeight = window.innerHeight;
requestTick();
}
function onScroll() {
requestTick();
}
function requestTick() {
if( !ticking ) {
requestAnimationFrame( update );
ticking = true;
}
}
window.addEventListener( 'resize', onResize, false );
document.addEventListener( 'scroll', onScroll, false );
document.addEventListener( 'touchmove', onScroll, false );
onResize();
}
inView({
selector: '.view-poll', // an .in-view class will get toggled on these elements
once: true, // set this to false to have the .in-view class be toggled on AND off
offsetTop: 0, // top threshold to be considered "in view"
offsetBot: 0 // bottom threshold to be considered "in view"
});
function openAnimation() {
var rotate = $('.rotate.in-view');
var scale = $('.scale.in-view');
var translate = $('.translate.in-view');
//feature Left
TweenLite.from(rotate, 1.2, {y:-400, opacity: 0.0, delay:0.0, }, 0.05);
TweenLite.from(scale, 1.2, {y:-400, opacity: 0.0, delay:0.0, }, 0.05);
TweenLite.from(translate, 1.2, {y:-400, opacity: 0.0, delay:0.0, }, 0.05);
}

Three.js OrbitControls Orthographic Panning

In my program, the further out you zoom, the slower you can pan around. So, I want to increase the panning speed based on the zoom level. I've tried .panSpeed, but that doesn't work, and .panSpeed doesn't seem to exist anymore in OrbitControls.js. Is there another function that I can use?
Here is the documentation I looked at for Three.js OrbitControls:
https://github.com/mrdoob/three.js/blob/master/examples/js/controls/OrbitControls.js
If you look in the documentation you just linked youll'find
// Set to false to disable panning
this.enablePan = true;
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
Maybe .keyPanSpeed is what you're looking for.
UPDATE 1:
In the OrbitControls.js you have the following function to handle pan:
function pan( deltaX, deltaY ) {
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight );
}
So if for example you multiply deltaX and deltaY by 10 you'll see the pan going 10 times faster:
constraint.pan( deltaX * 10, deltaY * 10, element.clientWidth, element.clientHeight );
Try to insert your calculations based on zoom right there, it should work.
UPDATE 2:
Actually I'm using an older version of OrbitControls, which is slightly different from the current one. Here it is:
/**
* #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
*/
/*global THREE, console */
( function () {
function OrbitConstraint ( object ) {
this.object = object;
// "target" sets the location of focus, where the object orbits around
// and where it pans with respect to.
this.target = new THREE.Vector3();
// Limits to how far you can dolly in and out ( PerspectiveCamera only )
this.minDistance = 0;
this.maxDistance = Infinity;
// Limits to 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;
////////////
// internals
var scope = this;
var EPS = 0.000001;
// Current position in spherical coordinate system.
var theta;
var phi;
// Pending changes
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var panOffset = new THREE.Vector3();
var zoomChanged = false;
// API
this.getPolarAngle = function () {
return phi;
};
this.getAzimuthalAngle = function () {
return theta;
};
this.rotateLeft = function ( angle ) {
thetaDelta -= angle;
};
this.rotateUp = function ( angle ) {
phiDelta -= angle;
};
// pass in distance in world space to move left
this.panLeft = function() {
var v = new THREE.Vector3();
return function panLeft ( distance ) {
var te = this.object.matrix.elements;
// get X column of matrix
v.set( te[ 0 ], te[ 1 ], te[ 2 ] );
v.multiplyScalar( - distance );
panOffset.add( v );
};
}();
// pass in distance in world space to move up
this.panUp = function() {
var v = new THREE.Vector3();
return function panUp ( distance ) {
var te = this.object.matrix.elements;
// get Y column of matrix
v.set( te[ 4 ], te[ 5 ], te[ 6 ] );
v.multiplyScalar( distance );
panOffset.add( v );
};
}();
// pass in x,y of change desired in pixel space,
// right and down are positive
this.pan = function ( deltaX, deltaY, screenWidth, screenHeight ) {
if ( scope.object instanceof THREE.PerspectiveCamera ) {
// perspective
var position = scope.object.position;
var offset = position.clone().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
scope.panLeft( 2 * deltaX * targetDistance / screenHeight );
scope.panUp( 2 * deltaY * targetDistance / screenHeight );
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
// orthographic
scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth );
scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight );
} else {
// camera neither orthographic or perspective
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
}
};
this.dollyIn = function ( dollyScale ) {
if ( scope.object instanceof THREE.PerspectiveCamera ) {
scale /= dollyScale;
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) );
scope.object.updateProjectionMatrix();
zoomChanged = true;
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
}
};
this.dollyOut = function ( dollyScale ) {
if ( scope.object instanceof THREE.PerspectiveCamera ) {
scale *= dollyScale;
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) );
scope.object.updateProjectionMatrix();
zoomChanged = true;
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
}
};
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 = this.object.position;
offset.copy( position ).sub( this.target );
// rotate offset to "y-axis-is-up" space
offset.applyQuaternion( quat );
// angle from z-axis around y-axis
theta = Math.atan2( offset.x, offset.z );
// angle from y-axis
phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
theta += thetaDelta;
phi += phiDelta;
// restrict theta to be between desired limits
theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) );
// restrict phi to be between desired limits
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
// restrict phi to be betwee EPS and PI-EPS
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
var radius = offset.length() * scale;
// restrict radius to be between desired limits
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
// move target to panned location
this.target.add( panOffset );
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
offset.y = radius * Math.cos( phi );
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
// rotate offset back to "camera-up-vector-is-up" space
offset.applyQuaternion( quatInverse );
position.copy( this.target ).add( offset );
this.object.lookAt( this.target );
if ( this.enableDamping === true ) {
thetaDelta *= ( 1 - this.dampingFactor );
phiDelta *= ( 1 - this.dampingFactor );
} else {
thetaDelta = 0;
phiDelta = 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( this.object.position ) > EPS ||
8 * ( 1 - lastQuaternion.dot( this.object.quaternion ) ) > EPS ) {
lastPosition.copy( this.object.position );
lastQuaternion.copy( this.object.quaternion );
zoomChanged = false;
return true;
}
return false;
};
}();
};
// This set of controls performs orbiting, dollying (zooming), and panning. It maintains
// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
// supported.
//
// 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 ) {
var constraint = new OrbitConstraint( object );
this.domElement = ( domElement !== undefined ) ? domElement : document;
// API
Object.defineProperty( this, 'constraint', {
get: function() {
return constraint;
}
} );
this.getPolarAngle = function () {
return constraint.getPolarAngle();
};
this.getAzimuthalAngle = function () {
return constraint.getAzimuthalAngle();
};
// Set to false to disable this control
this.enabled = true;
// center is old, deprecated; use "target" instead
this.center = this.target;
// 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 };
////////////
// internals
var scope = this;
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();
var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
var state = STATE.NONE;
// for reset
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this.zoom0 = this.object.zoom;
// events
var changeEvent = { type: 'change' };
var startEvent = { type: 'start' };
var endEvent = { type: 'end' };
// pass in x,y of change desired in pixel space,
// right and down are positive
function pan( deltaX, deltaY ) {
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight );
}
this.update = function () {
if ( this.autoRotate && state === STATE.NONE ) {
constraint.rotateLeft( getAutoRotationAngle() );
}
if ( constraint.update() === true ) {
this.dispatchEvent( changeEvent );
}
};
this.reset = function () {
state = STATE.NONE;
this.target.copy( this.target0 );
this.object.position.copy( this.position0 );
this.object.zoom = this.zoom0;
this.object.updateProjectionMatrix();
this.dispatchEvent( changeEvent );
this.update();
};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow( 0.95, scope.zoomSpeed );
}
function onMouseDown( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
if ( event.button === scope.mouseButtons.ORBIT ) {
if ( scope.enableRotate === false ) return;
state = STATE.ROTATE;
rotateStart.set( event.clientX, event.clientY );
} else if ( event.button === scope.mouseButtons.ZOOM ) {
if ( scope.enableZoom === false ) return;
state = STATE.DOLLY;
dollyStart.set( event.clientX, event.clientY );
} else if ( event.button === scope.mouseButtons.PAN ) {
if ( scope.enablePan === false ) return;
state = STATE.PAN;
panStart.set( event.clientX, event.clientY );
}
if ( state !== STATE.NONE ) {
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
scope.dispatchEvent( startEvent );
}
}
function onMouseMove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
if ( state === STATE.ROTATE ) {
if ( scope.enableRotate === false ) return;
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
constraint.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
constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
} else if ( state === STATE.DOLLY ) {
if ( scope.enableZoom === false ) return;
dollyEnd.set( event.clientX, event.clientY );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
constraint.dollyIn( getZoomScale() );
} else if ( dollyDelta.y < 0 ) {
constraint.dollyOut( getZoomScale() );
}
dollyStart.copy( dollyEnd );
} else if ( state === STATE.PAN ) {
if ( scope.enablePan === false ) return;
panEnd.set( event.clientX, event.clientY );
panDelta.subVectors( panEnd, panStart );
pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
}
if ( state !== STATE.NONE ) scope.update();
}
function onMouseUp( /* event */ ) {
if ( scope.enabled === false ) return;
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', 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();
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 ) {
constraint.dollyOut( getZoomScale() );
} else if ( delta < 0 ) {
constraint.dollyIn( getZoomScale() );
}
scope.update();
scope.dispatchEvent( startEvent );
scope.dispatchEvent( endEvent );
}
function onKeyDown( event ) {
if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
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 touchstart( event ) {
if ( scope.enabled === false ) return;
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.enableRotate === false ) return;
state = STATE.TOUCH_ROTATE;
rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
case 2: // two-fingered touch: dolly
if ( scope.enableZoom === false ) return;
state = STATE.TOUCH_DOLLY;
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 );
break;
case 3: // three-fingered touch: pan
if ( scope.enablePan === false ) return;
state = STATE.TOUCH_PAN;
panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
default:
state = STATE.NONE;
}
if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );
}
function touchmove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
event.stopPropagation();
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.enableRotate === false ) return;
if ( state !== STATE.TOUCH_ROTATE ) return;
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
constraint.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
constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
scope.update();
break;
case 2: // two-fingered touch: dolly
if ( scope.enableZoom === false ) return;
if ( state !== STATE.TOUCH_DOLLY ) return;
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 ) {
constraint.dollyOut( getZoomScale() );
} else if ( dollyDelta.y < 0 ) {
constraint.dollyIn( getZoomScale() );
}
dollyStart.copy( dollyEnd );
scope.update();
break;
case 3: // three-fingered touch: pan
if ( scope.enablePan === false ) return;
if ( state !== STATE.TOUCH_PAN ) return;
panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
panDelta.subVectors( panEnd, panStart );
pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
scope.update();
break;
default:
state = STATE.NONE;
}
}
function touchend( /* event */ ) {
if ( scope.enabled === false ) return;
scope.dispatchEvent( endEvent );
state = STATE.NONE;
}
function contextmenu( event ) {
event.preventDefault();
}
this.dispose = function() {
this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
this.domElement.removeEventListener( 'mousedown', onMouseDown, false );
this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );
this.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
this.domElement.removeEventListener( 'touchstart', touchstart, false );
this.domElement.removeEventListener( 'touchend', touchend, false );
this.domElement.removeEventListener( 'touchmove', touchmove, false );
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
window.removeEventListener( 'keydown', onKeyDown, false );
}
this.domElement.addEventListener( 'contextmenu', contextmenu, false );
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
this.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox
this.domElement.addEventListener( 'touchstart', touchstart, false );
this.domElement.addEventListener( 'touchend', touchend, false );
this.domElement.addEventListener( 'touchmove', touchmove, 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, {
object: {
get: function () {
return this.constraint.object;
}
},
target: {
get: function () {
return this.constraint.target;
},
set: function ( value ) {
console.warn( 'THREE.OrbitControls: target is now immutable. Use target.set() instead.' );
this.constraint.target.copy( value );
}
},
minDistance : {
get: function () {
return this.constraint.minDistance;
},
set: function ( value ) {
this.constraint.minDistance = value;
}
},
maxDistance : {
get: function () {
return this.constraint.maxDistance;
},
set: function ( value ) {
this.constraint.maxDistance = value;
}
},
minZoom : {
get: function () {
return this.constraint.minZoom;
},
set: function ( value ) {
this.constraint.minZoom = value;
}
},
maxZoom : {
get: function () {
return this.constraint.maxZoom;
},
set: function ( value ) {
this.constraint.maxZoom = value;
}
},
minPolarAngle : {
get: function () {
return this.constraint.minPolarAngle;
},
set: function ( value ) {
this.constraint.minPolarAngle = value;
}
},
maxPolarAngle : {
get: function () {
return this.constraint.maxPolarAngle;
},
set: function ( value ) {
this.constraint.maxPolarAngle = value;
}
},
minAzimuthAngle : {
get: function () {
return this.constraint.minAzimuthAngle;
},
set: function ( value ) {
this.constraint.minAzimuthAngle = value;
}
},
maxAzimuthAngle : {
get: function () {
return this.constraint.maxAzimuthAngle;
},
set: function ( value ) {
this.constraint.maxAzimuthAngle = value;
}
},
enableDamping : {
get: function () {
return this.constraint.enableDamping;
},
set: function ( value ) {
this.constraint.enableDamping = value;
}
},
dampingFactor : {
get: function () {
return this.constraint.dampingFactor;
},
set: function ( value ) {
this.constraint.dampingFactor = value;
}
},
// 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;
}
}
} );
}() );

Categories