Intersection Observer - amark/gun GitHub Wiki
If you're willing to help out with this, message Mark on X:
Intersection Observers is an API that can be used to detect when HTML element's become visible on screen. SecureRender's CSS3 fallback renderer ( sandbox.js lines ~300) need to detect that, pretend we have 1000 boxes (pretend the Lego bricks in Code from Phone), if we scroll down such that the TOP of our screen goes 1px past the BOTTOM of a box that we REMOVE the box from the DOM and any of its scroll-contributing height (multiple boxes might exist on 1 line, so its only the highest of each box in a line for example) gets added to a ::before SecureRender (or body) hidden height buffering element so that the scrollbar looks like we're at the same correct height but none of the boxes above the screen actually exist in DOM. So as we scroll and boxes go above the screen, they get removed from DOM without any noticeable glitching of scroll position or document height. Likewise when we scroll back up, the intersection observer needs to remember to re-inject those boxes back into the DOM before their BOTTOM's should display on screen, again, without any noticeable visual glitching of scroll or page height. This same thing is true but also for the TOP of boxes as they scroll BELOW the screen, all boxes below the screen need to be removed from DOM and then re-injected as we scroll down BEFORE their tops would become visible on screen.
A few things to note here:
Use whatever buffering % you find is necessary to prevent visual glitching, like if 1px above/below is too janky on fast scrolling, then of course it doesn't have to be exact, I'm kinda guessing that +20% -20% probably will have to actually exist in DOM since DOM is slow.
The boxes are still "in memory" in SecureRender, but note: These in-memory boxes will eventually be managed by Book such that if there are too many of them in-memory they get swapped to disk. This means we theoretically won't have any limit on the number of boxes we can display except for any 1 screen at a time, with the performance goal that that could be up to 1 box per 1 pixel... so that could easily be 1M+ boxes at a time on low end older laptops, which may be hard to achieve. So be prepared to handle at least 100K boxes.
Note that infinity scroll or streaming will have to be supported, so whether these boxes are getting memory swapped by Book or streaming via GUN etc. ultimately doesn't matter.
A good approach to start is probably creating a non-SecureRender self-contained testing demo that generates X random number of DIVs that you then render their top/bottom visibility status in an animation loop so you get the "feel" of how Intersection Observer works, etc. no dependencies other than plain vanilla HTML/JS, as concise code as possible, and you then work on perfecting the DOM removal/re-injection buffering to be as silky smooth as possible. Then once this is demo-able and working we do stage 2 of integrating it into SecureRender. Especially beware of testing boxes in different layout configurations, with different nesting/parent combinations, etc.
Happy to answer any Qs or jump on a call, etc.
Here is a broken & unfinished little prototype of deleting all elements before a clicked on item and snapping buffer elements to keep the clicked on item where it is at. It doesn't handle situations where earlier taller elements cause later elements a different reflow tho.
<!DOCTYPE html>
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"></head>
<style>
:root {
--bufferH: 1px;
--bufferW: 100px;
}
html, body {
margin: 0;
padding: 0;
border: 0;
}
div {
position: relative;
float: left;
}
body::before {
content: "";
display: block;
height: var(--bufferH);
width: var(--bufferW);
background-color: red;
position: relative;
float: left;
z-index: 1;
}
</style>
<body>
<script src="https://cdn.jsdelivr.net/npm/gun/examples/jquery.js"></script>
<script>(function(){
console.log("testing...");
var css = document.documentElement.style;
var rsize = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
var rcolor = () => '#' + Math.floor(Math.random() * 16777215).toString(16);
function r(){
r.at = r.at || $(document.body);
r.at = $("<div></div>").css({width: rsize(100, 500), height: rsize(100, 500), background: rcolor()}).appendTo(1 > Math.random()? document.body : r.at);
}
window.onkeydown = r;
var i = 50; while(--i){ r() }
document.onclick = function(eve){
var at = $(eve.target);
if(!at.is('div')){ return }
var b = at[0].getBoundingClientRect();
at.prevAll().remove();
console.log(b);
$('body').css('border-top', b.y+'px solid black');
//css.setProperty('--bufferH', b.y+'px');
css.setProperty('--bufferW', b.x+'px');
}
}());</script>
</body>
</html>