js/Mobilizing/input/Orientation.js
import Component from "../core/Component";
//import * as _Math from "../core/util/Math";
import Device from '../core/util/Device';
/**
* Fired when a new orientation is available
* @event deviceorientation
*/
const EVT_DEVICE_ORIENTATION = "deviceorientation";
/**
* Fired when calibration is required
* @event compassneedscalibration
*/
const EVT_COMPASS_CALIBRATION = "compassneedscalibration";
/**
* Uses built-in compass and/or gyroscope to produce orientation Data. Some heplers functions are in there to generate quarternion that can be applied on a camera or a 3D object's transform.
* !WARNING! On iOS 13+ you must call on() in a user interaction (i.e "click" or equivalent). See examples!
*/
export default class Orientation extends Component {
constructor() {
super(...arguments)
/**
* true if the magnetometer/compass is available on the device, false otherwise
*/
this.available = window.DeviceOrientationEvent;
}
setup() {
if (!this._setupDone) {
/**
The compass/gyro current raw values.
This can also be get with the onDeviceOrientation event from the user script.
@type {Object}
@property alpha
@property gamma
@property beta
@property heading
*/
this.compass = {
alpha: null,
gamma: null,
beta: null,
heading: null
};
this._baseHeading = 0;
this.rotationMatrix = [];
super.setup();
}
}
on() {
super.on();
//manage iOS 13+ fucking security system : must activate sensors on "click"
if (Device.getOS() === "iOS") {
if (typeof window.DeviceOrientationEvent.requestPermission === 'function') {
window.DeviceOrientationEvent.requestPermission().then((permissionState) => {
if (permissionState === "granted") {
window.addEventListener("deviceorientation", (event) => this.onDeviceOrientation(event));
}
}).catch(console.error);
}
else {
// handle regular non iOS 13+ devices
window.addEventListener("deviceorientation", (event) => this.onDeviceOrientation(event));
}
}
else {
window.addEventListener("deviceorientation", (event) => this.onDeviceOrientation(event));
}
window.addEventListener("compassneedscalibration", (event) => this.onCompassCalibration(event));
}
off() {
super.off();
window.removeEventListener("deviceorientation", (event) => this.onDeviceOrientation(event));
window.removeEventListener("compassneedscalibration", (event) => this.onCompassCalibration(event));
}
/**
* Reset the horizontal rotation to make a kind of realtime recalibration of the rotation
*/
resetDirection() {
if (this.compass.heading) {
this._baseHeading = this.compass.heading;
}
}
/**
* compass calibration event callback
* @private
* @param {Object} event
*/
onCompassCalibration(event) {
//alert("onCompassCalibration call", event);
this.events.trigger(EVT_COMPASS_CALIBRATION, event);
}
/**
* callback used to access compass event.
*
* @private
* @param {Object} event
*/
onDeviceOrientation(event) {
this.compass.alpha = event.alpha;//x
this.compass.beta = event.beta;//y
this.compass.gamma = event.gamma;//z
//this.compass.heading = event.compassHeading || event.webkitCompassHeading || event.mozCompassHeading || event.ieCompassHeading;// || -event.alpha;
//When the device doesn't generate a heading information, find a substitute.
if (event.webkitCompassHeading) {
this.compass.heading = event.webkitCompassHeading;
}
else {
this.compass.heading = -event.alpha;
}
this.rotationMatrix = this.getRotationMatrix(this.compass.alpha, this.compass.beta, this.compass.gamma);
this.events.trigger(EVT_DEVICE_ORIENTATION, this.compass);
}
/**
* ©https://www.w3.org/TR/orientation-event/
* @param {Number} alpha
* @param {Number} beta
* @param {Number} gamma
* @returns
*/
getRotationMatrix(alpha, beta, gamma) {
const degtorad = Math.PI / 180; // Degree-to-Radian conversion
const _x = beta ? beta * degtorad : 0; // beta value
const _y = gamma ? gamma * degtorad : 0; // gamma value
const _z = alpha ? alpha * degtorad : 0; // alpha value
const cX = Math.cos(_x);
const cY = Math.cos(_y);
const cZ = Math.cos(_z);
const sX = Math.sin(_x);
const sY = Math.sin(_y);
const sZ = Math.sin(_z);
// ZXY rotation matrix construction.
const m11 = cZ * cY - sZ * sX * sY;
const m12 = - cX * sZ;
const m13 = cY * sZ * sX + cZ * sY;
const m21 = cY * sZ + cZ * sX * sY;
const m22 = cZ * cX;
const m23 = sZ * sY - cZ * cY * sX;
const m31 = - cX * sY;
const m32 = sX;
const m33 = cX * cY;
return [
m11, m12, m13,
m21, m22, m23,
m31, m32, m33
];
}
}