diff --git a/README.md b/README.md index 8c27522..14fa089 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file diff --git a/demo/index.html b/demo/index.html index 6345013..d4496e5 100644 --- a/demo/index.html +++ b/demo/index.html @@ -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> diff --git a/dist/tileview.js b/dist/tileview.js index b296bf0..b5dc2c9 100644 --- a/dist/tileview.js +++ b/dist/tileview.js @@ -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: { @@ -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]; @@ -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); + } } } } diff --git a/package.json b/package.json index cf7b0e4..5039111 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-tileview", - "version": "0.3.3", + "version": "0.5.0", "description": "A tileview for angular", "main": "gulpfile.js", "scripts": { diff --git a/src/tileview.ts b/src/tileview.ts index 956741b..8f49f59 100644 --- a/src/tileview.ts +++ b/src/tileview.ts @@ -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: { @@ -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(); @@ -256,7 +258,12 @@ 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; @@ -264,29 +271,36 @@ declare const angular: any; 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); + } } } }