Skip to content
This repository has been archived by the owner on Oct 14, 2024. It is now read-only.

Double-click/tap zoom #1

Open
wants to merge 16 commits into
base: peek
Choose a base branch
from
146 changes: 135 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/*eslint semi: [2, "always"]*/
/*eslint indent: 0*/

var isDoubleClick = require( './isDoubleClick' );

module.exports = function(THREE) {

// BEGIN original file //
Expand All @@ -18,6 +21,8 @@ module.exports = function(THREE) {

this.object = object;

this.zoomScale = 0;

// "target" sets the location of focus, where the object orbits around
// and where it pans with respect to.
this.target = new THREE.Vector3();
Expand Down Expand Up @@ -63,6 +68,7 @@ module.exports = function(THREE) {
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var scaleDelta = 0;
var panOffset = new THREE.Vector3();
var zoomChanged = false;

Expand Down Expand Up @@ -95,6 +101,20 @@ module.exports = function(THREE) {
}
};

this.setZoomScale = function ( desiredZoomScale ) {

if ( this.maxDistance < Infinity ) {

scaleDelta = desiredZoomScale - this.zoomScale;

} else {

scaleDelta = this.zoomScale - desiredZoomScale;

}

};

this.rotateLeft = function ( angle ) {

thetaDelta -= angle;
Expand Down Expand Up @@ -182,7 +202,19 @@ module.exports = function(THREE) {

if ( scope.object instanceof THREE.PerspectiveCamera ) {

scale /= dollyScale;
if ( this.maxDistance < Infinity ) {

var nextRadius = this._radius / dollyScale;
nextRadius = Math.max( this.minDistance, Math.min( this.maxDistance, nextRadius ) );
var nextZoomScale = (this.maxDistance - nextRadius) / (this.maxDistance - this.minDistance) || 0;

this.zoomScale = nextZoomScale;

} else {

scale /= dollyScale;

}

} else if ( scope.object instanceof THREE.OrthographicCamera ) {

Expand All @@ -202,7 +234,19 @@ module.exports = function(THREE) {

if ( scope.object instanceof THREE.PerspectiveCamera ) {

scale *= dollyScale;
if ( this.maxDistance < Infinity ) {

var nextRadius = this._radius * dollyScale;
nextRadius = Math.max( this.minDistance, Math.min( this.maxDistance, nextRadius ) );
var nextZoomScale = (this.maxDistance - nextRadius) / (this.maxDistance - this.minDistance) || 0;

this.zoomScale = nextZoomScale;

} else {

scale *= dollyScale;

}

} else if ( scope.object instanceof THREE.OrthographicCamera ) {

Expand Down Expand Up @@ -247,8 +291,37 @@ module.exports = function(THREE) {

phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );

theta += thetaDelta * (( this.enableDamping === true ) ? this.dampingFactor : 1);
phi += phiDelta * (( this.enableDamping === true ) ? this.dampingFactor : 1);
if ( this.enableDamping === true ) {

theta += thetaDelta * this.dampingFactor;
phi += phiDelta * this.dampingFactor;

if ( this.maxDistance < Infinity ) {

this.zoomScale += scaleDelta * this.dampingFactor;

} else {

scale += scaleDelta;

}

} else {

theta += thetaDelta;
phi += phiDelta;

if ( this.maxDistance < Infinity ) {

this.zoomScale += scaleDelta;

} else {

scale += scaleDelta;

}

}

// restrict theta to be between desired limits
theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) );
Expand All @@ -259,14 +332,25 @@ module.exports = function(THREE) {
// 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 ) );
if ( this.maxDistance < Infinity ) {

var radius = this.maxDistance - this.zoomScale * (this.maxDistance - this.minDistance) || offset.length();
this._radius = radius;

} else {

radius = offset.length() * scale;

// restrict radius to be between desired limits
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );

this.zoomScale = (this.maxDistance - radius) / (this.maxDistance - this.minDistance) || 0;

}

var zoomScale = (this.maxDistance - radius) / (this.maxDistance - this.minDistance) || 0;
var peekScale = (this.maxPolarAngle - phi) / (this.maxPolarAngle - this.minPolarAngle) * 2 - 1;
peekOffset.set(0, peekScale * zoomScale * this.peekDistance, 0);
peekOffset.set(0, peekScale * this.zoomScale * this.peekDistance, 0);

// move target to panned location
this.target.add( panOffset );
Expand All @@ -288,11 +372,13 @@ module.exports = function(THREE) {

thetaDelta *= ( 1 - this.dampingFactor );
phiDelta *= ( 1 - this.dampingFactor );
scaleDelta *= ( 1 - this.dampingFactor );

} else {

thetaDelta = 0;
phiDelta = 0;
scaleDelta = 0;

}

Expand Down Expand Up @@ -482,6 +568,14 @@ module.exports = function(THREE) {

};

this.setZoomScale = function ( desiredZoomScale ) {

if ( scope.enabled === false || scope.enableZoom === false ) return;

constraint.setZoomScale( desiredZoomScale );

};

function getAutoRotationAngle() {

return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
Expand Down Expand Up @@ -595,7 +689,7 @@ module.exports = function(THREE) {

}

function onMouseUp( /* event */ ) {
function onMouseUp( event ) {

if ( scope.enabled === false ) return;

Expand All @@ -604,6 +698,13 @@ module.exports = function(THREE) {
scope.dispatchEvent( endEvent );
state = STATE.NONE;

if ( isDoubleClick( event ) === true ) {

var desiredZoomScale = +constraint.zoomScale.toFixed( 2 ) > 0 ? 0 : 1;
scope.setZoomScale( desiredZoomScale );

}

}

function onMouseWheel( event ) {
Expand Down Expand Up @@ -800,13 +901,20 @@ module.exports = function(THREE) {

}

function touchend( /* event */ ) {
function touchend( event ) {

if ( scope.enabled === false ) return;

scope.dispatchEvent( endEvent );
state = STATE.NONE;

if ( isDoubleClick( event ) === true ) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the doubletap can be initiated only after the touch state has been completed - after state = STATE.NONE;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean this code block should be placed after state = STATE.NONE; ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes


var desiredZoomScale = +constraint.zoomScale.toFixed( 2 ) > 0 ? 0 : 1;
scope.setZoomScale( desiredZoomScale );

}

}

function contextmenu( event ) {
Expand Down Expand Up @@ -865,6 +973,22 @@ module.exports = function(THREE) {

},

zoomScale : {

get: function () {

return this.constraint.zoomScale;

},

set: function ( value ) {

this.setZoomScale( value );

}

},

target: {

get: function () {
Expand Down
47 changes: 47 additions & 0 deletions isDoubleClick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
var clicks = 0
var wait = 300
var doubleTapRadius = 24
var lastClick = null
var distFromLastClick = 0

function isDoubleClick( event ) {

var click = event.changedTouches && event.changedTouches[0] || event
click.type = event.type

if ( lastClick !== null ) {

if ( lastClick.type !== click.type ) return false

var horizontalDist = click.pageX - lastClick.pageX
var verticalDist = click.pageY - lastClick.pageY
distFromLastClick = Math.sqrt( Math.pow( horizontalDist, 2 ) + Math.pow( verticalDist, 2 ) )

} else {

lastClick = click
distFromLastClick = 0

}

if ( distFromLastClick <= doubleTapRadius ) clicks++

if ( clicks !== 2 ) {

setTimeout(function () {

clicks = 0
lastClick = null

}, wait)

return false

} else {

return true

}
}

module.exports = isDoubleClick