1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 cc.UIInterfaceOrientationLandscapeLeft = -90;
 28 
 29 cc.UIInterfaceOrientationLandscapeRight = 90;
 30 
 31 cc.UIInterfaceOrientationPortraitUpsideDown = 180;
 32 
 33 cc.UIInterfaceOrientationPortrait = 0;
 34 
 35 /**
 36  * he device accelerometer reports values for each axis in units of g-force
 37  */
 38 cc.Acceleration = function (x, y, z, timestamp) {
 39     this.x = x || 0;
 40     this.y = y || 0;
 41     this.z = z || 0;
 42     this.timestamp = timestamp || 0;
 43 };
 44 
 45 /**
 46  * @class
 47  * @extends cc.Class
 48  */
 49 cc.Accelerometer = cc.Class.extend(/** @lends cc.Accelerometer# */{
 50     setDelegate: function (delegate) {
 51         cc.AccelerometerDispatcher.getInstance().addDelegate(delegate);
 52     },
 53     setAccelerometerInterval: function (interval) {
 54         cc.AccelerometerDispatcher.getInstance().setAccelerometerInterval(interval);
 55     }
 56 });
 57 
 58 /**
 59  *
 60  * The cc.AccelerometerDelegate defines a single method for
 61  * receiving acceleration-related data from the system.
 62  * @class
 63  * @extends cc.Class
 64  */
 65 cc.AccelerometerDispatcher = cc.Class.extend(/** @lends cc.AccelerometerDispatcher# */{
 66     _delegate: null,
 67     _acceleration: null,
 68     _deviceEvent: null,
 69     _interval: 0,
 70     _minus: 1,
 71     init: function () {
 72         this._acceleration = new cc.Acceleration();
 73         this._deviceEvent = window.DeviceMotionEvent || window.DeviceOrientationEvent;
 74         var ua = navigator.userAgent;
 75         if (/Android/.test(ua) || (/Adr/.test(ua) && cc.Browser.type == "ucbrowser")) {
 76             this._minus = -1;
 77         }
 78 
 79         //TODO fix DeviceMotionEvent bug on QQ Browser version 4.1 and below.
 80         if (cc.Browser.type == "mqqbrowser") {
 81             this._deviceEvent = window.DeviceOrientationEvent;
 82         }
 83         return true;
 84     },
 85 
 86     getDelegate: function () {
 87         return this._delegate;
 88     },
 89 
 90     addDelegate: function (delegate) {
 91         this._delegate = delegate;
 92         var acc = this.didAccelerate.bind(this);
 93 
 94         if (this._delegate) {
 95             if (this._deviceEvent == window.DeviceMotionEvent)
 96                 window.addEventListener('devicemotion', acc, false);
 97             else
 98                 window.addEventListener('deviceorientation', acc, false);
 99         } else {
100             if (this._deviceEvent == window.DeviceMotionEvent)
101                 window.removeEventListener('devicemotion', acc);
102             else
103                 window.removeEventListener('deviceorientation', acc);
104         }
105     },
106 
107     setAccelerometerInterval: function (interval) {
108         if (this._interval !== interval) {
109             this._interval = interval;
110         }
111     },
112 
113     didAccelerate: function (eventData) {
114         if (!this._delegate) {
115             return;
116         }
117 
118         var now = Date.now();
119          if ((now - this._acceleration.timestamp) / 1000 < this._interval) return;
120 
121         if (this._deviceEvent == window.DeviceMotionEvent) {
122             var acceleration = eventData.accelerationIncludingGravity;
123             this._acceleration.x = this._minus * acceleration.x * 0.1;
124             this._acceleration.y = this._minus * acceleration.y * 0.1;
125             this._acceleration.z = acceleration.z * 0.1;
126         }
127         else {
128             this._acceleration.x = (eventData.gamma / 90) * 0.981;
129             this._acceleration.y = -(eventData.beta / 90) * 0.981;
130             this._acceleration.z = (eventData.alpha / 90) * 0.981;
131         }
132         this._acceleration.timestamp = Date.now();
133 
134         var tmp = this._acceleration.x;
135         switch (window.orientation) {
136             case cc.UIInterfaceOrientationLandscapeRight://-90
137                 this._acceleration.x = -this._acceleration.y;
138                 this._acceleration.y = tmp;
139                 break;
140 
141             case cc.UIInterfaceOrientationLandscapeLeft://90
142                 this._acceleration.x = this._acceleration.y;
143                 this._acceleration.y = -tmp;
144                 break;
145 
146             case cc.UIInterfaceOrientationPortraitUpsideDown://180
147                 this._acceleration.x = -this._acceleration.x
148                 this._acceleration.y = -this._acceleration.y;
149                 break;
150 
151             case cc.UIInterfaceOrientationPortrait://0
152                 break;
153         }
154 
155         this._delegate.onAccelerometer(this._acceleration);
156     }
157 });
158 
159 
160 cc.AccelerometerDispatcher.getInstance = function () {
161     if (!this._instance) {
162         this._instance = new cc.AccelerometerDispatcher();
163         this._instance.init();
164     }
165 
166     return this._instance;
167 };