pinafore/routes/_components/virtualList/virtualListStore.js

117 lines
3.6 KiB
JavaScript
Raw Normal View History

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