Skip to content

Instantly share code, notes, and snippets.

@veggiemonk
Forked from anonymous/index.html
Created November 17, 2015 10:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save veggiemonk/03eb34852725dd963a96 to your computer and use it in GitHub Desktop.
Save veggiemonk/03eb34852725dd963a96 to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/secaq
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<script src="https://rawgit.com/lhorie/mithril.js/next/mithril.js"></script>
<script id="jsbin-javascript">
// noprotect
function occluder(children) {
var childrenHeights;
var containerHeight;
var viewport, offset;
var ready = false;
var dom, container;
var occlusion = [];
function scroller(el, isInit) {
if (!isInit) {
el.addEventListener("scroll", scroll);
viewport = el.offsetHeight;
}
}
function setup(el, isInit) {
dom = Array.prototype.slice.call(el.childNodes);
childrenHeights = [];
containerHeight = 0;
for (var height, i = 0; i < el.childNodes.length; i++) {
height = el.childNodes[i].getBoundingClientRect().height;
childrenHeights.push(height);
containerHeight += height;
}
ready = true;
console.log("REDRAW!!!!");
( requestAnimationFrame || setTimeout )( m.redraw );
}
function scroll(e) {
offset = e.target.scrollTop;
var newOcclusion = calculateOcclusion();
if (newOcclusion[newOcclusion.length - 1] != occlusion[occlusion.length - 1] || newOcclusion[0] != occlusion[0]) {
occlusion = newOcclusion;
console.time("redraw");
update();
console.timeEnd("redraw");
}
}
function restart() {
ready = false;
m.redraw(true);
}
function view(template) {
console.log("READY", ready);
if (ready) {
return m("", {config: setContainer, style: {position: "relative", height: containerHeight + "px"}})
} else {
return m("", {config: setup}, children.map(template));
}
}
function setContainer(el) {
console.log("Set container to", el);
container = el;
update();
}
function update() {
var inner = document.createElement("div");
inner.style.position = "relative";
inner.style.top = offset + "px";
container.style.top = "-" + topOffset() + "px";
for (var i = 0; i < occlusion.length; i++) {
inner.appendChild(dom[occlusion[i]]);
}
container.innerHTML = "";
container.appendChild(inner);
}
function calculateOcclusion() {
var past = 0;
var shown = [];
for (var i = 0; i < children.length; i++) {
var height = childrenHeights[i];
if (offset >= past + height) {
past += height;
} else if(past < offset + viewport) {
past += height;
shown.push(i);
} else {
break;
}
}
return shown;
}
function occlusionStyle() {
return {
position: "relative",
height: containerHeight + "px",
top: "-" + topOffset() + "px"
};
}
function topOffset() {
var past = 0;
for (var i = 0; i < childrenHeights.length; i++) {
if (past + childrenHeights[i] > offset) {
return offset - past;
} else {
past += childrenHeights[i];
}
}
}
return {
view: view,
restart: restart,
scroller: scroller
};
}
var items = []
for(var i = 0; i < 5000; i++) {
items.push({
title: 'Foo Bar ' + i
})
}
var app = {
controller: function() {
return {
occlusion: occluder(items)
}
},
view: function(scope) {
console.log("VIEW");
return m(".scroller", {
config: scope.occlusion.scroller,
style: {overflow: "auto", height: "500px"}
}, scope.occlusion.view(function(item) {
return m("", item.title);
})
)
}
}
m.mount(document.body, app);
</script>
<script id="jsbin-source-javascript" type="text/javascript">// noprotect
function occluder(children) {
var childrenHeights;
var containerHeight;
var viewport, offset;
var ready = false;
var dom, container;
var occlusion = [];
function scroller(el, isInit) {
if (!isInit) {
el.addEventListener("scroll", scroll);
viewport = el.offsetHeight;
}
}
function setup(el, isInit) {
dom = Array.prototype.slice.call(el.childNodes);
childrenHeights = [];
containerHeight = 0;
for (var height, i = 0; i < el.childNodes.length; i++) {
height = el.childNodes[i].getBoundingClientRect().height;
childrenHeights.push(height);
containerHeight += height;
}
ready = true;
console.log("REDRAW!!!!");
( requestAnimationFrame || setTimeout )( m.redraw );
}
function scroll(e) {
offset = e.target.scrollTop;
var newOcclusion = calculateOcclusion();
if (newOcclusion[newOcclusion.length - 1] != occlusion[occlusion.length - 1] || newOcclusion[0] != occlusion[0]) {
occlusion = newOcclusion;
console.time("redraw");
update();
console.timeEnd("redraw");
}
}
function restart() {
ready = false;
m.redraw(true);
}
function view(template) {
console.log("READY", ready);
if (ready) {
return m("", {config: setContainer, style: {position: "relative", height: containerHeight + "px"}})
} else {
return m("", {config: setup}, children.map(template));
}
}
function setContainer(el) {
console.log("Set container to", el);
container = el;
update();
}
function update() {
var inner = document.createElement("div");
inner.style.position = "relative";
inner.style.top = offset + "px";
container.style.top = "-" + topOffset() + "px";
for (var i = 0; i < occlusion.length; i++) {
inner.appendChild(dom[occlusion[i]]);
}
container.innerHTML = "";
container.appendChild(inner);
}
function calculateOcclusion() {
var past = 0;
var shown = [];
for (var i = 0; i < children.length; i++) {
var height = childrenHeights[i];
if (offset >= past + height) {
past += height;
} else if(past < offset + viewport) {
past += height;
shown.push(i);
} else {
break;
}
}
return shown;
}
function occlusionStyle() {
return {
position: "relative",
height: containerHeight + "px",
top: "-" + topOffset() + "px"
};
}
function topOffset() {
var past = 0;
for (var i = 0; i < childrenHeights.length; i++) {
if (past + childrenHeights[i] > offset) {
return offset - past;
} else {
past += childrenHeights[i];
}
}
}
return {
view: view,
restart: restart,
scroller: scroller
};
}
var items = []
for(var i = 0; i < 5000; i++) {
items.push({
title: 'Foo Bar ' + i
})
}
var app = {
controller: function() {
return {
occlusion: occluder(items)
}
},
view: function(scope) {
console.log("VIEW");
return m(".scroller", {
config: scope.occlusion.scroller,
style: {overflow: "auto", height: "500px"}
}, scope.occlusion.view(function(item) {
return m("", item.title);
})
)
}
}
m.mount(document.body, app);
</script></body>
</html>
// noprotect
function occluder(children) {
var childrenHeights;
var containerHeight;
var viewport, offset;
var ready = false;
var dom, container;
var occlusion = [];
function scroller(el, isInit) {
if (!isInit) {
el.addEventListener("scroll", scroll);
viewport = el.offsetHeight;
}
}
function setup(el, isInit) {
dom = Array.prototype.slice.call(el.childNodes);
childrenHeights = [];
containerHeight = 0;
for (var height, i = 0; i < el.childNodes.length; i++) {
height = el.childNodes[i].getBoundingClientRect().height;
childrenHeights.push(height);
containerHeight += height;
}
ready = true;
console.log("REDRAW!!!!");
( requestAnimationFrame || setTimeout )( m.redraw );
}
function scroll(e) {
offset = e.target.scrollTop;
var newOcclusion = calculateOcclusion();
if (newOcclusion[newOcclusion.length - 1] != occlusion[occlusion.length - 1] || newOcclusion[0] != occlusion[0]) {
occlusion = newOcclusion;
console.time("redraw");
update();
console.timeEnd("redraw");
}
}
function restart() {
ready = false;
m.redraw(true);
}
function view(template) {
console.log("READY", ready);
if (ready) {
return m("", {config: setContainer, style: {position: "relative", height: containerHeight + "px"}})
} else {
return m("", {config: setup}, children.map(template));
}
}
function setContainer(el) {
console.log("Set container to", el);
container = el;
update();
}
function update() {
var inner = document.createElement("div");
inner.style.position = "relative";
inner.style.top = offset + "px";
container.style.top = "-" + topOffset() + "px";
for (var i = 0; i < occlusion.length; i++) {
inner.appendChild(dom[occlusion[i]]);
}
container.innerHTML = "";
container.appendChild(inner);
}
function calculateOcclusion() {
var past = 0;
var shown = [];
for (var i = 0; i < children.length; i++) {
var height = childrenHeights[i];
if (offset >= past + height) {
past += height;
} else if(past < offset + viewport) {
past += height;
shown.push(i);
} else {
break;
}
}
return shown;
}
function occlusionStyle() {
return {
position: "relative",
height: containerHeight + "px",
top: "-" + topOffset() + "px"
};
}
function topOffset() {
var past = 0;
for (var i = 0; i < childrenHeights.length; i++) {
if (past + childrenHeights[i] > offset) {
return offset - past;
} else {
past += childrenHeights[i];
}
}
}
return {
view: view,
restart: restart,
scroller: scroller
};
}
var items = []
for(var i = 0; i < 5000; i++) {
items.push({
title: 'Foo Bar ' + i
})
}
var app = {
controller: function() {
return {
occlusion: occluder(items)
}
},
view: function(scope) {
console.log("VIEW");
return m(".scroller", {
config: scope.occlusion.scroller,
style: {overflow: "auto", height: "500px"}
}, scope.occlusion.view(function(item) {
return m("", item.title);
})
)
}
}
m.mount(document.body, app);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment