@hughsk/fulltilt
Version:
Standalone device orientation + device motion normalization and conversion library
290 lines (173 loc) • 6.14 kB
JavaScript
///// FULLTILT.DeviceOrientation //////
FULLTILT.DeviceOrientation = function (options) {
this.options = options || {}; // by default use UA deviceorientation 'type' ("game" on iOS, "world" on Android)
var tries = 0;
var maxTries = 200;
var successCount = 0;
var successThreshold = 10;
this.alphaOffsetScreen = 0;
this.alphaOffsetDevice = undefined;
// Create a game-based deviceorientation object (initial alpha === 0 degrees)
if (this.options.type === "game") {
var setGameAlphaOffset = function(evt) {
if (evt.alpha !== null) { // do regardless of whether 'evt.absolute' is also true
this.alphaOffsetDevice = new FULLTILT.Euler(evt.alpha, 0, 0);
this.alphaOffsetDevice.rotateZ( -screenOrientationAngle );
// Discard first {successThreshold} responses while a better compass lock is found by UA
if(++successCount >= successThreshold) {
window.removeEventListener( 'deviceorientation', setGameAlphaOffset, false );
return;
}
}
if(++tries >= maxTries) {
window.removeEventListener( 'deviceorientation', setGameAlphaOffset, false );
}
}.bind(this);
window.addEventListener( 'deviceorientation', setGameAlphaOffset, false );
// Create a compass-based deviceorientation object (initial alpha === compass degrees)
} else if (this.options.type === "world") {
var setCompassAlphaOffset = function(evt) {
if (evt.absolute !== true && evt.webkitCompassAccuracy !== undefined && evt.webkitCompassAccuracy !== null && +evt.webkitCompassAccuracy >= 0 && +evt.webkitCompassAccuracy < 50) {
this.alphaOffsetDevice = new FULLTILT.Euler(evt.webkitCompassHeading, 0, 0);
this.alphaOffsetDevice.rotateZ( screenOrientationAngle );
this.alphaOffsetScreen = screenOrientationAngle;
// Discard first {successThreshold} responses while a better compass lock is found by UA
if(++successCount >= successThreshold) {
window.removeEventListener( 'deviceorientation', setCompassAlphaOffset, false );
return;
}
}
if(++tries >= maxTries) {
window.removeEventListener( 'deviceorientation', setCompassAlphaOffset, false );
}
}.bind(this);
window.addEventListener( 'deviceorientation', setCompassAlphaOffset, false );
} // else... use whatever orientation system the UA provides ("game" on iOS, "world" on Android)
};
FULLTILT.DeviceOrientation.prototype = {
constructor: FULLTILT.DeviceOrientation,
start: function ( callback ) {
if ( callback && Object.prototype.toString.call( callback ) == '[object Function]' ) {
sensors.orientation.callbacks.push( callback );
}
if( !screenActive ) {
if ( hasScreenOrientationAPI ) {
window.screen.orientation.addEventListener( 'change', handleScreenOrientationChange, false );
} else {
window.addEventListener( 'orientationchange', handleScreenOrientationChange, false );
}
}
if ( !sensors.orientation.active ) {
window.addEventListener( 'deviceorientation', handleDeviceOrientationChange, false );
sensors.orientation.active = true;
}
},
stop: function () {
if ( sensors.orientation.active ) {
window.removeEventListener( 'deviceorientation', handleDeviceOrientationChange, false );
sensors.orientation.active = false;
}
},
listen: function( callback ) {
this.start( callback );
},
getFixedFrameQuaternion: (function () {
var euler = new FULLTILT.Euler();
var matrix = new FULLTILT.RotationMatrix();
var quaternion = new FULLTILT.Quaternion();
return function() {
var orientationData = sensors.orientation.data || { alpha: 0, beta: 0, gamma: 0 };
var adjustedAlpha = orientationData.alpha;
if (this.alphaOffsetDevice) {
matrix.setFromEuler( this.alphaOffsetDevice );
matrix.rotateZ( - this.alphaOffsetScreen );
euler.setFromRotationMatrix( matrix );
if (euler.alpha < 0) {
euler.alpha += 360;
}
euler.alpha %= 360;
adjustedAlpha -= euler.alpha;
}
euler.set(
adjustedAlpha,
orientationData.beta,
orientationData.gamma
);
quaternion.setFromEuler( euler );
return quaternion;
};
})(),
getScreenAdjustedQuaternion: (function () {
var quaternion;
return function() {
quaternion = this.getFixedFrameQuaternion();
// Automatically apply screen orientation transform
quaternion.rotateZ( - screenOrientationAngle );
return quaternion;
};
})(),
getFixedFrameMatrix: (function () {
var euler = new FULLTILT.Euler();
var matrix = new FULLTILT.RotationMatrix();
return function () {
var orientationData = sensors.orientation.data || { alpha: 0, beta: 0, gamma: 0 };
var adjustedAlpha = orientationData.alpha;
if (this.alphaOffsetDevice) {
matrix.setFromEuler( this.alphaOffsetDevice );
matrix.rotateZ( - this.alphaOffsetScreen );
euler.setFromRotationMatrix( matrix );
if (euler.alpha < 0) {
euler.alpha += 360;
}
euler.alpha %= 360;
adjustedAlpha -= euler.alpha;
}
euler.set(
adjustedAlpha,
orientationData.beta,
orientationData.gamma
);
matrix.setFromEuler( euler );
return matrix;
};
})(),
getScreenAdjustedMatrix: (function () {
var matrix;
return function () {
matrix = this.getFixedFrameMatrix();
// Automatically apply screen orientation transform
matrix.rotateZ( - screenOrientationAngle );
return matrix;
};
})(),
getFixedFrameEuler: (function () {
var euler = new FULLTILT.Euler();
var matrix;
return function () {
matrix = this.getFixedFrameMatrix();
euler.setFromRotationMatrix( matrix );
return euler;
};
})(),
getScreenAdjustedEuler: (function () {
var euler = new FULLTILT.Euler();
var matrix;
return function () {
matrix = this.getScreenAdjustedMatrix();
euler.setFromRotationMatrix( matrix );
return euler;
};
})(),
isAbsolute: function () {
if ( sensors.orientation.data && sensors.orientation.data.absolute === true ) {
return true;
}
return false;
},
getLastRawEventData: function () {
return sensors.orientation.data || {};
},
ALPHA: 'alpha',
BETA: 'beta',
GAMMA: 'gamma'
};