From ccafdf24213ffe0d303cf8cc5bf11325a84751cc Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 27 May 2015 16:08:56 -0400 Subject: deviceorientation stuff --- Gruntfile.js | 1 + site/public/assets/javascripts/_env.js | 28 ++- .../mx/extensions/mx.unclampedOrbitCameraMobile.js | 225 +++++++++++++++++++++ site/templates/index.liquid | 1 + 4 files changed, 247 insertions(+), 8 deletions(-) create mode 100644 site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js diff --git a/Gruntfile.js b/Gruntfile.js index b32e6ad..bb6f1eb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,6 +12,7 @@ module.exports = function(grunt) { "site/public/assets/javascripts/mx/mx.skew.js", "site/public/assets/javascripts/mx/extensions/mx.scene.js", "site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCamera.js", + "site/public/assets/javascripts/mx/extensions/mx.unclampedOrbitCameraMobile.js", "site/public/assets/javascripts/mx/primitives/mx.image.js", "site/public/assets/javascripts/vendor/jquery.min.js", diff --git a/site/public/assets/javascripts/_env.js b/site/public/assets/javascripts/_env.js index dee524c..6748409 100644 --- a/site/public/assets/javascripts/_env.js +++ b/site/public/assets/javascripts/_env.js @@ -74,14 +74,26 @@ environment.init = function(){ environment.ready = function(){ if (window.innerWidth < 500) document.body.classList.add('mobile') - controls = new MX.OrbitCamera({ - radius: 100000, - radiusRange: [ 10, 2000 ], - rotationX: PI/2, - rotationY: PI, - wheelEase: 20, - ease: 100 - }) + if (is_mobile) { + controls = new MX.OrbitCameraMobile({ + radius: 100000, + radiusRange: [ 10, 2000 ], + rotationX: PI/2, + rotationY: PI, + wheelEase: 20, + ease: 100 + }) + } + else { + controls = new MX.OrbitCamera({ + radius: 100000, + radiusRange: [ 10, 2000 ], + rotationX: PI/2, + rotationY: PI, + wheelEase: 20, + ease: 100 + }) + } controls.init() $('.cat').click( function(){ 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 +} diff --git a/site/templates/index.liquid b/site/templates/index.liquid index 41d64e6..75fe389 100644 --- a/site/templates/index.liquid +++ b/site/templates/index.liquid @@ -181,6 +181,7 @@ WEBSITE BY OKFOCUS, http://okfoc.us, Internet Legends. + -- cgit v1.2.3-70-g09d2