Responsive Infinite Heirarchal List
by skibulk
HTML
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
<div id="heirarchy-outer">
<div id="heirarchy-inner"></div>
</div>
CSS
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
}
#heirarchy-outer {
height: 400px;
margin: 40px;
overflow-y: scroll;
overflow-x: hidden;
}
.level {
width: 100%;
}
.level .level {
margin-left: 10%;
margin-right: -10%;
}
.content {
border: 1px solid lightgray;
padding: 5px 10px;
margin-right: 10%;
}
JavaScript
var $heirarchy_outer = $('#heirarchy-outer'),
$heirarchy_inner = $('#heirarchy-inner'),
$prevEl = $heirarchy_inner,
$nextEl;
// Generate Example Heirarchal Content
function addRow(i) {
$nextEl = $('<div class="level"><div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi consectetur fringilla nisi vel tempor.</div></div>');
$prevEl.append($nextEl);
$prevEl = $nextEl;
}
for (var i = 0; i < 30; i++) {
addRow(i);
}
// Scroll State Data
var prev_width = $heirarchy_outer.width(),
target_el = $('.content').first(),
target_spacer = 0,
target_margin = 0;
// Check if element is inside parent's top and bottom boundaries
function isScrolledIntoView(child, parent) {
child = child.getBoundingClientRect();
parent = parent.getBoundingClientRect();
// Return true if child is partially visible
// return (child.bottom >= parent.top) && (child.top <= parent.bottom);
// Return true if child is completely visible
return (child.top >= parent.top) && (child.bottom <= parent.bottom);
}
// On Scroll-Y, Automatically calculate scroll-X
$heirarchy_outer.scroll(function(event) {
// Check for intentional scrolling (not from resizing)
if (prev_width == $heirarchy_outer.width()) {
// For each node in the heirarchy
$('.content').each(function(index, item) {
// Check if the node is scrolled into view
if (isScrolledIntoView(item, $heirarchy_outer[0])) {
// Save scroll state data
target_el = item;
target_spacer = item.getBoundingClientRect().top - $heirarchy_outer[0].getBoundingClientRect().top;
return false;
}
});
} else {
// Automatic scrolling (from resizing)
prev_width = $heirarchy_outer.width();
}
// Already at the correct position?
var margin = target_el.getBoundingClientRect().left - $heirarchy_inner[0].getBoundingClientRect().left;
if (margin != target_margin) {
target_margin = margin;
console.log('scroll-x');
//...