Skip to content

Instantly share code, notes, and snippets.

@ArcticLight
Created October 1, 2019 02:47
Show Gist options
  • Save ArcticLight/cff8dccede30273a3c2cf6150305b913 to your computer and use it in GitHub Desktop.
Save ArcticLight/cff8dccede30273a3c2cf6150305b913 to your computer and use it in GitHub Desktop.
For Forceh
const rows = [];
const filteredRows = [];
for (let i = 0; i < 100; i++) {
rows.push({
text: "I'm a row!",
id: (i * 1000).toString(32),
});
}
const DEFAULT_BATCH_SIZE = 15;
let startIndex = 0;
let batchSize = DEFAULT_BATCH_SIZE;
let firstVisibleId = '';
let lastVisibleId = '';
let isFiltering = false;
function filterList() {
// get start/end points
let start = startIndex;
let end = Math.min(startIndex + batchSize, rows.length - 1);
// check the length of the batch and figure out how many we're missing
const length = end - start;
const missing = batchSize - length;
filteredRows.splice(0, filteredRows.length);
for (let i = start; i < end; i++) {
filteredRows.push(rows[i]);
}
}
function render() {
const el = document.getElementById('tbody');
while (el.firstChild) {
el.removeChild(el.firstChild);
}
filteredRows.forEach((row, ix) => {
el.innerHTML += `<tr id="row.${row.id}" data-id="${row.id}" data-ix="${ix}"><td>${row.text} (${row.id})</td><td>row ${ix + 1 + startIndex}</td>`;
});
// get first visible row
firstVisibleId = getFirstVisibleRow();
lastVisibleId = getLastVisibleRow();
}
function getFirstVisibleRow() {
const el = document.getElementById('tbody');
const children = [...el.children];
const firstVisibleIndex = children.findIndex((childNode) => isRowVisible(childNode));
return (firstVisibleIndex === -1) ? null : children[firstVisibleIndex].dataset.id;
}
function getLastVisibleRow() {
const el = document.getElementById('tbody');
const children = [...el.children];
children.reverse();
const lastVisibleIndex = children.findIndex((childNode) => isRowVisible(childNode));
return (lastVisibleIndex === -1) ? null : children[lastVisibleIndex].dataset.id;
}
function isRowVisible(rowNode) {
const top = 0;
const bottom = window.innerHeight;
const boundingRect = rowNode.getBoundingClientRect();
return bottom > boundingRect.top && boundingRect.top > top;
}
let previousScrollTop = 0;
let scrollDirection = 0; // 1 = down, -1 = up
window.addEventListener('scroll', (e) => {
const el = e.currentTarget;
if (!el) return;
const scrollAmount = document.body.scrollTop || document.documentElement.scrollTop;
const direction = scrollDirection = scrollAmount > previousScrollTop ? 1 : -1;
previousScrollTop = scrollAmount;
if (direction === 1) {
scrollingDownHandler();
} else if (direction === -1) {
scrollingUpHandler();
}
});
function scrollingDownHandler() {
// see if the first thing is out of the window
const row = document.getElementById(`row.${firstVisibleId}`);
if (!row) return;
// still visible so stop
if (isRowVisible(row)) return
// otherwise get its height
const height = row.clientHeight;
// then update the start index by 1
const idx = rows.findIndex(r => r.id === row.dataset.id);
if (idx === -1) return;
// create some padding on the list
containerAddPadding(height);
startIndex = idx + 1;
// re-render
filterAndRender();
}
function scrollingUpHandler() {
if (isFiltering) return;
let row = document.getElementById(`row.${lastVisibleId}`);
if (!row) return;
// still visible so stop
if (isRowVisible(row)) return;
// otherwise get its height
const height = row.clientHeight;
// create some padding on the list
containerRemovePadding(height);
// Need the current top of the list to find where to back up from:
row = document.getElementById(`row.${firstVisibleId}`);
const idx = rows.findIndex(r => r.id === row.dataset.id);
if (idx === -1) return; // oops?
// then back up the start of the list:
startIndex = idx - 1;
// re-render
filterAndRender();
}
function containerAddPadding(amount) {
console.log("adding padding")
const el = document.getElementById("container");
if (!el) return;
const padding = parseInt(el.style.paddingTop || 0);
el.style.paddingTop = `${padding + amount}px`
}
function containerRemovePadding(amount) {
console.log("remove padding")
const el = document.getElementById("container");
if (!el) return;
const padding = parseInt(el.style.paddingTop || 0);
el.style.paddingTop = `${padding - amount}px`
}
function filterAndRender() {
filterList();
render();
}
filterAndRender();
function showMe() {
const el = document.getElementById('tbody');
const children = [...el.children];
children.forEach((row) => {
if (isRowVisible(row)) {
row.style.background = 'green';
} else {
row.style.background = 'red';
}
});
}
window.setInterval(showMe, 100);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment