summaryrefslogtreecommitdiff
path: root/site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js
diff options
context:
space:
mode:
Diffstat (limited to 'site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js')
-rw-r--r--site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js225
1 files changed, 225 insertions, 0 deletions
diff --git a/site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js b/site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js
new file mode 100644
index 0000000..510a002
--- /dev/null
+++ b/site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js
@@ -0,0 +1,225 @@
+MX.OrbitCameraMobile = function(opt){
+ var exports = {}, bound = false
+ exports.opt = opt = defaults(opt, {
+ el: window, // object to bind events on
+ camera: scene.camera, // camera object we'll be moving
+ radius: 100,
+ radiusRange: [ 10, 1000 ],
+ rotationX: PI/2,
+ rotationY: 0,
+ center: { x: 0, y: 0, z: 0 },
+ sensitivity: 10, // moving 1 pixel is like moving N radians
+ wheelSensitivity: 10,
+ ease: 10,
+ wheelEase: 10,
+ })
+ var rx, ry, radius, px, py, epsilon = 1e-10
+ var rotationSum = 0
+ var rotationMedian = 0
+ var orientationMax = 0
+ var samples = 0
+ var sampleThreshold = 20
+ var lastAlpha
+
+ exports.dragging = false
+ exports.init = function(){
+ ry = opt.rotationY
+ rx = opt.rotationX
+ radius = opt.radius
+ exports.wheel = new wheel({
+ el: opt.el,
+ update: function(e, delta){
+ opt.radius = clamp( opt.radius + delta * opt.wheelSensitivity, opt.radiusRange[0], opt.radiusRange[1] )
+ },
+ })
+ exports.bind()
+
+ exports.orientationchange()
+ }
+ exports.toggle = function(state){
+ if (state) exports.bind()
+ else exports.unbind()
+ }
+ exports.bind = function(){
+ if (bound) return;
+ bound = true
+ opt.el.addEventListener("touchstart", touch(down))
+ window.addEventListener("touchmove", touch(move))
+ window.addEventListener("touchend", touch(up))
+
+ window.addEventListener('orientationchange', exports.orientationchange)
+ window.addEventListener("devicemotion", exports.devicemotion)
+ window.addEventListener("deviceorientation", exports.deviceorientation)
+
+ exports.wheel.unlock()
+ }
+ exports.unbind = function(){
+ if (! bound) return;
+ bound = false
+ exports.wheel.lock()
+ }
+ function cancelable (fn) {
+ return function(e){
+ e.preventDefault()
+ fn(e)
+ }
+ }
+ function touch (fn){
+ return function(e){
+ fn(e.touches[0])
+ }
+ }
+ function down (e) {
+ px = e.pageX
+ py = e.pageY
+ exports.dragging = true
+ }
+ function move (e) {
+ if (! exports.dragging) return
+ exports.delta(px- e.pageX, py - e.pageY)
+ px = e.pageX
+ py = e.pageY
+ }
+ function up (e) {
+ exports.dragging = false
+ }
+
+ exports.orientationchange = function(e){
+ is_portrait = window.innerWidth < window.innerHeight
+ if (is_portrait) {
+ lastAlpha = 0
+ }
+ }
+ exports.devicemotion = function(e) {
+ if (! is_portrait) return;
+ var rotationBeta = e.rotationRate.alpha; // weird!
+ rotationSum += rotationBeta;
+ samples += 1;
+ }
+ exports.deviceorientation = function (e) {
+ if (! lastAlpha) { lastAlpha = e.alpha }
+ is_portrait ? exports.portraitorientation(e) : exports.landscapeorientation(e)
+ }
+ exports.portraitorientation = function(e) {
+ // compass gives most accurate orientation in portrait mode
+ var alpha, dx = 0, dy = 0
+
+ if (e.webkitCompassHeading) {
+ alpha = 180 - e.webkitCompassHeading;
+ }
+ else {
+ alpha = 180 - e.alpha;
+ }
+
+ // android rotates in reverse
+ if (is_android) {
+ alpha = 360 - alpha
+ }
+
+ // use rotationRate to gauge if we've tilted the screen past vertical
+ // for looking at ceiling
+ if (e.beta > orientationMax) {
+ orientationMax = e.beta
+ rotationMedian = rotationSum
+ }
+
+ // this number was only going to 83 max.. not 90.. weird
+ var beta = e.beta + 7;
+
+ // if we've got enough motion data, we should be able to determine
+ // if we've tilted backwards. otherwise, lock to the horizon.
+ if (! is_android && samples > sampleThreshold) {
+ dx = rotationSum > rotationMedian ? e.beta - 90 : 90 - e.beta
+ }
+ else {
+ dx = 0
+ }
+
+ // avoid jumping around in a circle
+ if (Math.abs(alpha - lastAlpha) < 100 || Math.abs(alpha - lastAlpha) > 300) {
+ dy = alpha - lastAlpha
+ lastAlpha = alpha
+ }
+
+ // avoid jumping around in a circle #2
+ if (dy > 300) {
+ dy -= 360
+ } else if (dy < -300) {
+ dy += 360
+ }
+ opt.rotationX = MX.toRad(dx * -5)
+ opt.rotationY += MX.toRad(dy * 10)
+ }
+ exports.landscapeorientation = function (e) {
+ var dx, dy
+
+ dx = e.gamma > 0 ? 90 - e.gamma : 90 + e.gamma
+ dy = e.alpha - lastAlpha
+ lastAlpha = e.alpha
+
+ // avoid the sudden jump from 0 to -360
+ if (dy > 300) {
+ dy -= 360
+ }
+ else if (dy < -300) {
+ dy += 360
+ }
+
+ opt.rotationX = dx > 45 ? 0 : MX.toRad(dx)
+ opt.rotationY += MX.toRad(dy)
+ }
+
+
+ exports.delta = function(x,y){
+ opt.rotationY += x/window.innerWidth * opt.sensitivity
+ opt.rotationX = opt.rotationX + y/window.innerHeight * opt.sensitivity
+ }
+ exports.move = function(y, x){
+ opt.rotationY = y
+ if (typeof x == "number") { opt.rotationX = x }
+ }
+ exports.zoom = function(r){
+ opt.radius = r
+ }
+ exports.setZoom = function(r){
+ radius = opt.radius = r
+ }
+ exports.zoomPercent = function(n){
+ opt.radius = lerp(n, opt.radiusRange[0], opt.radiusRange[1])
+ }
+ exports.zoomDelta = function(r){
+ opt.radius += r
+ }
+ exports.pause = function(){
+ var sy = sign(opt.rotationY-ry)
+ var sx = sign(opt.rotationX-rx)
+ opt.rotationY = ry + sy * 0.1
+ opt.rotationX = rx + sx * 0.1
+ }
+ exports.update = function(){
+ if (abs(ry - opt.rotationY) > epsilon) {
+ ry = avg(ry, opt.rotationY, opt.ease)
+ }
+ else {
+ ry = opt.rotationY
+ }
+ if (abs(rx - opt.rotationX) > epsilon) {
+ rx = avg(rx, opt.rotationX, opt.ease)
+ }
+ else {
+ rx = opt.rotationX
+ }
+ if (abs(radius - opt.radius) > epsilon) {
+ radius = avg(radius, opt.radius, opt.wheelEase)
+ }
+ else {
+ radius = opt.radius
+ }
+ opt.camera.x = opt.center.x + radius * sin(rx) * cos(ry)
+ opt.camera.z = opt.center.y + radius * sin(rx) * sin(ry)
+ opt.camera.y = opt.center.z + radius * cos(rx)
+ opt.camera.rotationX = PI/2 - rx
+ opt.camera.rotationY = ry + PI/2
+ }
+ return exports
+}