Skip to content

Instantly share code, notes, and snippets.

Created October 6, 2017 13:24
Show Gist options
  • Save anonymous/1613feac7943ba575d56c7554862b430 to your computer and use it in GitHub Desktop.
Save anonymous/1613feac7943ba575d56c7554862b430 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style id="jsbin-css">
/* wrapper */
.tableWrap {
border: solid 1px #ddd;
height: 100vh;
overflow-x: auto;
overflow-y: hidden;
position: relative;
background: #eee;
}
/* table */
table {
border-collapse: collapse;
margin: 0;
padding: 0;
border: 0;
width: 100%;
}
tr {
height: 40px;
margin: 0;
padding: 0;
border-top: solid 1px #ddd;
}
tr.heading {
border-top: none;
background: #fff;
}
td, th {
border: none;
margin: 0;
padding: 10px;
min-width: 200px;
max-width: 200px;
overflow: hidden;
text-align: center;
}
/* grid */
.vertical-overflow {
height: 100%;
position: absolute;
top: 40px;
left: 0;
overflow-x: hidden;
overflow-y: auto;
}
.grid {
width: 100%;
height: 100%;
margin-bottom: 40px;
}
</style>
</head>
<body>
<div class="tableWrap">
<table id="header">
<tr class="heading">
<th>Heading 1</th>
<th>Heading 2</th>
<th>Heading 3</th>
<th>Heading 4</th>
<th>Heading 5</th>
<th>Heading 6</th>
<th>Heading 7</th>
</tr>
</table>
<div class="vertical-overflow">
<table class="grid"></table>
</div>
</div>
<script id="jsbin-javascript">
// globals
let curY = 0
let curDirection = 'DOWN'
let curOffset = 0
let data = []
let scrollHeight = 0
const maxRows = 40
const verticalOverflow = document.querySelector('.vertical-overflow')
const tableWrap = document.querySelector('.tableWrap')
// example data
const createRows = data =>
data.reduce((acc, d) => {
acc += `<tr>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
</tr>`
return acc
}, '')
const createData = (offsetRows = []) => {
let counter = 0
let dataVal = curOffset
data = []
while (counter < maxRows) {
dataVal += 1
data.push(dataVal)
counter++
}
counter = 0
const rowData = curDirection === 'DOWN' ?
offsetRows.concat(data) :
data.concat(offsetRows)
document.querySelector('.grid').innerHTML = createRows(rowData)
}
createData()
// calculations
const viewHeight = parseInt(
getComputedStyle(tableWrap).height,
10
)
const tdHeight = parseInt(
document.querySelector('.grid td').getBoundingClientRect().top,
10
)
// get offset rows
const getNumOffsetRows = () => Math.floor(viewHeight / tdHeight)
// data loader
const loadData = () => {
const numOffsetRows = curOffset > 0 ? getNumOffsetRows() : 0
let offsetRows = curDirection === 'DOWN' ?
data.slice(data.length - numOffsetRows - 1, data.length) :
data.slice(0, numOffsetRows)
createData(offsetRows)
scrollGrid()
}
const scrollGrid = () => {
const y = curDirection === 'DOWN' ? tdHeight : scrollHeight - tdHeight
verticalOverflow.scrollTop = y
}
// check threshold
const checkThreshold = (scrollHeight) => {
if (curY === scrollHeight && curDirection === 'DOWN') {
curOffset += maxRows
// load data
loadData()
} else if (curY === 0 && curDirection === 'UP') {
curOffset -= maxRows
if (curOffset < 0) {
curOffset = 0
return
}
// load data
loadData()
}
}
// vertical scroll listener
verticalOverflow.addEventListener('scroll', (e) => {
const scrollTop = parseInt(e.target.scrollTop, 10)
scrollHeight = parseInt(e.target.scrollHeight, 10) - viewHeight
// set direction
curDirection = scrollTop > curY ? 'DOWN' : 'UP'
// set current y coordinate
curY = scrollTop
// check scroll thresholds
checkThreshold(scrollHeight)
})
</script>
<script id="jsbin-source-css" type="text/css">/* wrapper */
.tableWrap {
border: solid 1px #ddd;
height: 100vh;
overflow-x: auto;
overflow-y: hidden;
position: relative;
background: #eee;
}
/* table */
table {
border-collapse: collapse;
margin: 0;
padding: 0;
border: 0;
width: 100%;
}
tr {
height: 40px;
margin: 0;
padding: 0;
border-top: solid 1px #ddd;
}
tr.heading {
border-top: none;
background: #fff;
}
td, th {
border: none;
margin: 0;
padding: 10px;
min-width: 200px;
max-width: 200px;
overflow: hidden;
text-align: center;
}
/* grid */
.vertical-overflow {
height: 100%;
position: absolute;
top: 40px;
left: 0;
overflow-x: hidden;
overflow-y: auto;
}
.grid {
width: 100%;
height: 100%;
margin-bottom: 40px;
}
</script>
<script id="jsbin-source-javascript" type="text/javascript">// globals
let curY = 0
let curDirection = 'DOWN'
let curOffset = 0
let data = []
let scrollHeight = 0
const maxRows = 40
const verticalOverflow = document.querySelector('.vertical-overflow')
const tableWrap = document.querySelector('.tableWrap')
// example data
const createRows = data =>
data.reduce((acc, d) => {
acc += `<tr>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
</tr>`
return acc
}, '')
const createData = (offsetRows = []) => {
let counter = 0
let dataVal = curOffset
data = []
while (counter < maxRows) {
dataVal += 1
data.push(dataVal)
counter++
}
counter = 0
const rowData = curDirection === 'DOWN' ?
offsetRows.concat(data) :
data.concat(offsetRows)
document.querySelector('.grid').innerHTML = createRows(rowData)
}
createData()
// calculations
const viewHeight = parseInt(
getComputedStyle(tableWrap).height,
10
)
const tdHeight = parseInt(
document.querySelector('.grid td').getBoundingClientRect().top,
10
)
// get offset rows
const getNumOffsetRows = () => Math.floor(viewHeight / tdHeight)
// data loader
const loadData = () => {
const numOffsetRows = curOffset > 0 ? getNumOffsetRows() : 0
let offsetRows = curDirection === 'DOWN' ?
data.slice(data.length - numOffsetRows - 1, data.length) :
data.slice(0, numOffsetRows)
createData(offsetRows)
scrollGrid()
}
const scrollGrid = () => {
const y = curDirection === 'DOWN' ? tdHeight : scrollHeight - tdHeight
verticalOverflow.scrollTop = y
}
// check threshold
const checkThreshold = (scrollHeight) => {
if (curY === scrollHeight && curDirection === 'DOWN') {
curOffset += maxRows
// load data
loadData()
} else if (curY === 0 && curDirection === 'UP') {
curOffset -= maxRows
if (curOffset < 0) {
curOffset = 0
return
}
// load data
loadData()
}
}
// vertical scroll listener
verticalOverflow.addEventListener('scroll', (e) => {
const scrollTop = parseInt(e.target.scrollTop, 10)
scrollHeight = parseInt(e.target.scrollHeight, 10) - viewHeight
// set direction
curDirection = scrollTop > curY ? 'DOWN' : 'UP'
// set current y coordinate
curY = scrollTop
// check scroll thresholds
checkThreshold(scrollHeight)
})
</script></body>
</html>
/* wrapper */
.tableWrap {
border: solid 1px #ddd;
height: 100vh;
overflow-x: auto;
overflow-y: hidden;
position: relative;
background: #eee;
}
/* table */
table {
border-collapse: collapse;
margin: 0;
padding: 0;
border: 0;
width: 100%;
}
tr {
height: 40px;
margin: 0;
padding: 0;
border-top: solid 1px #ddd;
}
tr.heading {
border-top: none;
background: #fff;
}
td, th {
border: none;
margin: 0;
padding: 10px;
min-width: 200px;
max-width: 200px;
overflow: hidden;
text-align: center;
}
/* grid */
.vertical-overflow {
height: 100%;
position: absolute;
top: 40px;
left: 0;
overflow-x: hidden;
overflow-y: auto;
}
.grid {
width: 100%;
height: 100%;
margin-bottom: 40px;
}
// globals
let curY = 0
let curDirection = 'DOWN'
let curOffset = 0
let data = []
let scrollHeight = 0
const maxRows = 40
const verticalOverflow = document.querySelector('.vertical-overflow')
const tableWrap = document.querySelector('.tableWrap')
// example data
const createRows = data =>
data.reduce((acc, d) => {
acc += `<tr>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
<td>${d}</td>
</tr>`
return acc
}, '')
const createData = (offsetRows = []) => {
let counter = 0
let dataVal = curOffset
data = []
while (counter < maxRows) {
dataVal += 1
data.push(dataVal)
counter++
}
counter = 0
const rowData = curDirection === 'DOWN' ?
offsetRows.concat(data) :
data.concat(offsetRows)
document.querySelector('.grid').innerHTML = createRows(rowData)
}
createData()
// calculations
const viewHeight = parseInt(
getComputedStyle(tableWrap).height,
10
)
const tdHeight = parseInt(
document.querySelector('.grid td').getBoundingClientRect().top,
10
)
// get offset rows
const getNumOffsetRows = () => Math.floor(viewHeight / tdHeight)
// data loader
const loadData = () => {
const numOffsetRows = curOffset > 0 ? getNumOffsetRows() : 0
let offsetRows = curDirection === 'DOWN' ?
data.slice(data.length - numOffsetRows - 1, data.length) :
data.slice(0, numOffsetRows)
createData(offsetRows)
scrollGrid()
}
const scrollGrid = () => {
const y = curDirection === 'DOWN' ? tdHeight : scrollHeight - tdHeight
verticalOverflow.scrollTop = y
}
// check threshold
const checkThreshold = (scrollHeight) => {
if (curY === scrollHeight && curDirection === 'DOWN') {
curOffset += maxRows
// load data
loadData()
} else if (curY === 0 && curDirection === 'UP') {
curOffset -= maxRows
if (curOffset < 0) {
curOffset = 0
return
}
// load data
loadData()
}
}
// vertical scroll listener
verticalOverflow.addEventListener('scroll', (e) => {
const scrollTop = parseInt(e.target.scrollTop, 10)
scrollHeight = parseInt(e.target.scrollHeight, 10) - viewHeight
// set direction
curDirection = scrollTop > curY ? 'DOWN' : 'UP'
// set current y coordinate
curY = scrollTop
// check scroll thresholds
checkThreshold(scrollHeight)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment