ng-virtual-list 17.0.13 → 17.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/ng-virtual-list-item.component.mjs +4 -4
- package/esm2022/lib/ng-virtual-list.component.mjs +12 -29
- package/esm2022/lib/utils/cacheMap.mjs +32 -8
- package/esm2022/lib/utils/trackBox.mjs +118 -52
- package/fesm2022/ng-virtual-list.mjs +162 -89
- package/fesm2022/ng-virtual-list.mjs.map +1 -1
- package/lib/components/ng-virtual-list-item.component.d.ts +3 -3
- package/lib/ng-virtual-list.component.d.ts +3 -3
- package/lib/utils/cacheMap.d.ts +16 -9
- package/lib/utils/trackBox.d.ts +32 -15
- package/package.json +1 -1
|
@@ -59,7 +59,7 @@ const CLASS_LIST_HORIZONTAL = 'horizontal';
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Virtual list item component
|
|
62
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/
|
|
62
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/19.x/projects/ng-virtual-list/src/lib/components/ng-virtual-list-item.component.ts
|
|
63
63
|
* @author Evgenii Grebennikov
|
|
64
64
|
* @email djonnyx@gmail.com
|
|
65
65
|
*/
|
|
@@ -113,8 +113,8 @@ class NgVirtualListItemComponent {
|
|
|
113
113
|
? 0 : NgVirtualListItemComponent.__nextId + 1;
|
|
114
114
|
}
|
|
115
115
|
getBounds() {
|
|
116
|
-
const el = this._elementRef.nativeElement, { width, height
|
|
117
|
-
return { width, height
|
|
116
|
+
const el = this._elementRef.nativeElement, { width, height } = el.getBoundingClientRect();
|
|
117
|
+
return { width, height };
|
|
118
118
|
}
|
|
119
119
|
show() {
|
|
120
120
|
const styles = this._elementRef.nativeElement.style;
|
|
@@ -398,17 +398,44 @@ class EventEmitter {
|
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
+
class CMap {
|
|
402
|
+
_dict = {};
|
|
403
|
+
constructor(dict) {
|
|
404
|
+
if (dict) {
|
|
405
|
+
this._dict = { ...dict._dict };
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
get(key) {
|
|
409
|
+
const k = String(key);
|
|
410
|
+
return this._dict[k];
|
|
411
|
+
}
|
|
412
|
+
set(key, value) {
|
|
413
|
+
const k = String(key);
|
|
414
|
+
this._dict[k] = value;
|
|
415
|
+
return this;
|
|
416
|
+
}
|
|
417
|
+
has(key) {
|
|
418
|
+
return this._dict.hasOwnProperty(String(key));
|
|
419
|
+
}
|
|
420
|
+
delete(key) {
|
|
421
|
+
const k = String(key);
|
|
422
|
+
delete this._dict[k];
|
|
423
|
+
}
|
|
424
|
+
clear() {
|
|
425
|
+
this._dict = {};
|
|
426
|
+
}
|
|
427
|
+
}
|
|
401
428
|
const MAX_SCROLL_DIRECTION_POOL = 50, CLEAR_SCROLL_DIRECTION_TO = 10;
|
|
402
429
|
/**
|
|
403
430
|
* Cache map.
|
|
404
431
|
* Emits a change event on each mutation.
|
|
405
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/
|
|
432
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/19.x/projects/ng-virtual-list/src/lib/utils/cacheMap.ts
|
|
406
433
|
* @author Evgenii Grebennikov
|
|
407
434
|
* @email djonnyx@gmail.com
|
|
408
435
|
*/
|
|
409
436
|
class CacheMap extends EventEmitter {
|
|
410
|
-
_map = new
|
|
411
|
-
_snapshot = new
|
|
437
|
+
_map = new CMap();
|
|
438
|
+
_snapshot = new CMap();
|
|
412
439
|
_version = 0;
|
|
413
440
|
_delta = 0;
|
|
414
441
|
get delta() {
|
|
@@ -492,11 +519,8 @@ class CacheMap extends EventEmitter {
|
|
|
492
519
|
get(id) {
|
|
493
520
|
return this._map.get(id);
|
|
494
521
|
}
|
|
495
|
-
forEach(callbackfn, thisArg) {
|
|
496
|
-
return this._map.forEach(callbackfn, thisArg);
|
|
497
|
-
}
|
|
498
522
|
snapshot() {
|
|
499
|
-
this._snapshot = new
|
|
523
|
+
this._snapshot = new CMap(this._map);
|
|
500
524
|
}
|
|
501
525
|
dispose() {
|
|
502
526
|
super.dispose();
|
|
@@ -515,7 +539,7 @@ var ItemDisplayMethods;
|
|
|
515
539
|
})(ItemDisplayMethods || (ItemDisplayMethods = {}));
|
|
516
540
|
/**
|
|
517
541
|
* An object that performs tracking, calculations and caching.
|
|
518
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/
|
|
542
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/19.x/projects/ng-virtual-list/src/lib/utils/trackBox.ts
|
|
519
543
|
* @author Evgenii Grebennikov
|
|
520
544
|
* @email djonnyx@gmail.com
|
|
521
545
|
*/
|
|
@@ -561,10 +585,16 @@ class TrackBox extends CacheMap {
|
|
|
561
585
|
this.dispatch(TRACK_BOX_CHANGE_EVENT_NAME, version);
|
|
562
586
|
};
|
|
563
587
|
_previousCollection;
|
|
588
|
+
_deletedItemsMap = {};
|
|
589
|
+
_crudDetected = false;
|
|
590
|
+
get crudDetected() { return this._crudDetected; }
|
|
564
591
|
_debounceChanges = debounce(this._fireChanges, 0);
|
|
565
592
|
fireChange() {
|
|
566
593
|
this._debounceChanges.execute(this._version);
|
|
567
594
|
}
|
|
595
|
+
_previousTotalSize = 0;
|
|
596
|
+
_scrollDelta = 0;
|
|
597
|
+
get scrollDelta() { return this._scrollDelta; }
|
|
568
598
|
/**
|
|
569
599
|
* Scans the collection for deleted items and flushes the deleted item cache.
|
|
570
600
|
*/
|
|
@@ -580,11 +610,13 @@ class TrackBox extends CacheMap {
|
|
|
580
610
|
* Update the cache of items from the list
|
|
581
611
|
*/
|
|
582
612
|
updateCache(previousCollection, currentCollection, itemSize) {
|
|
613
|
+
let crudDetected = false;
|
|
583
614
|
if (!currentCollection || currentCollection.length === 0) {
|
|
584
615
|
if (previousCollection) {
|
|
585
616
|
// deleted
|
|
586
617
|
for (let i = 0, l = previousCollection.length; i < l; i++) {
|
|
587
618
|
const item = previousCollection[i], id = item.id;
|
|
619
|
+
crudDetected = true;
|
|
588
620
|
if (this._map.has(id)) {
|
|
589
621
|
this._map.delete(id);
|
|
590
622
|
}
|
|
@@ -596,8 +628,9 @@ class TrackBox extends CacheMap {
|
|
|
596
628
|
if (currentCollection) {
|
|
597
629
|
// added
|
|
598
630
|
for (let i = 0, l = currentCollection.length; i < l; i++) {
|
|
631
|
+
crudDetected = true;
|
|
599
632
|
const item = currentCollection[i], id = item.id;
|
|
600
|
-
this._map.set(id, {
|
|
633
|
+
this._map.set(id, { width: itemSize, height: itemSize, method: ItemDisplayMethods.CREATE });
|
|
601
634
|
}
|
|
602
635
|
}
|
|
603
636
|
return;
|
|
@@ -609,7 +642,7 @@ class TrackBox extends CacheMap {
|
|
|
609
642
|
collectionDict[item.id] = item;
|
|
610
643
|
}
|
|
611
644
|
}
|
|
612
|
-
const notChangedMap = {}, deletedMap = {}, updatedMap = {};
|
|
645
|
+
const notChangedMap = {}, deletedMap = {}, deletedItemsMap = {}, updatedMap = {};
|
|
613
646
|
for (let i = 0, l = previousCollection.length; i < l; i++) {
|
|
614
647
|
const item = previousCollection[i], id = item.id;
|
|
615
648
|
if (item) {
|
|
@@ -617,18 +650,21 @@ class TrackBox extends CacheMap {
|
|
|
617
650
|
if (item === collectionDict[id]) {
|
|
618
651
|
// not changed
|
|
619
652
|
notChangedMap[item.id] = item;
|
|
620
|
-
this._map.set(id, { ...(this._map.get(id) || {
|
|
653
|
+
this._map.set(id, { ...(this._map.get(id) || { width: itemSize, height: itemSize }), method: ItemDisplayMethods.NOT_CHANGED });
|
|
621
654
|
continue;
|
|
622
655
|
}
|
|
623
656
|
else {
|
|
624
657
|
// updated
|
|
658
|
+
crudDetected = true;
|
|
625
659
|
updatedMap[item.id] = item;
|
|
626
|
-
this._map.set(id, { ...(this._map.get(id) || {
|
|
660
|
+
this._map.set(id, { ...(this._map.get(id) || { width: itemSize, height: itemSize }), method: ItemDisplayMethods.UPDATE });
|
|
627
661
|
continue;
|
|
628
662
|
}
|
|
629
663
|
}
|
|
630
664
|
// deleted
|
|
665
|
+
crudDetected = true;
|
|
631
666
|
deletedMap[item.id] = item;
|
|
667
|
+
deletedItemsMap[i] = this._map.get(item.id);
|
|
632
668
|
this._map.delete(id);
|
|
633
669
|
}
|
|
634
670
|
}
|
|
@@ -636,32 +672,51 @@ class TrackBox extends CacheMap {
|
|
|
636
672
|
const item = currentCollection[i], id = item.id;
|
|
637
673
|
if (item && !deletedMap.hasOwnProperty(id) && !updatedMap.hasOwnProperty(id) && !notChangedMap.hasOwnProperty(id)) {
|
|
638
674
|
// added
|
|
639
|
-
|
|
675
|
+
crudDetected = true;
|
|
676
|
+
this._map.set(id, { width: itemSize, height: itemSize, method: ItemDisplayMethods.CREATE });
|
|
640
677
|
}
|
|
641
678
|
}
|
|
679
|
+
this._crudDetected = crudDetected;
|
|
680
|
+
this._deletedItemsMap = deletedItemsMap;
|
|
642
681
|
}
|
|
643
682
|
/**
|
|
644
683
|
* Finds the position of a collection element by the given Id
|
|
645
684
|
*/
|
|
646
685
|
getItemPosition(id, stickyMap, options) {
|
|
647
686
|
const opt = { fromItemId: id, stickyMap, ...options };
|
|
648
|
-
const { scrollSize } = this.recalculateMetrics(
|
|
687
|
+
const { scrollSize } = this.recalculateMetrics({
|
|
688
|
+
...opt,
|
|
689
|
+
dynamicSize: this._crudDetected || opt.dynamicSize,
|
|
690
|
+
previousTotalSize: this._previousTotalSize,
|
|
691
|
+
crudDetected: this._crudDetected,
|
|
692
|
+
deletedItemsMap: this._deletedItemsMap,
|
|
693
|
+
});
|
|
649
694
|
return scrollSize;
|
|
650
695
|
}
|
|
651
696
|
/**
|
|
652
697
|
* Updates the collection of display objects
|
|
653
698
|
*/
|
|
654
699
|
updateCollection(items, stickyMap, options) {
|
|
655
|
-
const opt = { stickyMap, ...options };
|
|
656
|
-
|
|
700
|
+
const opt = { stickyMap, ...options }, crudDetected = this._crudDetected, deletedItemsMap = this._deletedItemsMap;
|
|
701
|
+
if (opt.dynamicSize) {
|
|
702
|
+
this.cacheElements();
|
|
703
|
+
}
|
|
657
704
|
const metrics = this.recalculateMetrics({
|
|
658
705
|
...opt,
|
|
659
706
|
collection: items,
|
|
707
|
+
previousTotalSize: this._previousTotalSize,
|
|
708
|
+
crudDetected: this._crudDetected,
|
|
709
|
+
deletedItemsMap,
|
|
660
710
|
});
|
|
661
711
|
this._delta += metrics.delta;
|
|
662
|
-
this.
|
|
663
|
-
|
|
664
|
-
|
|
712
|
+
this._previousTotalSize = metrics.totalSize;
|
|
713
|
+
this._deletedItemsMap = {};
|
|
714
|
+
this._crudDetected = false;
|
|
715
|
+
if (opt.dynamicSize) {
|
|
716
|
+
this.snapshot();
|
|
717
|
+
}
|
|
718
|
+
const displayItems = this.generateDisplayCollection(items, stickyMap, { ...metrics, });
|
|
719
|
+
return { displayItems, totalSize: metrics.totalSize, delta: metrics.delta, crudDetected };
|
|
665
720
|
}
|
|
666
721
|
/**
|
|
667
722
|
* Finds the closest element in the collection by scrollSize
|
|
@@ -720,7 +775,7 @@ class TrackBox extends CacheMap {
|
|
|
720
775
|
* Calculates list metrics
|
|
721
776
|
*/
|
|
722
777
|
recalculateMetrics(options) {
|
|
723
|
-
const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, itemsOffset, scrollSize, snap, stickyMap, enabledBufferOptimization } = options;
|
|
778
|
+
const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, itemsOffset, scrollSize, snap, stickyMap, enabledBufferOptimization, previousTotalSize, crudDetected, deletedItemsMap } = options;
|
|
724
779
|
const { width, height } = bounds, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME, size = isVertical ? height : width, totalLength = collection.length, typicalItemSize = itemSize, w = isVertical ? width : typicalItemSize, h = isVertical ? typicalItemSize : height, map = this._map, snapshot = this._snapshot, checkOverscrollItemsLimit = Math.ceil(size / typicalItemSize), snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
|
|
725
780
|
|| (typeof fromItemId === 'string' && fromItemId > '-1');
|
|
726
781
|
let leftItemsOffset = 0, rightItemsOffset = 0;
|
|
@@ -745,32 +800,36 @@ class TrackBox extends CacheMap {
|
|
|
745
800
|
else {
|
|
746
801
|
leftItemsOffset = rightItemsOffset = itemsOffset;
|
|
747
802
|
}
|
|
748
|
-
let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0,
|
|
803
|
+
let itemsFromStartToScrollEnd = -1, itemsFromDisplayEndToOffsetEnd = 0, itemsFromStartToDisplayEnd = -1, leftItemLength = 0, rightItemLength = 0, leftItemsWeight = 0, rightItemsWeight = 0, leftHiddenItemsWeight = 0, totalItemsToDisplayEndWeight = 0, leftSizeOfAddedItems = 0, leftSizeOfUpdatedItems = 0, leftSizeOfDeletedItems = 0, itemById = undefined, itemByIdPos = 0, targetDisplayItemIndex = -1, isTargetInOverscroll = false, actualScrollSize = itemByIdPos, totalSize = 0, startIndex;
|
|
749
804
|
// If the list is dynamic or there are new elements in the collection, then it switches to the long algorithm.
|
|
750
805
|
if (dynamicSize) {
|
|
751
|
-
let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0
|
|
806
|
+
let y = 0, stickyCollectionItem = undefined, stickyComponentSize = 0;
|
|
752
807
|
for (let i = 0, l = collection.length; i < l; i++) {
|
|
753
808
|
const ii = i + 1, collectionItem = collection[i], id = collectionItem.id;
|
|
754
809
|
let componentSize = 0, componentSizeDelta = 0, itemDisplayMethod = ItemDisplayMethods.NOT_CHANGED;
|
|
755
810
|
if (map.has(id)) {
|
|
756
|
-
const bounds = map.get(id) || {
|
|
811
|
+
const bounds = map.get(id) || { width: typicalItemSize, height: typicalItemSize };
|
|
757
812
|
componentSize = bounds[sizeProperty];
|
|
758
813
|
itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
814
|
+
switch (itemDisplayMethod) {
|
|
815
|
+
case ItemDisplayMethods.UPDATE: {
|
|
816
|
+
const snapshotBounds = snapshot.get(id);
|
|
817
|
+
const componentSnapshotSize = componentSize - (snapshotBounds ? snapshotBounds[sizeProperty] : typicalItemSize);
|
|
818
|
+
componentSizeDelta = componentSnapshotSize;
|
|
819
|
+
map.set(id, { ...bounds, method: ItemDisplayMethods.NOT_CHANGED });
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
case ItemDisplayMethods.CREATE: {
|
|
823
|
+
componentSizeDelta = typicalItemSize;
|
|
824
|
+
map.set(id, { ...bounds, method: ItemDisplayMethods.NOT_CHANGED });
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
768
827
|
}
|
|
769
828
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
if (
|
|
773
|
-
|
|
829
|
+
if (this._deletedItemsMap.hasOwnProperty(i)) {
|
|
830
|
+
const bounds = this._deletedItemsMap[i], size = bounds[sizeProperty] ?? typicalItemSize;
|
|
831
|
+
if (y < scrollSize - size) {
|
|
832
|
+
leftSizeOfDeletedItems += size;
|
|
774
833
|
}
|
|
775
834
|
}
|
|
776
835
|
totalSize += componentSize;
|
|
@@ -779,7 +838,6 @@ class TrackBox extends CacheMap {
|
|
|
779
838
|
if (id !== fromItemId && stickyMap && stickyMap[id] > 0) {
|
|
780
839
|
stickyComponentSize = componentSize;
|
|
781
840
|
stickyCollectionItem = collectionItem;
|
|
782
|
-
stickyComponentIndex = i;
|
|
783
841
|
}
|
|
784
842
|
if (id === fromItemId) {
|
|
785
843
|
targetDisplayItemIndex = i;
|
|
@@ -822,22 +880,25 @@ class TrackBox extends CacheMap {
|
|
|
822
880
|
totalItemsToDisplayEndWeight += componentSize;
|
|
823
881
|
itemsFromDisplayEndToOffsetEnd = itemsFromStartToDisplayEnd + rightItemsOffset;
|
|
824
882
|
}
|
|
825
|
-
if (y > itemByIdPos + size + componentSize) {
|
|
826
|
-
if (itemDisplayMethod === ItemDisplayMethods.UPDATE) {
|
|
827
|
-
rightSizeOfAddedItems += componentSizeDelta;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
883
|
}
|
|
831
884
|
else if (y < scrollSize + size + componentSize) {
|
|
832
885
|
itemsFromStartToDisplayEnd = ii;
|
|
833
886
|
totalItemsToDisplayEndWeight += componentSize;
|
|
834
887
|
itemsFromDisplayEndToOffsetEnd = itemsFromStartToDisplayEnd + rightItemsOffset;
|
|
835
888
|
if (y < scrollSize - componentSize) {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
889
|
+
switch (itemDisplayMethod) {
|
|
890
|
+
case ItemDisplayMethods.CREATE: {
|
|
891
|
+
leftSizeOfAddedItems += componentSizeDelta;
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
case ItemDisplayMethods.UPDATE: {
|
|
895
|
+
leftSizeOfUpdatedItems += componentSizeDelta;
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
case ItemDisplayMethods.DELETE: {
|
|
899
|
+
leftSizeOfDeletedItems += componentSizeDelta;
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
841
902
|
}
|
|
842
903
|
}
|
|
843
904
|
}
|
|
@@ -845,12 +906,6 @@ class TrackBox extends CacheMap {
|
|
|
845
906
|
if (i < itemsFromDisplayEndToOffsetEnd) {
|
|
846
907
|
rightItemsWeight += componentSize;
|
|
847
908
|
}
|
|
848
|
-
if (itemDisplayMethod === ItemDisplayMethods.UPDATE) {
|
|
849
|
-
rightSizeOfUpdatedItems += componentSizeDelta;
|
|
850
|
-
}
|
|
851
|
-
if (itemDisplayMethod === ItemDisplayMethods.CREATE) {
|
|
852
|
-
rightSizeOfAddedItems += componentSizeDelta;
|
|
853
|
-
}
|
|
854
909
|
}
|
|
855
910
|
y += componentSize;
|
|
856
911
|
}
|
|
@@ -878,6 +933,43 @@ class TrackBox extends CacheMap {
|
|
|
878
933
|
else
|
|
879
934
|
// Buffer optimization does not work on fast linear algorithm
|
|
880
935
|
{
|
|
936
|
+
if (crudDetected) {
|
|
937
|
+
let y = 0;
|
|
938
|
+
for (let i = 0, l = collection.length; i < l; i++) {
|
|
939
|
+
const collectionItem = collection[i], id = collectionItem.id;
|
|
940
|
+
let componentSize = typicalItemSize, itemDisplayMethod = ItemDisplayMethods.NOT_CHANGED;
|
|
941
|
+
if (map.has(id)) {
|
|
942
|
+
const bounds = map.get(id);
|
|
943
|
+
itemDisplayMethod = bounds?.method ?? ItemDisplayMethods.UPDATE;
|
|
944
|
+
if (itemDisplayMethod === ItemDisplayMethods.CREATE) {
|
|
945
|
+
map.set(id, { ...bounds, method: ItemDisplayMethods.NOT_CHANGED });
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
if (this._deletedItemsMap.hasOwnProperty(i)) {
|
|
949
|
+
const bounds = this._deletedItemsMap[i], size = bounds[sizeProperty] ?? typicalItemSize;
|
|
950
|
+
if (y < scrollSize - size) {
|
|
951
|
+
leftSizeOfDeletedItems += size;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
if (y < scrollSize - componentSize) {
|
|
955
|
+
switch (itemDisplayMethod) {
|
|
956
|
+
case ItemDisplayMethods.CREATE: {
|
|
957
|
+
leftSizeOfUpdatedItems += componentSize;
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
case ItemDisplayMethods.UPDATE: {
|
|
961
|
+
leftSizeOfUpdatedItems += componentSize;
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
case ItemDisplayMethods.DELETE: {
|
|
965
|
+
leftSizeOfDeletedItems += componentSize;
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
y += componentSize;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
881
973
|
itemsFromStartToScrollEnd = Math.floor(scrollSize / typicalItemSize);
|
|
882
974
|
itemsFromStartToDisplayEnd = Math.ceil((scrollSize + size) / typicalItemSize);
|
|
883
975
|
leftItemLength = Math.min(itemsFromStartToScrollEnd, itemsOffset);
|
|
@@ -887,11 +979,12 @@ class TrackBox extends CacheMap {
|
|
|
887
979
|
rightItemsWeight = rightItemLength * typicalItemSize,
|
|
888
980
|
leftHiddenItemsWeight = itemsFromStartToScrollEnd * typicalItemSize,
|
|
889
981
|
totalItemsToDisplayEndWeight = itemsFromStartToDisplayEnd * typicalItemSize;
|
|
890
|
-
actualScrollSize = scrollSize;
|
|
891
982
|
totalSize = totalLength * typicalItemSize;
|
|
983
|
+
const k = totalSize !== 0 ? previousTotalSize / totalSize : 0;
|
|
984
|
+
actualScrollSize = scrollSize * k;
|
|
892
985
|
}
|
|
893
986
|
startIndex = Math.min(itemsFromStartToScrollEnd - leftItemLength, totalLength > 0 ? totalLength - 1 : 0);
|
|
894
|
-
const itemsOnDisplay = totalItemsToDisplayEndWeight - leftHiddenItemsWeight, itemsOnDisplayLength = itemsFromStartToDisplayEnd - itemsFromStartToScrollEnd, startPosition = leftHiddenItemsWeight - leftItemsWeight, renderItems = itemsOnDisplayLength + leftItemLength + rightItemLength, delta = leftSizeOfUpdatedItems + leftSizeOfAddedItems;
|
|
987
|
+
const itemsOnDisplay = totalItemsToDisplayEndWeight - leftHiddenItemsWeight, itemsOnDisplayLength = itemsFromStartToDisplayEnd - itemsFromStartToScrollEnd, startPosition = leftHiddenItemsWeight - leftItemsWeight, renderItems = itemsOnDisplayLength + leftItemLength + rightItemLength, delta = leftSizeOfUpdatedItems + leftSizeOfAddedItems - leftSizeOfDeletedItems;
|
|
895
988
|
const metrics = {
|
|
896
989
|
delta,
|
|
897
990
|
normalizedItemWidth: w,
|
|
@@ -913,7 +1006,6 @@ class TrackBox extends CacheMap {
|
|
|
913
1006
|
rightItemsWeight,
|
|
914
1007
|
scrollSize: actualScrollSize,
|
|
915
1008
|
leftSizeOfAddedItems,
|
|
916
|
-
rightSizeOfAddedItems,
|
|
917
1009
|
sizeProperty,
|
|
918
1010
|
snap,
|
|
919
1011
|
snippedPos,
|
|
@@ -926,8 +1018,6 @@ class TrackBox extends CacheMap {
|
|
|
926
1018
|
};
|
|
927
1019
|
return metrics;
|
|
928
1020
|
}
|
|
929
|
-
_scrollDelta = 0;
|
|
930
|
-
get scrollDelta() { return this._scrollDelta; }
|
|
931
1021
|
clearDeltaDirection() {
|
|
932
1022
|
this.clearScrollDirectionCache();
|
|
933
1023
|
}
|
|
@@ -1112,7 +1202,7 @@ class ScrollEvent {
|
|
|
1112
1202
|
* Virtual list component.
|
|
1113
1203
|
* Maximum performance for extremely large lists.
|
|
1114
1204
|
* It is based on algorithms for virtualization of screen objects.
|
|
1115
|
-
* @link https://github.com/DjonnyX/ng-virtual-list/blob/
|
|
1205
|
+
* @link https://github.com/DjonnyX/ng-virtual-list/blob/19.x/projects/ng-virtual-list/src/lib/ng-virtual-list.component.ts
|
|
1116
1206
|
* @author Evgenii Grebennikov
|
|
1117
1207
|
* @email djonnyx@gmail.com
|
|
1118
1208
|
*/
|
|
@@ -1205,11 +1295,7 @@ class NgVirtualListComponent {
|
|
|
1205
1295
|
this.clearScrollToRepeatExecutionTimeout();
|
|
1206
1296
|
const container = this._container()?.nativeElement;
|
|
1207
1297
|
if (container) {
|
|
1208
|
-
const
|
|
1209
|
-
let actualScrollSize = scrollSize, isScrollIUmmediate = false;
|
|
1210
|
-
if (dynamicSize && delta !== 0) {
|
|
1211
|
-
actualScrollSize = scrollSize + delta;
|
|
1212
|
-
}
|
|
1298
|
+
const scrollSize = (this._isVertical ? container.scrollTop : container.scrollLeft), actualScrollSize = scrollSize;
|
|
1213
1299
|
this._scrollSize.set(actualScrollSize);
|
|
1214
1300
|
}
|
|
1215
1301
|
};
|
|
@@ -1255,7 +1341,7 @@ class NgVirtualListComponent {
|
|
|
1255
1341
|
const { width, height } = bounds;
|
|
1256
1342
|
let actualScrollSize = (this._isVertical ? this._container()?.nativeElement.scrollTop ?? 0 : this._container()?.nativeElement.scrollLeft) ?? 0;
|
|
1257
1343
|
const opts = {
|
|
1258
|
-
bounds: { width, height },
|
|
1344
|
+
bounds: { width, height }, dynamicSize, isVertical, itemSize,
|
|
1259
1345
|
itemsOffset, scrollSize: scrollSize, snap, enabledBufferOptimization,
|
|
1260
1346
|
};
|
|
1261
1347
|
const { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, {
|
|
@@ -1266,28 +1352,15 @@ class NgVirtualListComponent {
|
|
|
1266
1352
|
this.tracking();
|
|
1267
1353
|
const container = this._container();
|
|
1268
1354
|
if (container) {
|
|
1269
|
-
|
|
1355
|
+
const delta = this._trackBox.delta;
|
|
1356
|
+
actualScrollSize = actualScrollSize + delta;
|
|
1270
1357
|
this._trackBox.clearDelta();
|
|
1271
|
-
if (
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
container.nativeElement.scrollTo(params);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
else {
|
|
1281
|
-
if (scrollSize !== actualScrollSize) {
|
|
1282
|
-
const params = {
|
|
1283
|
-
[this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: actualScrollSize,
|
|
1284
|
-
behavior: BEHAVIOR_INSTANT
|
|
1285
|
-
};
|
|
1286
|
-
const container = this._container();
|
|
1287
|
-
if (container) {
|
|
1288
|
-
container.nativeElement.scrollTo(params);
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1358
|
+
if (scrollSize !== actualScrollSize) {
|
|
1359
|
+
const params = {
|
|
1360
|
+
[this._isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: actualScrollSize,
|
|
1361
|
+
behavior: BEHAVIOR_INSTANT
|
|
1362
|
+
};
|
|
1363
|
+
container.nativeElement.scrollTo(params);
|
|
1291
1364
|
}
|
|
1292
1365
|
}
|
|
1293
1366
|
return of(displayItems);
|