pinafore/routes/_components/virtualList/virtualListStore.js

97 lines
2.6 KiB
JavaScript
Raw Normal View History

2018-01-25 08:23:14 -08:00
import { mark, stop } from '../../_utils/marks'
2018-01-30 21:55:23 -08:00
import { RealmStore } from '../../_utils/RealmStore'
2018-01-20 15:37:40 -08:00
const VIEWPORT_RENDER_FACTOR = 4
2018-01-30 21:55:23 -08:00
class VirtualListStore extends RealmStore {
2018-01-17 19:53:12 -08:00
constructor(state) {
2018-01-30 21:55:23 -08:00
super(state, /* maxSize */ 10)
2018-01-17 19:41:37 -08:00
}
}
2018-01-31 08:37:59 -08:00
const virtualListStore = new VirtualListStore()
2018-01-30 21:55:23 -08:00
virtualListStore.computeForRealm('items', [])
virtualListStore.computeForRealm('showFooter', false)
2018-01-31 08:37:59 -08:00
virtualListStore.computeForRealm('footerHeight', 0)
2018-01-30 21:55:23 -08:00
virtualListStore.computeForRealm('scrollTop', 0)
virtualListStore.computeForRealm('scrollHeight', 0)
virtualListStore.computeForRealm('offsetHeight', 0)
2018-01-31 08:37:59 -08:00
virtualListStore.computeForRealm('itemHeights', {})
2018-01-27 08:13:28 -08:00
2018-01-15 16:12:07 -08:00
virtualListStore.compute('visibleItems',
2018-01-16 21:43:31 -08:00
['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
(items, scrollTop, itemHeights, offsetHeight) => {
2018-01-17 00:59:15 -08:00
mark('compute visibleItems')
2018-01-20 15:37:40 -08:00
let renderBuffer = VIEWPORT_RENDER_FACTOR * offsetHeight
2018-01-15 16:12:07 -08:00
let visibleItems = []
2018-01-15 17:25:32 -08:00
let totalOffset = 0
let len = items.length
let i = -1
while (++i < len) {
2018-01-23 18:19:03 -08:00
let key = items[i]
2018-01-15 16:35:08 -08:00
let height = itemHeights[key] || 0
2018-01-15 17:25:32 -08:00
let currentOffset = totalOffset
totalOffset += height
let isBelowViewport = (currentOffset < scrollTop)
if (isBelowViewport) {
2018-01-15 18:29:28 -08:00
if (scrollTop - renderBuffer > currentOffset) {
2018-01-15 17:25:32 -08:00
continue // below the area we want to render
}
2018-01-15 16:12:07 -08:00
} else {
2018-01-16 23:16:15 -08:00
if (currentOffset > (scrollTop + height + renderBuffer)) {
2018-01-15 17:25:32 -08:00
break // above the area we want to render
}
2018-01-15 16:12:07 -08:00
}
2018-01-15 17:25:32 -08:00
visibleItems.push({
offset: currentOffset,
key: key,
2018-01-16 23:16:15 -08:00
index: i
2018-01-15 17:25:32 -08:00
})
}
2018-01-17 00:59:15 -08:00
stop('compute visibleItems')
2018-01-15 16:12:07 -08:00
return visibleItems
})
2018-01-21 16:07:11 -08:00
virtualListStore.compute('heightWithoutFooter',
['items', 'itemHeights'],
(items, itemHeights) => {
let sum = 0
2018-01-15 17:25:32 -08:00
let i = -1
let len = items.length
while (++i < len) {
2018-01-23 18:19:03 -08:00
sum += itemHeights[items[i]] || 0
2018-01-15 17:25:32 -08:00
}
return sum
})
2018-01-21 16:07:11 -08:00
virtualListStore.compute('height',
['heightWithoutFooter', 'showFooter', 'footerHeight'],
(heightWithoutFooter, showFooter, footerHeight) => {
return showFooter ? (heightWithoutFooter + footerHeight) : heightWithoutFooter
})
2018-01-17 23:00:33 -08:00
virtualListStore.compute('numItems', ['items'], (items) => items.length)
2018-01-24 18:04:25 -08:00
virtualListStore.compute('allVisibleItemsHaveHeight',
['visibleItems', 'itemHeights'],
(visibleItems, itemHeights) => {
2018-01-24 18:58:10 -08:00
if (!visibleItems.length) {
return false
}
2018-01-24 18:04:25 -08:00
for (let visibleItem of visibleItems) {
if (!itemHeights[visibleItem.key]) {
return false
}
}
return true
})
if (process.browser && process.env.NODE_ENV !== 'production') {
window.virtualListStore = virtualListStore
}
export {
virtualListStore
}