drop items out of holdzone, and update changed topics

This commit is contained in:
Roland Osborne 2022-04-21 12:10:04 -07:00
parent 5900d9f085
commit efbd714fa5

View File

@ -3,13 +3,11 @@ import { VirtualListWrapper, VirtualItem } from './VirtualList.styled';
import ReactResizeDetector from 'react-resize-detector';
import { TopicItem } from './TopicItem/TopicItem';
// TODO: drop items past overscan
// TODO: sync topic updates
export function VirtualList({ topics }) {
const REDZONE = 256;
const OVERSCAN = 256;
const REDZONE = 256; // recenter on canvas if in canvas edge redzone
const HOLDZONE = 512; // drop items outside of holdzone of view
const OVERSCAN = 256; // add items in overscan of view
const DEFAULT_ITEM_HEIGHT = 64;
const DEFAULT_LIST_HEIGHT = 4096;
const GUTTER = 8;
@ -33,6 +31,10 @@ export function VirtualList({ topics }) {
setItems((m) => { m.set(id, item); return new Map(m); })
}
const removeItem = (id) => {
setItems((m) => { m.delete(id); return new Map(m); })
}
useEffect(() => {
if (viewHeight * 3 > canvasHeight) {
setCanvasHeight(viewHeight*3);
@ -85,10 +87,18 @@ export function VirtualList({ topics }) {
height: DEFAULT_ITEM_HEIGHT,
index: containers.current[0].index - 1,
id: topics[containers.current[0].index - 1].id,
revision: topics[containers.current[0].index - 1].revision,
}
containers.current.unshift(container);
addItem(container.id, getItem(container))
anchorBottom.current = true;
if (containers.current[containers.current.length - 1].top > scrollTop.current + viewHeight + HOLDZONE) {
removeItem(containers.current[containers.current.length - 1].id);
containers.current.pop();
}
alignItems();
}
}
if (view.overscan.bottom < OVERSCAN) {
@ -99,10 +109,18 @@ export function VirtualList({ topics }) {
height: DEFAULT_ITEM_HEIGHT,
index: containers.current[containers.current.length - 1].index + 1,
id: topics[containers.current[containers.current.length - 1].index + 1].id,
revision: topics[containers.current[containers.current.length - 1].index + 1].revision,
}
containers.current.push(container);
addItem(container.id, getItem(container))
anchorBottom.current = false;
if (containers.current[0].top + containers.current[0].height + 2 * GUTTER < scrollTop.current) {
removeItem(containers.current[0].id);
containers.current.shift();
}
alignItems();
}
}
}
@ -173,8 +191,42 @@ export function VirtualList({ topics }) {
}
const setTopics = () => {
// validate items
// update or removed any affected items
if (anchorBottom.current) {
for (let i = containers.current.length - 1; i >= 0; i--) {
let container = containers.current[i];
if (topics.length < container.index || topics[container.index].id != container.id) {
for (let j = 0; j <= i; j++) {
let shifted = containers.current.shift();
removeItem(shifted.id);
}
break;
}
else if (topics[container.index].revision != container.revision) {
updateItem(container.id, getItem(containers.current[i]));
containers.revision = topics[container.index].revision;
}
}
}
else {
for (let i = 0; i < containers.current.length; i++) {
let container = containers.current[i];
if (topics.length < container.index || topics[container.index].id != container.id) {
for (let j = i; j < containers.current.length; j++) {
let popped = containers.current.pop();
removeItem(popped.id);
}
break;
}
else if (topics[container.index].revision != container.revision) {
updateItem(container.id, getItem(containers.current[i]));
containers.revision = topics[container.index].revision;
}
}
}
// place first item
if (topics.length > 0 && canvasHeight > 0) {
let view = getPlacement();
if (!view) {
@ -187,6 +239,7 @@ export function VirtualList({ topics }) {
height: DEFAULT_ITEM_HEIGHT,
index: topics.length - 1,
id: topics[topics.length - 1].id,
revision: topics[topics.length - 1].revision,
}
anchorBottom.current = true;