forked from cybrespace/pinafore
		
	itemHeights should be divided by realm
This commit is contained in:
		
							parent
							
								
									0d4ee2bba3
								
							
						
					
					
						commit
						2c2f84b870
					
				
					 4 changed files with 46 additions and 37 deletions
				
			
		| 
						 | 
					@ -19,7 +19,7 @@
 | 
				
			||||||
      const asyncLayout = new AsyncLayout(() => '__footer__')
 | 
					      const asyncLayout = new AsyncLayout(() => '__footer__')
 | 
				
			||||||
      asyncLayout.observe('__footer__', this.refs.node, (rect) => {
 | 
					      asyncLayout.observe('__footer__', this.refs.node, (rect) => {
 | 
				
			||||||
        asyncLayout.disconnect()
 | 
					        asyncLayout.disconnect()
 | 
				
			||||||
        this.store.set({footerHeight: rect.height})
 | 
					        this.store.setForRealm({footerHeight: rect.height})
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    store: () => virtualListStore,
 | 
					    store: () => virtualListStore,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
  <:Component {component}
 | 
					  <:Component {component}
 | 
				
			||||||
              virtualProps="{{props}}"
 | 
					              virtualProps="{{props}}"
 | 
				
			||||||
              virtualIndex="{{index}}"
 | 
					              virtualIndex="{{index}}"
 | 
				
			||||||
              virtualLength="{{$numItems}}"
 | 
					              virtualLength="{{numItems}}"
 | 
				
			||||||
              on:recalculateHeight="doRecalculateHeight()"/>
 | 
					              on:recalculateHeight="doRecalculateHeight()"/>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
<style>
 | 
					<style>
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@
 | 
				
			||||||
        asyncLayout.observe(key, this.refs.node, (rect) => {
 | 
					        asyncLayout.observe(key, this.refs.node, (rect) => {
 | 
				
			||||||
          asyncLayout.disconnect()
 | 
					          asyncLayout.disconnect()
 | 
				
			||||||
          // update all item heights in one batch for better perf
 | 
					          // update all item heights in one batch for better perf
 | 
				
			||||||
          this.store.batchUpdate('itemHeights', key, rect.height)
 | 
					          this.store.batchUpdateForRealm('itemHeights', key, rect.height)
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,49 +6,18 @@ const VIEWPORT_RENDER_FACTOR = 4
 | 
				
			||||||
class VirtualListStore extends RealmStore {
 | 
					class VirtualListStore extends RealmStore {
 | 
				
			||||||
  constructor(state) {
 | 
					  constructor(state) {
 | 
				
			||||||
    super(state, /* maxSize */ 10)
 | 
					    super(state, /* maxSize */ 10)
 | 
				
			||||||
    this._batches = {}
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  batchUpdate(key, subKey, value) {
 | 
					 | 
				
			||||||
    let batch = this._batches[key]
 | 
					 | 
				
			||||||
    if (!batch) {
 | 
					 | 
				
			||||||
      batch = this._batches[key] = {}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    batch[subKey] = value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    requestAnimationFrame(() => {
 | 
					 | 
				
			||||||
      let batch = this._batches[key]
 | 
					 | 
				
			||||||
      if (!batch) {
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      let updatedKeys = Object.keys(batch)
 | 
					 | 
				
			||||||
      if (!updatedKeys.length) {
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      mark('batchUpdate()')
 | 
					 | 
				
			||||||
      let obj = this.get(key)
 | 
					 | 
				
			||||||
      for (let otherKey of updatedKeys) {
 | 
					 | 
				
			||||||
        obj[otherKey] = batch[otherKey]
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      delete this._batches[key]
 | 
					 | 
				
			||||||
      let toSet = {}
 | 
					 | 
				
			||||||
      toSet[key] = obj
 | 
					 | 
				
			||||||
      this.set(toSet)
 | 
					 | 
				
			||||||
      stop('batchUpdate()')
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const virtualListStore = new VirtualListStore({
 | 
					const virtualListStore = new VirtualListStore()
 | 
				
			||||||
  itemHeights: {},
 | 
					 | 
				
			||||||
  footerHeight: 0
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
virtualListStore.computeForRealm('items', [])
 | 
					virtualListStore.computeForRealm('items', [])
 | 
				
			||||||
virtualListStore.computeForRealm('showFooter', false)
 | 
					virtualListStore.computeForRealm('showFooter', false)
 | 
				
			||||||
 | 
					virtualListStore.computeForRealm('footerHeight', 0)
 | 
				
			||||||
virtualListStore.computeForRealm('scrollTop', 0)
 | 
					virtualListStore.computeForRealm('scrollTop', 0)
 | 
				
			||||||
virtualListStore.computeForRealm('scrollHeight', 0)
 | 
					virtualListStore.computeForRealm('scrollHeight', 0)
 | 
				
			||||||
virtualListStore.computeForRealm('offsetHeight', 0)
 | 
					virtualListStore.computeForRealm('offsetHeight', 0)
 | 
				
			||||||
 | 
					virtualListStore.computeForRealm('itemHeights', {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
virtualListStore.compute('visibleItems',
 | 
					virtualListStore.compute('visibleItems',
 | 
				
			||||||
    ['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
 | 
					    ['items', 'scrollTop', 'itemHeights', 'offsetHeight'],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,11 +3,13 @@
 | 
				
			||||||
// with computeForRealm(). The maxSize determines how many realms to keep in the LRU cache.
 | 
					// with computeForRealm(). The maxSize determines how many realms to keep in the LRU cache.
 | 
				
			||||||
import { Store } from 'svelte/store.js'
 | 
					import { Store } from 'svelte/store.js'
 | 
				
			||||||
import QuickLRU from 'quick-lru'
 | 
					import QuickLRU from 'quick-lru'
 | 
				
			||||||
 | 
					import { mark, stop } from './marks'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class RealmStore extends Store {
 | 
					export class RealmStore extends Store {
 | 
				
			||||||
  constructor(init, maxSize) {
 | 
					  constructor(init, maxSize) {
 | 
				
			||||||
    super(init)
 | 
					    super(init)
 | 
				
			||||||
    this.set({realms: new QuickLRU({maxSize: maxSize})})
 | 
					    this.set({realms: new QuickLRU({maxSize: maxSize})})
 | 
				
			||||||
 | 
					    this._batches = {}
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setCurrentRealm(realm) {
 | 
					  setCurrentRealm(realm) {
 | 
				
			||||||
| 
						 | 
					@ -29,4 +31,42 @@ export class RealmStore extends Store {
 | 
				
			||||||
      return (realmData && realmData[key]) || defaultValue
 | 
					      return (realmData && realmData[key]) || defaultValue
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					   * Update several values at once in a realm, assuming the key points
 | 
				
			||||||
 | 
					   * to a plain old javascript object.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  batchUpdateForRealm(key, subKey, value) {
 | 
				
			||||||
 | 
					    let realm = this.get('currentRealm')
 | 
				
			||||||
 | 
					    let realmBatches = this._batches[realm]
 | 
				
			||||||
 | 
					    if (!realmBatches) {
 | 
				
			||||||
 | 
					      realmBatches = this._batches[realm] = {}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let batch = realmBatches[key]
 | 
				
			||||||
 | 
					    if (!batch) {
 | 
				
			||||||
 | 
					      batch = realmBatches[key] = {}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    batch[subKey] = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    requestAnimationFrame(() => {
 | 
				
			||||||
 | 
					      let batch = this._batches[realm] && this._batches[realm][key]
 | 
				
			||||||
 | 
					      if (!batch) {
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let updatedKeys = Object.keys(batch)
 | 
				
			||||||
 | 
					      if (!updatedKeys.length) {
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      mark('batchUpdate')
 | 
				
			||||||
 | 
					      let obj = this.get(key)
 | 
				
			||||||
 | 
					      for (let otherKey of updatedKeys) {
 | 
				
			||||||
 | 
					        obj[otherKey] = batch[otherKey]
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      delete this._batches[realm][key]
 | 
				
			||||||
 | 
					      let realms = this.get('realms')
 | 
				
			||||||
 | 
					      realms.set(realm, Object.assign(realms.get(realm) || {}, {[key]: obj}))
 | 
				
			||||||
 | 
					      this.set({realms: realms})
 | 
				
			||||||
 | 
					      stop('batchUpdate')
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue