Skip to content

Commit

Permalink
Add support for debouncing $digest calls
Browse files Browse the repository at this point in the history
  • Loading branch information
widmoser committed May 11, 2016
1 parent c838374 commit feaee70
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 51 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,9 @@ The row, counted from the end, that triggers the `scrollEnd` expression.
Type: `number`. Default: `2`

The number of excess rows that are added to the DOM.

#### debounce

Type: `number`. Default: `0`

The debounce in milliseconds. This will only affect the calls to `$digest`. The cells will still be moved smoothly. A value of `0` is interpreted as no debounce.
4 changes: 4 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
<label for="horizontal">Align Horizontal:</label>
<input id="horizontal" class="form-control" type="checkbox" ng-model="options.alignHorizontal">
</fieldset>
<fieldset class="form-group">
<label for="debounce">Debounce:</label>
<input id="debounce" class="form-control" type="number" ng-model="options.debounce">
</fieldset>
<button type="button" class="btn btn-default" ng-click="fixSize()">Fix size</button>
<button type="button" class="btn btn-default" ng-click="changeData()">Change Data</button>
<button type="button" class="btn btn-default" ng-click="insert()">Insert</button>
Expand Down
62 changes: 34 additions & 28 deletions dist/tileview.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@
* - **scrollEndOffset** - {number} - Some features that rely on the `scrollEnd` callback need to be informed in advance.
* This property specifies an offset in rows to trigger the scroll end event before actually hitting the bottom of the data. **Default**: 0
* - **overflow** - {number} - Number of rows that are rendered additionally to the visible rows to make the scrolling experience more fluent. **Default**: 2
* - **debounce** - {number} - Debounce in milliseconds. This will only affect the calls to `$digest`. The cells will still be moved smoothly. A value of `0` is interpreted as no debounce. **Default**: 0.
*/
mod.directive('tdTileview', ['$compile', '$templateCache', '$window', function ($compile, $templateCache, $window) {
mod.directive('tdTileview', ['$compile', '$templateCache', '$timeout', '$window', function ($compile, $templateCache, $timeout, $window) {
return {
restrict: 'E',
scope: {
Expand Down Expand Up @@ -60,6 +61,7 @@
scope.$watch('options', function (options) {
options.scrollEndOffset = def(options.scrollEndOffset, 0);
options.overflow = def(options.overflow, 2);
options.debounce = def(options.debounce, 0);
});
scope.$watchGroup(['options.tileSize.width', 'options.tileSize.height'], function (_a) {
var width = _a[0], height = _a[1];
Expand Down Expand Up @@ -224,42 +226,46 @@
setPlaceholder();
}
}
function forEachItem(startIndex, endIndex, fn) {
var fromRight = startIndex > endIndex;
var incr = fromRight ? -1 : 1;
var j = fromRight ? -1 : 0;
for (var i = startIndex; i < endIndex; i += incr) {
fn(scope.items[i], j);
}
function updateAll() {
forEachElement(function (el, i) { return updateItem(el, scope.items[startRow * itemsPerRow + i], true); });
}
var debounceTimeout;
function onScroll() {
var oldStartRow = startRow;
var oldEndRow = endRow;
updateVisibleRows();
if (startRow > oldEndRow || endRow < oldStartRow) {
forEachElement(function (el, i) { return updateItem(el, scope.items[startRow * itemsPerRow + i], true); });
if (scope.options.debounce !== undefined && scope.options.debounce > 0) {
if (debounceTimeout) {
$timeout.cancel(debounceTimeout);
}
debounceTimeout = $timeout(updateAll, scope.options.debounce);
}
else {
var intersectionStart = Math.max(startRow, oldStartRow);
var intersectionEnd = Math.min(endRow, oldEndRow);
if (endRow > intersectionEnd) {
var j = 0;
for (var i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
updateItem(itemContainer.children().eq(j++), scope.items[i], true);
}
for (var i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
var itemElement = itemContainer.children().eq(0).detach();
itemContainer.append(itemElement);
}
if (startRow > oldEndRow || endRow < oldStartRow) {
updateAll();
}
else if (startRow < intersectionStart) {
var j = -1;
for (var i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
updateItem(itemContainer.children().eq(j--), scope.items[i], true);
else {
var intersectionStart = Math.max(startRow, oldStartRow);
var intersectionEnd = Math.min(endRow, oldEndRow);
if (endRow > intersectionEnd) {
var j = 0;
for (var i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
updateItem(itemContainer.children().eq(j++), scope.items[i], true);
}
for (var i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
var itemElement = itemContainer.children().eq(0).detach();
itemContainer.append(itemElement);
}
}
for (var i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
var itemElement = itemContainer.children().eq(-1).detach();
itemContainer.prepend(itemElement);
else if (startRow < intersectionStart) {
var j = -1;
for (var i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
updateItem(itemContainer.children().eq(j--), scope.items[i], true);
}
for (var i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
var itemElement = itemContainer.children().eq(-1).detach();
itemContainer.prepend(itemElement);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "angular-tileview",
"version": "0.3.3",
"version": "0.5.0",
"description": "A tileview for angular",
"main": "gulpfile.js",
"scripts": {
Expand Down
58 changes: 36 additions & 22 deletions src/tileview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ declare const angular: any;
* - **scrollEndOffset** - {number} - Some features that rely on the `scrollEnd` callback need to be informed in advance.
* This property specifies an offset in rows to trigger the scroll end event before actually hitting the bottom of the data. **Default**: 0
* - **overflow** - {number} - Number of rows that are rendered additionally to the visible rows to make the scrolling experience more fluent. **Default**: 2
* - **debounce** - {number} - Debounce in milliseconds. This will only affect the calls to `$digest`. The cells will still be moved smoothly. A value of `0` is interpreted as no debounce. **Default**: 0.
*/
mod.directive('tdTileview', ['$compile', '$templateCache', '$window', ($compile, $templateCache, $window) => {
mod.directive('tdTileview', ['$compile', '$templateCache', '$timeout', '$window', ($compile, $templateCache, $timeout, $window) => {
return {
restrict: 'E',
scope: {
Expand Down Expand Up @@ -72,6 +73,7 @@ declare const angular: any;
scope.$watch('options', options => {
options.scrollEndOffset = def(options.scrollEndOffset, 0);
options.overflow = def(options.overflow, 2);
options.debounce = def(options.debounce, 0);
});
scope.$watchGroup(['options.tileSize.width', 'options.tileSize.height'], ([width, height]) => {
layout();
Expand Down Expand Up @@ -256,37 +258,49 @@ declare const angular: any;
setPlaceholder();
}
}

function updateAll() {
forEachElement((el, i) => updateItem(el, scope.items[startRow * itemsPerRow + i], true));
}

let debounceTimeout;
function onScroll() {

const oldStartRow = startRow;
const oldEndRow = endRow;

updateVisibleRows();

if (startRow > oldEndRow || endRow < oldStartRow) {
forEachElement((el, i) => updateItem(el, scope.items[startRow * itemsPerRow + i], true));
if (scope.options.debounce !== undefined && scope.options.debounce > 0) {
if (debounceTimeout) {
$timeout.cancel(debounceTimeout);
}
debounceTimeout = $timeout(updateAll, scope.options.debounce);
} else {
const intersectionStart = Math.max(startRow, oldStartRow);
const intersectionEnd = Math.min(endRow, oldEndRow);
if (startRow > oldEndRow || endRow < oldStartRow) {
updateAll();
} else {
const intersectionStart = Math.max(startRow, oldStartRow);
const intersectionEnd = Math.min(endRow, oldEndRow);

if (endRow > intersectionEnd) {
let j = 0;
for (let i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
updateItem(itemContainer.children().eq(j++), scope.items[i], true);
}
for (let i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
const itemElement = itemContainer.children().eq(0).detach();
itemContainer.append(itemElement);
}
} else if (startRow < intersectionStart) {
let j = -1;
for (let i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
updateItem(itemContainer.children().eq(j--), scope.items[i], true);
}
for (let i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
const itemElement = itemContainer.children().eq(-1).detach();
itemContainer.prepend(itemElement);
if (endRow > intersectionEnd) {
let j = 0;
for (let i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
updateItem(itemContainer.children().eq(j++), scope.items[i], true);
}
for (let i = intersectionEnd * itemsPerRow; i < endRow * itemsPerRow; ++i) {
const itemElement = itemContainer.children().eq(0).detach();
itemContainer.append(itemElement);
}
} else if (startRow < intersectionStart) {
let j = -1;
for (let i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
updateItem(itemContainer.children().eq(j--), scope.items[i], true);
}
for (let i = intersectionStart * itemsPerRow - 1; i >= startRow * itemsPerRow; --i) {
const itemElement = itemContainer.children().eq(-1).detach();
itemContainer.prepend(itemElement);
}
}
}
}
Expand Down

0 comments on commit feaee70

Please sign in to comment.