AnimationFrameLoop

create a loop runner using requestAnimationFrame, with stop, start, toggle, fps/delay.

by Laurens Maneschijn

JavaScript

(function(window) {
	function AnimationFrameLoop() {
		var that = this;
		var _private = {
			run: false,
			requestanimationframe_id: null,
			framecount: 0,
			timestamp_last_frame: null,
			delay: 0,
		}

		function tick() {
			if (!_private.run) {
				return;
			}
			var timestamp_now = getTimestamp();
			if (_private.delay && _private.timestamp_last_frame !== null) {
				if (_private.timestamp_last_frame + _private.delay > timestamp_now) {
					cancelAnimationFrame(_private.requestanimationframe_id);
					_private.requestanimationframe_id = requestAnimationFrame(tick);
					return;
				}
			}
			_private.timestamp_last_frame = timestamp_now;
			_private.framecount++;
			if (typeof that.tick === 'function') {
				that.tick();
			}
			cancelAnimationFrame(_private.requestanimationframe_id);
			_private.requestanimationframe_id = requestAnimationFrame(tick);
		}

		function stop() {
			_private.run = false;
			cancelAnimationFrame(_private.requestanimationframe_id);
			_private.requestanimationframe_id = null;
		}

		function start() {
			if (_private.run) {
				return;
			}
			_private.run = true;
			tick();
		}

		function restart() {
			stop();
			_private.run = true;
			tick();
		}

		function toggle() {
			_private.run ?
				stop() :
				start();
		}

		function getFrameCount() {
			return _private.framecount;
		}

		function resetFrameCount() {
			_private.framecount = 0;
		}

		function setFrameCount(framecount) {
			if (typeof framecount !== 'number') {
				throw new Error('AnimationFrameLoop setFrameCount() given framecount not a number.');
			}
			_private.framecount = Math.max(0, Math.floor(framecount));
		}

		function getTimestamp() {
			if (typeof Date.now === 'function') {
				return Date.now();
			}
			return new Date().getTime();
		}

		function setDelay(delay) {
			if (typeof delay !== 'number') {
				throw new Error('AnimationFrameLoop setDelay() given delay not a number.');
			}
			if (delay < 0) {
				throw new Error('AnimationFrameLoop...