diff options
Diffstat (limited to 'web/src/js/components/helpers/VirtualScroll.js')
-rw-r--r-- | web/src/js/components/helpers/VirtualScroll.js | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/web/src/js/components/helpers/VirtualScroll.js b/web/src/js/components/helpers/VirtualScroll.js new file mode 100644 index 00000000..5d4cf796 --- /dev/null +++ b/web/src/js/components/helpers/VirtualScroll.js @@ -0,0 +1,70 @@ +/** + * Calculate virtual scroll stuffs + * + * @param {?Object} opts Options for calculation + * + * @returns {Object} result + * + * __opts__ should have following properties: + * - {number} itemCount + * - {number} rowHeight + * - {number} viewportTop + * - {number} viewportHeight + * - {Array<?number>} [itemHeights] + * + * __result__ have following properties: + * - {number} start + * - {number} end + * - {number} paddingTop + * - {number} paddingBottom + */ +export function calcVScroll(opts) { + if (!opts) { + return { start: 0, end: 0, paddingTop: 0, paddingBottom: 0 }; + } + + const { itemCount, rowHeight, viewportTop, viewportHeight, itemHeights } = opts; + const viewportBottom = viewportTop + viewportHeight; + + let start = 0; + let end = 0; + + let paddingTop = 0; + let paddingBottom = 0; + + if (itemHeights) { + + for (let i = 0, pos = 0; i < itemCount; i++) { + const height = itemHeights[i] || rowHeight; + + if (pos <= viewportTop && i % 2 === 0) { + paddingTop = pos; + start = i; + } + + if (pos <= viewportBottom) { + end = i + 1; + } else { + paddingBottom += height; + } + + pos += height; + } + + } else { + + // Make sure that we start at an even row so that CSS `:nth-child(even)` is preserved + start = Math.max(0, Math.floor(viewportTop / rowHeight) - 1) & ~1; + end = Math.min( + itemCount, + start + Math.ceil(viewportHeight / rowHeight) + 1 + ); + + // When a large trunk of elements is removed from the button, start may be far off the viewport. + // To make this issue less severe, limit the top placeholder to the total number of rows. + paddingTop = Math.min(start, itemCount) * rowHeight; + paddingBottom = Math.max(0, itemCount - end) * rowHeight; + } + + return { start, end, paddingTop, paddingBottom }; +} |