Angular: ng-blank

http://angularjs.org/

HTML

<title>ng-blank</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script>
<body ng-app="app" id='body'>
  <div ng-controller="MainCtrl">
    <div id="totop" ng-click="toTop()">click me</div>
  </div>
<p>Open console to see completion messages</p>
</body>

CSS

body {
  height: 10000px;
}
#totop {
  position: fixed;
  top: 10px;
  color: red;
}
p {
  position: fixed;
  top: 30px;
}

JavaScript

var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, $q) {
	$scope.toTop = function() {
		var element = angular.element(document.querySelector('#body'))[0];
		var dataAttrib = 'data-startTime';
		element.setAttribute(dataAttrib, -1); // stop signal.
		scrollTo_(0, 500).then(function() {
			console.log('scroll complete');
		}, function() {
			console.log('scroll stopped');
		});
		function scrollTo_(to, duration) {
			var startTime = null,
				startPos = element.scrollTop,
				dfrd = $q.defer();
			function step(timestamp) {
				if(element.getAttribute(dataAttrib) < 0) {
					element.setAttribute(dataAttrib, 0);
					dfrd.reject();
					return;
				}
				if (!startTime) {
					startTime = timestamp;
					element.setAttribute(dataAttrib, startTime);
				}
				var progress = timestamp - startTime;
				if (progress < duration) {
					element.scrollTop = startPos + (to - startPos) * progress / duration;
					window.requestAnimationFrame(step);
				} else {
					element.scrollTop = to; // ensure final position is accurate
					dfrd.resolve();
				}
			}
			window.requestAnimationFrame(function() {
				element.setAttribute(dataAttrib, 0);
				window.requestAnimationFrame(step);
			});
			return dfrd.promise;
		}
	};
});