1 var
  2 	WINDOW_APP = WINDOW_APP || {};
  3 
  4 WINDOW_APP.util = {};
  5 
  6 
  7 /**
  8  * スクロールの監視
  9  *
 10  * @class
 11  * @author	ngi@phantom4.org
 12  * @example
 13  *
 14  * /**
 15  *  * スクロールの監視イベント
 16  *  *
 17  *  * @param params {Object} 監視中のパラメーター
 18  *  * @param params.status {int} 0: スクロール停止した、1: スクロール開始した、2: スクロール中、-1: スクロールしていない
 19  *  * @param params.positionX {Number} 縦スクロールの位置
 20  *  * @param params.positionY {Number} 横スクロールの位置
 21  *  * @param params.deltaX {Number} 縦スクロールの移動量
 22  *  * @param params.deltaY {Number} 横スクロールの移動量
 23  *  *\/
 24  * function onScroll (params) {
 25  * 	switch(params.status) {
 26  * 		case 0:
 27  * 			//スクロール停止したときの処理
 28  * 			break;
 29  *
 30  * 		case 1:
 31  * 			//スクロール開始したときの処理
 32  * 			break;
 33  *
 34  * 		case 2:
 35  * 			//スクロール中の処理
 36  * 			break;
 37  * 	}
 38  * }
 39  *
 40  * WINDOW_APP.util.scrollMonitor.add(onScroll);	//リスナー追加
 41  */
 42 
 43 
 44 WINDOW_APP.util.scrollMonitor = (function () {
 45 	var
 46 		_DELAY = 100,
 47 
 48 		_isPlaying = false,	//動作中か
 49 		_listeners = [],	//リスナー
 50 		_numListener = 0,	//追加された要素の数
 51 		_timer,	//タイマー
 52 		_isScrolling = false,	//スクロール中か
 53 		_prevPoint = {
 54 			x: 0,
 55 			y: 0
 56 		};	//前回のスクロール座標
 57 
 58 	/**
 59 	 * イベントを追加する
 60 	 *
 61 	 * @param	func {Function} リスナー
 62 	 * @return	{Boolean} 追加されたか
 63 	 */
 64 	function add (func) {
 65 		var
 66 			result = false,	//結果
 67 			isAdded = false;	//すでに追加されているか
 68 
 69 		if(typeof func === "function") {
 70 			//同じものがあれば上書き
 71 			for(var i = 0; i < _numListener; i++) {
 72 				if(_listeners[i] === func) {
 73 					_listeners[i] = func;
 74 					isAdded = true;
 75 					break;
 76 				}
 77 			}
 78 
 79 			if(!isAdded) {
 80 				_listeners.push(func);
 81 				_numListener++;
 82 			}
 83 		}
 84 
 85 		//動作開始
 86 		if(!_isPlaying && _numListener > 0) {
 87 			start();
 88 		}
 89 
 90 		return result;
 91 	}
 92 
 93 	/**
 94 	 * イベントを削除する
 95 	 *
 96 	 * @param	func {Function} リスナー
 97 	 * @return	{Boolean} 削除されたか
 98 	 */
 99 	function remove (func) {
100 		var result = false;
101 		for(var i = 0; i < _numListener; i++) {
102 			//一致したリスナーを削除
103 			if(_listeners[i] === func) {
104 				delete _listeners[i];
105 				_numListener--;
106 				break;
107 			}
108 		}
109 
110 		//動作終了
111 		if(_numListener <= 0) {
112 			stop();
113 		}
114 
115 		return result;
116 	}
117 
118 	/**
119 	 * モニターの開始(手動で実行する場合)
120 	 *
121 	 */
122 	function start () {
123 		stop();
124 		_timer = setInterval(_monitor, _DELAY);
125 		_isPlaying = true;
126 	}
127 
128 	/**
129 	 * モニターの停止(手動で実行する場合)
130 	 *
131 	 */
132 	function stop () {
133 		if(_timer) {
134 			clearInterval(_timer);
135 		}
136 		_isPlaying = false;
137 	}
138 
139 	/**
140 	 * 監視&通知
141 	 *
142 	 */
143 	function _monitor () {
144 		var
145 			top = document.documentElement.scrollTop || document.body.scrollTop,	//スクロール上
146 			left = document.documentElement.scrollLeft || document.body.scrollLeft,	//スクロール左
147 			isMove = false,	//移動したか
148 			status = -1;	//スクロール開始、停止、スクロール中
149 
150 		if(_prevPoint.x != left) {
151 			isMove = true;
152 		}
153 
154 		if(_prevPoint.y != top) {
155 			isMove = true;
156 		}
157 
158 		//ステータスの設定
159 		if(isMove && _isScrolling) {
160 			status = 2;	//スクロール中
161 		}
162 		else if (isMove && !_isScrolling) {
163 			status = 1;	//スクロール開始
164 		}
165 		else if (!isMove && _isScrolling) {
166 			status = 0;	//スクロール停止
167 		}
168 
169 		//通知
170 		for(var i = 0; i < _numListener; i++) {
171 			_listeners[i].apply(window, [{
172 				status: status,
173 				positionX: left,	//x座標
174 				positionY: top,	//y座標
175 				deltaX: left - _prevPoint.x,	//x座標の移動量
176 				deltaY: top - _prevPoint.y	//y座標の移動量
177 			}]);
178 		}
179 
180 		_isScrolling = isMove;
181 		_prevPoint.x = left;
182 		_prevPoint.y = top;
183 	}
184 
185 
186 	return {
187 		add: add,
188 		remove: remove,
189 		start: start,
190 		stop: stop
191 	};
192 }());