<!DOCTYPE html>
<html ng-app="app">

<head>
  <script data-require="angularjs@1.5.3" data-semver="1.5.3" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
  <script src="https://rawgit.com/klumba12/vscroll/master/vscroll.js"></script>
  <style>
    table {
      border-spacing: 1;
    }
    
    table td {
      padding: 0;
    }
  </style>
</head>

<body ng-controller="vscrollTable">
  <div vscroll style="height: 400px; width: 100%; overflow: auto;">
    <table vscroll-port-x="columnContext" vscroll-port-y="rowContext">
      <tbody>
        <tr vscroll-mark="top">
        </tr>
        <tr vscroll-row="{{::$index}}" ng-repeat="row in data | vscroll: rowContext track by $index">
          <td vscroll-column="{{::$index}}" ng-repeat="color in row | vscroll: columnContext track by $index">
            <div ng-style="{'background-color': '#' + data[rowContext.container.position+$parent.$index][columnContext.container.position+$index]}" style="width: 15px; height: 15px; ">
            </div>
          </td>
        </tr>
        <tr vscroll-mark="bottom">
        </tr>
      </tbody>
    </table>
  </div>

  <script language="javascript">
    var app = angular.module('app', ['vscroll']);
    app.controller('vscrollTable', ['$scope', 'vscroll', function($scope, vscroll) {
      var rows = 0,
        columns = 0;

      $scope.data = [];
      $scope.rowContext = vscroll({
        threshold: 25,
        fetch: function(skip, take, d) {
          for (var i = skip; i < skip + take; i++) {
            var row = $scope.data[i] = [];
            for (var j = 0; j < columns; j++) {
              row[j] = Math.floor(Math.random() * 16777215).toString(16);
            }
          }

          rows += take;
          d.resolve(rows + take);
        }
      });

      $scope.rowContext.container.apply = function(f, emit) {
        f();
        if ($scope.rowContext.container.cursor !== $scope.rowContext.container.position) {
          $scope.$digest();
        }
      };

      $scope.columnContext = vscroll({
        threshold: 30,
        fetch: function(skip, take, d) {
          for (var j = 0; j < rows; j++) {
            var row = $scope.data[j];
            for (var i = skip; i < skip + take; i++) {
              row[i] = Math.floor(Math.random() * 16777215).toString(16);
            }
          }

          columns += take;
          d.resolve(columns + take);
        }
      });

      $scope.columnContext.container.apply = function(f, emit) {
        f();
        if ($scope.columnContext.container.cursor !== $scope.columnContext.container.position) {
          $scope.$digest();
        }
      };

    }]);
  </script>

</body>

</html>