///
module TDev { export module RT {
export enum DeviceFaceOrientation {
Up,
Down
}
export enum DeviceLandscapeOrientation {
Portrait,
LandscapeLeft,
LandscapeRight
}
export module DeviceOrientation
{
var _alpha: number = undefined;
var _beta: number = undefined;
var _gamma: number = undefined;
var _heading: number = 0;
var _face_orientation: DeviceFaceOrientation = undefined;
var _landscape_orientation: DeviceLandscapeOrientation = undefined;
var _runtime: Runtime = undefined;
function clearData(clearRuntime = true)
{
Util.log('deviceorientation: clear data');
_alpha = undefined;
_beta = undefined;
_gamma = undefined;
_heading = 0;
_face_orientation = undefined;
_landscape_orientation = undefined;
if (clearRuntime)
_runtime = undefined;
}
// see http://dev.w3.org/geo/api/spec-source-orientation.html#deviceorientation
export function computeHeading()
{
if (Math.abs(_gamma) < 45 &&
45 < Math.abs(_beta) &&
Math.abs(_beta) < 135) {
var sinAlpha = Math.sin(_alpha);
var cosAlpha = Math.cos(_alpha);
var sinBeta = Math.sin(_beta);
var sinGamma = Math.sin(_gamma);
var cosGamma = Math.cos(_gamma);
_heading = Math.atan(
(-cosAlpha * sinGamma - sinAlpha * sinBeta * cosGamma)
/ (-sinAlpha * sinGamma + cosGamma * sinBeta * cosGamma)
);
} else {
_heading = 360 - _alpha;
}
}
export function orientation(r: ResumeCtx)
{
start(r.rt);
if (_alpha && _beta && _gamma)
r.resumeVal(Vector3.mk(_alpha, _beta, _gamma));
else
r.resumeVal(Vector3.mk(0,0,0));
}
export function heading(r: ResumeCtx)
{
start(r.rt);
r.resumeVal(_heading);
}
function detectLandscapeOrientation()
{
var threshold = 30;
if (_beta > 90 - threshold && _beta < 90 + threshold) {
if (_landscape_orientation != DeviceLandscapeOrientation.Portrait) {
Util.log('phone portrait');
_landscape_orientation = DeviceLandscapeOrientation.Portrait;
Senses.raisePhonePortrait();
}
} else if ((_beta < threshold || _beta > 360 - threshold)
&& _gamma > 270 - threshold && _gamma < 270 + threshold) {
if (_landscape_orientation != DeviceLandscapeOrientation.LandscapeLeft) {
Util.log('phone landscape left');
_landscape_orientation = DeviceLandscapeOrientation.LandscapeLeft;
Senses.raisePhoneLandscapeLeft();
}
} else if ((_beta < threshold || _beta > 360 - threshold)
&& _gamma > 90 - threshold && _gamma < 90 + threshold) {
if (_landscape_orientation != DeviceLandscapeOrientation.LandscapeRight) {
Util.log('phone landscape right');
_landscape_orientation = DeviceLandscapeOrientation.LandscapeRight;
Senses.raisePhoneLandscapeRight();
}
} else {
_landscape_orientation = undefined;
}
}
function detectFaceOrientation()
{
var threshold = 30;
if ((_beta < threshold || _beta > 360 - threshold)
&& (_gamma < threshold || _gamma > 360 - threshold)
) {
if (_face_orientation != DeviceFaceOrientation.Up) {
Util.log('phone face up');
_face_orientation = DeviceFaceOrientation.Up;
Senses.raisePhoneFaceUp();
}
}
else if (
( (_gamma > 180 - threshold && _gamma < 180 + threshold && (_beta < threshold || _beta > 360 - threshold))
|| (_beta > 180 - threshold && _beta < 180 + threshold && (_gamma < threshold || _gamma > 360 - threshold))
)) {
if (_face_orientation != DeviceFaceOrientation.Down) {
Util.log('phone face down');
_face_orientation = DeviceFaceOrientation.Down;
Senses.raisePhoneFaceDown();
}
} else {
_face_orientation = undefined;
}
}
export function setOrientation(alpha: number, beta: number, gamma: number)
{
_alpha = alpha; if (_alpha && _alpha < 0) _alpha += 360.0;
_beta = beta; if (_beta && _beta < 0) _beta += 360.0;
_gamma = gamma; if (_gamma && _gamma < 0) _gamma += 360.0;
if (!_alpha || !_beta || !_gamma) {
clearData(false);
return;
}
detectLandscapeOrientation();
detectFaceOrientation();
}
export function setHeading(heading: number)
{
_heading = heading;
}
function reading(ev: any) {
Util.log('deviceorientation: reading...');
// read data
setOrientation(ev.alpha, ev.beta, ev.gamma);
// compass
setHeading(ev.compassHeading || ev.webkitCompassHeading || undefined);
if (!_heading && ev.absolute) {
computeHeading();
}
}
export var isOrientationSupported = () : boolean =>
{
return Browser.deviceOrientation;
}
export var isHeadingSupported = () : boolean =>
{
return Browser.deviceHeading;
}
export function rt_start(r: Runtime) {
if (r.eventEnabled("phone face up")
|| r.eventEnabled("phone face down")
|| r.eventEnabled("phone portrait")
|| r.eventEnabled("phone landscape left")
|| r.eventEnabled("phone landscape right")
) {
start(r);
}
}
export function rt_stop(rt: Runtime) {
stop(rt);
}
export var addOrientationReadingEvent = () =>
{
Util.log('deviceorientation: attaching');
window.addEventListener('deviceorientation', reading, false);
}
export var removeOrientationReadingEvent = () =>
{
window.removeEventListener('deviceorientation', reading, false);
}
export var addHeadingReadingEvent = () =>
{
Util.log('compassneedscalibration: attaching');
window.addEventListener("compassneedscalibration", calibrateCompass, false);
}
export var removeHeadingReadingEvent = () =>
{
window.removeEventListener("compassneedscalibration", calibrateCompass, false);
}
function calibrateCompass(ev : Event) {
HTML.showNotificationText("Your compass needs calibrating! Wave your device in a figure-eight motion.");
}
export function start(r : Runtime) {
if (r.isHeadless()) return
if (isOrientationSupported() || isHeadingSupported()) {
if (!_runtime) {
_runtime = r;
if (isOrientationSupported())
DeviceOrientation.addOrientationReadingEvent();
if (isHeadingSupported())
DeviceOrientation.addHeadingReadingEvent();
}
}
else {
Util.log('deviceorientation: not supported');
clearData();
}
}
export function stop(r: Runtime) {
if (r.isHeadless()) return
Util.log('deviceorientation: stop');
DeviceOrientation.removeOrientationReadingEvent();
DeviceOrientation.removeHeadingReadingEvent();
clearData(true);
}
}
} }