AngularJS - Smooth Anchor Scroll

by Premchand R

HTML

<div ng-app="app">
  <div id="scrollArea" ng-controller="ScrollCtrl">

    <a ng-click="gotoElement('middle')">Go to middle</a>
    <br/>
    <a ng-click="gotoElement('bottom')">Go to bottom</a>

    <p>Keffiyeh locavore aesthetic trust fund. Fingerstache irony Truffaut gastropub, cliche chambray gentrify. PBR&B raw denim kogi, tote bag cardigan Tumblr Neutra readymade Odd Future vinyl. Small batch single-origin coffee swag selvage, Blue Bottle occupy
      try-hard. Carles tote bag meggings Cosby sweater. Yr Vice photo booth put a bird on it, slow-carb kale chips locavore. Banh mi High Life biodiesel, Tonx fanny pack plaid Terry Richardson ennui small batch.</p>

    <p>Single-origin coffee butcher next level, umami chia cornhole hashtag four loko PBR fashion axe sustainable. Church-key High Life sartorial butcher, hella +1 Intelligentsia chambray Wes Anderson Terry Richardson leggings Helvetica stumptown brunch
      gentrify. Schlitz pour-over whatever cray, bicycle rights semiotics tousled try-hard hella selvage. Banksy next level art party, swag church-key Etsy bicycle rights hella synth hoodie Williamsburg Brooklyn letterpress meh stumptown. Slow-carb lo-fi
      umami, 3 wolf moon vegan PBR banh mi pop-up. Semiotics kogi photo booth occupy next level mumblecore Banksy master cleanse, asymmetrical chia forage vinyl swag. Leggings beard shabby chic 3 wolf moon cray, farm-to-table skateboard you probably haven't
      heard of them small batch squid mlkshk +1 banjo flannel pour-over.</p>

    <p>Schlitz deep v hoodie pour-over banh mi. Helvetica yr Etsy Tumblr selvage. Tousled swag ennui Williamsburg disrupt PBR&B. VHS tattooed swag Terry Richardson, plaid bitters cred try-hard. Organic photo booth Neutra Pinterest. Banjo vinyl four loko
      Neutra photo booth trust fund hella. Freegan retro Thundercats, locavore skateboard polaroid bicycle rights.</p>

    <p>Marfa beard Echo Park, Thundercats jean shorts Truffaut Vice. Banjo roof party polaroid,...

CSS

#scrollArea {
  height: 100%;
  overflow: auto;
}

#bottom {
  display: block;
}

JavaScript

var $scope, $location;
var app = angular.module('app', []);

app.service('anchorSmoothScroll', function() {

  this.scrollTo = function(eID) {

    // This scrolling function 
    // is from http://www.itnewb.com/tutorial/Creating-the-Smooth-Scroll-Effect-with-JavaScript

    var startY = currentYPosition();
    var stopY = elmYPosition(eID);
    var distance = stopY > startY ? stopY - startY : startY - stopY;
    if (distance < 100) {
      scrollTo(0, stopY);
      return;
    }
    var speed = Math.round(distance / 100);
    if (speed >= 20) speed = 20;
    var step = Math.round(distance / 25);
    var leapY = stopY > startY ? startY + step : startY - step;
    var timer = 0;
    if (stopY > startY) {
      for (var i = startY; i < stopY; i += step) {
        setTimeout("window.scrollTo(0, " + leapY + ")", timer * speed);
        leapY += step;
        if (leapY > stopY) leapY = stopY;
        timer++;
      }
      return;
    }
    for (var i = startY; i > stopY; i -= step) {
      setTimeout("window.scrollTo(0, " + leapY + ")", timer * speed);
      leapY -= step;
      if (leapY < stopY) leapY = stopY;
      timer++;
    }

    function currentYPosition() {
      // Firefox, Chrome, Opera, Safari
      if (self.pageYOffset) return self.pageYOffset;
      // Internet Explorer 6 - standards mode
      if (document.documentElement && document.documentElement.scrollTop)
        return document.documentElement.scrollTop;
      // Internet Explorer 6, 7 and 8
      if (document.body.scrollTop) return document.body.scrollTop;
      return 0;
    }

    function elmYPosition(eID) {
      var elm = document.getElementById(eID);
      var y = elm.offsetTop;
      var node = elm;
      while (node.offsetParent && node.offsetParent != document.body) {
        node = node.offsetParent;
        y += node.offsetTop;
      }
      return y;
    }

  };

});

app.controller('ScrollCtrl', function($scope, $location, anchorSmoothScroll) {

  $scope.gotoElement =...