MX.FollowingOrbitCamera = function(opt){ var exports = {}, bound = false, portraitMode = false var locked = 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: Math.PI/2, rotationY: 0, rotationXRange: [ 0, 1 ], rotationYRange: [ 0, 1 ], center: { x: 0, y: 0, z: 0 }, sensitivity: 10, // moving 1 pixel is like moving N radians wheelSensitivity: 10, ease: 10, }) opt.rotationXRange[0] *= Math.PI opt.rotationXRange[1] *= Math.PI opt.rotationYRange[0] *= Math.PI opt.rotationYRange[1] *= Math.PI var rx, ry, radius, px, py, epsilon = 1e-5, dragging = false exports.init = function(){ opt.rotationY = ry = ( opt.rotationYRange[0] + opt.rotationYRange[1] ) / 2 opt.rotationX = rx = ( opt.rotationXRange[0] + opt.rotationXRange[1] ) / 2 radius = opt.radius exports.wheel = new wheel({ el: opt.el, update: function(e, delta){ if (locked) return opt.radius = clamp( opt.radius + delta * opt.wheelSensitivity, opt.radiusRange[0], opt.radiusRange[1] ) }, }) exports.bind() } exports.toggle = function(state){ if (state) exports.bind() else exports.unbind() } exports.lock = function(){ locked = true } exports.unlock = function(){ locked = false } exports.bind = function(){ if (bound) return; bound = true // opt.el.addEventListener("mousedown", down) if (is_mobile) { if ('DeviceOrientationEvent' in window) { window.addEventListener("resize", resize) window.addEventListener("deviceorientation", deviceorientation) resize() } } else { window.addEventListener("mousemove", move) } // window.addEventListener("mouseup", up) exports.wheel.unlock() } exports.unbind = function(){ if (! bound) return; bound = false // opt.el.removeEventListener("mousedown", down) window.removeEventListener("mousemove", move) // window.removeEventListener("mouseup", up) exports.wheel.lock() } // function down (e) { // px = e.pageX // py = e.pageY // dragging = true // } function move (e) { // if (! dragging) return // exports.delta(px - e.pageX, py - e.pageY) if (locked) return exports.delta( e.pageX, e.pageY) px = e.pageX py = e.pageY } function resize (e) { var aspect = window.innerHeight / window.innerWidth; portraitMode = aspect >= 1; } function deviceorientation (e){ if (e && 'beta' in e && e.beta) { var b, g if (portraitMode) { b = e.beta g = e.gamma } else { b = e.gamma g = e.beta } // console.log(b, g) } } // function up (e) { // dragging = false // } exports.delta = function(x,y){ // opt.rotationY += x/window.innerWidth * opt.sensitivity // opt.rotationX = clamp( opt.rotationX + y/window.innerHeight * opt.sensitivity, 0, Math.PI) opt.rotationY = lerp( x / window.innerWidth, opt.rotationYRange[0], opt.rotationYRange[1] ) opt.rotationX = lerp( y / window.innerHeight, opt.rotationXRange[0], opt.rotationXRange[1] ) } exports.zoom = function(r){ opt.radius = r } exports.zoomDelta = function(r){ opt.radius += r } exports.move = function(y, x){ opt.rotationY = y if (typeof x == "number") { opt.rotationX = x } } exports.update = function(){ if (locked) return if (Math.abs(ry - opt.rotationY) > epsilon) { ry = avg(ry, opt.rotationY, opt.ease) } else { ry = opt.rotationY } if (Math.abs(rx - opt.rotationX) > epsilon) { rx = avg(rx, opt.rotationX, opt.ease) } else { rx = opt.rotationX } if (Math.abs(radius - opt.radius) > epsilon) { radius = avg(radius, opt.radius, opt.ease) } else { radius = opt.radius } opt.camera.x = opt.center.x + radius * Math.sin(rx) * Math.cos(ry) opt.camera.z = opt.center.y + radius * Math.sin(rx) * Math.sin(ry) opt.camera.y = opt.center.z + radius * Math.cos(rx) opt.camera.rotationX = Math.PI/2 - rx opt.camera.rotationY = ry + Math.PI/2 } return exports }