diff options
Diffstat (limited to 'site/public/javascripts/mx/extensions/mx.movementsMobile.js')
| -rw-r--r-- | site/public/javascripts/mx/extensions/mx.movementsMobile.js | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/site/public/javascripts/mx/extensions/mx.movementsMobile.js b/site/public/javascripts/mx/extensions/mx.movementsMobile.js new file mode 100644 index 0000000..95b61d1 --- /dev/null +++ b/site/public/javascripts/mx/extensions/mx.movementsMobile.js @@ -0,0 +1,237 @@ + +MX.MobileMovements = function (cam) { + + var touching = true, + moving = false, + startTime = null, + v = 12, + vr = Math.PI * 0.012, + vx = vy = vz = 0; + + var directionLocked = false, + directionLockThreshold = 5 + + var pos = { x: 0, y: viewHeight, z: 0, rotationX: 0, rotationY: 0 } + + var pointX, pointY, deltaX, deltaY, distX = 0, distY = 0, absDistX = 0, absDistY = 0, startTime + + var rotationX = 0, rotationY = 0, destRotationX = 0, destRotationY = 0 + var rotationSum = 0 + var rotationMedian = 0 + var orientationMax = 0 + var samples = 0 + var sampleThreshold = 120 + var lastAlpha + + var is_portrait + + var exports = { + + init: function () { + exports.orientationchange() + + document.addEventListener("touchstart", exports.touchstart) + document.addEventListener("touchmove", exports.touchmove) + document.addEventListener("touchend", exports.touchend) + window.addEventListener('orientationchange', exports.orientationchange) + window.addEventListener("devicemotion", exports.devicemotion) + window.addEventListener("deviceorientation", exports.deviceorientation) + }, + touchstart: function(e){ + if (e.touches.length == 1) { + touching = true + + startTime = Date.now() + + var point = event.touches[0] + pointX = point.pageX + pointY = point.pageY + distX = distY = 0 + pos.x = cam.x + pos.z = cam.z + pos.rotationY = cam.rotationY + } + }, + touchmove: function(e){ + e.preventDefault() + if (e.touches.length == 1) { + + var timestamp = Date.now() + var point = event.touches[0] + deltaX = point.pageX - pointX + deltaY = point.pageY - pointY + + pointX = point.pageX + pointY = point.pageY + + distX += deltaX + distY += deltaY + absDistX = abs(distX) + absDistY = abs(distY) + } + }, + touchend: function(e){ + e.preventDefault() + if (e.touches.length == 0) { + touching = directionLocked = false + var timestamp = Date.now() + var duration = startTime - timestamp + if (duration < 300) { + } + } + }, + orientationchange: function(e){ + is_portrait = window.innerWidth < window.innerHeight + if (is_portrait) { + lastAlpha = 0 + } + }, + devicemotion: function(e) { + if (! is_portrait) return; + var rotationBeta = e.rotationRate.alpha; // weird! + rotationSum += rotationBeta; + samples += 1; + }, + deviceorientation: function (e) { + if (! lastAlpha) { lastAlpha = e.alpha } + is_portrait ? exports.portraitorientation(e) : exports.landscapeorientation(e) + }, + 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 + } + + destRotationX = MX.toRad(dx) + destRotationY += MX.toRad(dy) + }, + + 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 + } + + destRotationX = dx > 45 ? 0 : MX.toRad(dx) + destRotationY += MX.toRad(dy) + }, + + update: function () { + var drx, dry + + dry = (destRotationY - rotationY) / 6 + drx = (destRotationX - rotationX) / 6 + rotationY += dry + rotationX += drx + cam.rotationY = pos.rotationY += dry + cam.rotationX = pos.rotationX += drx + + if (distX || distY) { + var oldDistY = absDistY, oldDistX = absDistX + absDistY = avg(absDistY, 0, 5) + var dy = (oldDistY - absDistY) * sign(distY) * 2 + + absDistX = avg(absDistX, 0, 5) + var dx = (oldDistX - absDistX) * sign(distX) * 2 + + distY = sign(distY) * absDistY + distX = sign(distX) * absDistX + + pos.x -= dy * Math.cos(pos.rotationY + Math.PI / 2) + pos.z -= dy * Math.sin(pos.rotationY + Math.PI / 2) + cam.rotationY = pos.rotationY += dx / (window.innerWidth) * Math.PI / 2 + + app.tube("move", pos) + } + }, + + lock: function(){ locked = true }, + unlock: function(){ locked = false }, + scale: function(n){ if (n) scale = n; return scale }, + resetScale: function(n){ scale = DEFAULT_SCALE }, + gravity: function(g){ return typeof g == "boolean" ? gravity = g : gravity }, + velocity: function(n){ v = clamp(n, 1, 50) }, + jumpVelocity: function(n){ jumpV = clamp(n, 1, 50) }, + } + + return exports +} + + +// function momentum (current, start, time, lowerMargin, wrapperSize, deceleration) { +// var distance = current - start, +// speed = Math.abs(distance) / time, +// destination, +// duration; +// +// deceleration = deceleration === undefined ? 0.0006 : deceleration; +// +// destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); +// duration = speed / deceleration; +// +// if ( destination < lowerMargin ) { +// destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; +// distance = Math.abs(destination - current); +// duration = distance / speed; +// } else if ( destination > 0 ) { +// destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; +// distance = Math.abs(current) + destination; +// duration = distance / speed; +// } +// +// return { +// destination: Math.round(destination), +// duration: duration +// }; +// } |
