// Usage: // // var control = new MX.RotationControl() // control.init( object{MX.Object3D} [, listener{HTMLElement}] ) // // In animation loop: // // control.update() // // The above code will register handler functions on `listener` // and will be updating `object`s rotationX and rotationY // If no `listener` is provided, will default to `object`s el. MX.GyroControl = function () { var object, locked = false var down = false, active = false, lastX, lastY var pub = { sensitivity : .5, ease : 10, drag : true, inverseX : false, inverseY : false, disableX : false, disableY : false, rotationX : 0, rotationY : 0, offsetX : 0, offsetY : 0, upperBoundX : undefined, lowerBoundX : undefined, upperBoundY : undefined, lowerBoundY : undefined, usePreset: function (name) { var ops = presets[name] if (ops) { if (currentPreset && presets[currentPreset].teardown) { presets[currentPreset].teardown() } for (var op in ops) { if (op !== 'setup' && op !== 'teardown') { pub[op] = ops[op] } } if (op.setup) ops.setup() } } } var currentPreset var presets = { firstPerson: { drag: false, ease: 2, sensitivity: .18, inverseX: true, inverseY: true, upperBoundX: MX.rotationUnit === 'deg' ? 90 : Math.PI / 2, lowerBoundX: MX.rotationUnit === 'deg' ? -90 : -Math.PI / 2 }, skybox: { sensitivity: .18, inverseX: true, inverseY: true, upperBoundX: MX.rotationUnit === 'deg' ? 90 : Math.PI / 2, lowerBoundX: MX.rotationUnit === 'deg' ? -90 : -Math.PI / 2 } } function init (obj, lis) { if (active) return object = obj pub.rotationX = object.rotationX pub.rotationY = object.rotationY if (lis instanceof HTMLElement) { listener = lis } else if (lis instanceof MX.Object3D) { listener = lis.el } else { listener = window.document } window.addEventListener('deviceorientation', updateTarget, false); updateTarget({ 'alpha': 0, 'beta': 0, 'gamma': 0 }); active = true } function changeObject (obj) { object = obj pub.rotationX = object.rotationX pub.rotationY = object.rotationY } function changeListener (lis) { remove() active = false init(object, lis) } function remove () { if (!active) return window.removeEventListener('deviceorientation', deviceorientation, false); active = false } function updateTarget (e) { var dy = 360 * ((-e.beta + 90) / 180); var dx = 360 * (-e.gamma /180); if (MX.rotationUnit !== 'deg') { dx = MX.toRad(dx) dy = MX.toRad(dy) } if (!pub.disableX) { pub.rotationX = dy * pub.sensitivity if (pub.upperBoundX) pub.rotationX = Math.min(pub.rotationX, pub.upperBoundX) if (pub.lowerBoundX) pub.rotationX = Math.max(pub.rotationX, pub.lowerBoundX) } if (!pub.disableY) { pub.rotationY = dx * pub.sensitivity if (pub.upperBoundY) pub.rotationY = Math.min(pub.rotationY, pub.upperBoundY) if (pub.lowerBoundY) pub.rotationY = Math.max(pub.rotationY, pub.lowerBoundY) } pub.rotationX += pub.offsetX pub.rotationY += pub.offsetY } function update () { if (!object || locked) return var dx = pub.rotationX - object.rotationX, dy = pub.rotationY - object.rotationY if (Math.abs(dx) < 0.0001) { object.rotationX = pub.rotationX } else { object.rotationX += dx / pub.ease } if (Math.abs(dy) < 0.0001) { object.rotationY = pub.rotationY } else { object.rotationY += dy / pub.ease } } function lock () { locked = true } function unlock () { pub.rotationX = object.rotationX pub.rotationY = object.rotationY locked = false } pub.init = init pub.remove = remove pub.update = update pub.lock = lock pub.unlock = unlock pub.changeObject = changeObject pub.changeListener = changeListener return pub }