-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvanilla-js-demo.html
More file actions
139 lines (126 loc) · 7.34 KB
/
Copy pathvanilla-js-demo.html
File metadata and controls
139 lines (126 loc) · 7.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Basic Virtual Scroll · Cerious-Scroll</title>
<link rel="stylesheet" href="shared-styles.css?v=20260922">
</head>
<body>
<header class="topbar" data-auto-topbar></header>
<main class="content">
<div class="demo-page">
<div class="demo-page__header">
<h1><span data-demo-icon="basic"></span>Basic virtual scroll</h1>
<p>Lazy data source, no array is allocated, so a million rows costs nothing.</p>
</div>
<div class="demo-toolbar">
<label for="size">Rows</label>
<select id="size">
<option value="100">100</option>
<option value="1000">1,000</option>
<option value="10000">10,000</option>
<option value="100000" selected>100,000</option>
<option value="1000000">1,000,000</option>
</select>
<label for="var">Heights</label>
<select id="var">
<option value="uniform">Uniform (44px)</option>
<option value="mixed" selected>Mixed (44/64/104px)</option>
<option value="variable">Variable (32–152px)</option>
</select>
<span style="display: inline-flex; gap: 6px">
<input id="jump" type="number" placeholder="row #" style="width: 110px">
<button id="goBtn" type="button">Go</button>
<button id="topBtn" type="button">Top</button>
<button id="endBtn" type="button">End</button>
</span>
<span class="spacer"></span>
<span class="stat" id="stat">scroll to see live stats</span>
</div>
<div class="demo-scroll" id="scroll"></div>
<div class="demo-footer">
<span>Total: <strong id="totalLabel">100,000</strong></span>
<span>Mode: <strong id="modeLabel">mixed</strong></span>
</div>
</div>
</main>
<script src="dist/cerious-scroll.bundle.js?v=20260922"></script>
<script src="demo-icons.js?v=20260922"></script>
<script src="demo-docs.js?v=20260922"></script>
<script src="demo-bootstrap.js?v=20260922"></script>
<script>
(function () {
const PALETTE = ['#1f6feb', '#238636', '#a371f7', '#db6d28', '#cf222e', '#0969da'];
const { hash } = window.demoUtils;
let variation = 'mixed';
let total = 100000;
function heightFor(index) {
if (variation === 'uniform') return 44;
if (variation === 'mixed') return [44, 64, 104][index % 3];
return 32 + Math.floor(hash(index, 7) * 120);
}
function render(index, container) {
const h = heightFor(index);
const color = PALETTE[index % PALETTE.length];
const row = document.createElement('div');
row.className = 'basic-row';
row.style.height = h + 'px';
row.style.borderLeftColor = color;
row.innerHTML =
'<span class="basic-row__index">#' + index.toLocaleString() + '</span>' +
'<span class="basic-row__bar" style="background:' + color + ';width:' + (30 + (index % 60)) + '%"></span>' +
'<span class="basic-row__meta">' + h + 'px</span>';
container.appendChild(row);
}
const demo = window.mountDemo({
host: document.getElementById('scroll'),
total: total,
render: render,
onViewport: (v) => {
document.getElementById('stat').textContent =
'top row ' + v.currentElement.toLocaleString() + ' · ' + v.percentage.toFixed(1) + '%';
},
});
document.getElementById('size').addEventListener('change', (e) => {
total = parseInt(e.target.value, 10);
document.getElementById('totalLabel').textContent = total.toLocaleString();
demo.setTotal(total);
});
document.getElementById('var').addEventListener('change', (e) => {
variation = e.target.value;
document.getElementById('modeLabel').textContent = variation;
demo.refresh();
});
document.getElementById('goBtn').addEventListener('click', () => {
const i = parseInt(document.getElementById('jump').value, 10);
if (Number.isFinite(i)) demo.jumpTo(i);
});
document.getElementById('topBtn').addEventListener('click', () => demo.scrollToPercentage(0));
document.getElementById('endBtn').addEventListener('click', () => demo.scrollToPercentage(100));
})();
</script>
<!-- "How to build this": the options this demo exists to show,
pulled out of the page source and put next to the demo. -->
<script>
// Deferred on some pages, inline on others: either way this runs
// before demo-docs.js has executed unless we wait for it.
(function (config) {
function mount() { window.demoDocs(config); }
if (window.demoDocs) mount();
else document.addEventListener('DOMContentLoaded', mount);
}({
"feature": "The base case: host, total, render",
"intro": "Everything else on this site is a variation on these three arguments. You give the engine a host element, how many items exist, and a function that fills one element for a given index. It mounts only what is visible and recycles elements as the window moves, so the DOM node count is a function of your viewport, never of your dataset. Heights are <em>measured</em>, never estimated, which is why a million rows of unpredictable height behaves the same as a million uniform ones.",
"code": "\n const scroller = new CeriousScroll(host, 1000000, {\n // Called with a RECYCLED container. Fill it in; do not append blindly,\n // or the row will accumulate the content of every index it has held.\n render: function (index, container) {\n container.textContent = '';\n const row = document.createElement('div');\n row.className = 'row';\n row.textContent = 'Row #' + index;\n container.appendChild(row);\n }\n });\n\n scroller.jumpToElement(750000); // O(1), no matter the dataset size\n scroller.updateTotalElements(2000000);\n ",
"notes": [
"The renderer is called for a recycled element. Clearing it first is the simplest correct thing; reusing child nodes is the fastest.",
"Row heights are measured from the DOM. You do not need to declare them, and they may differ per row.",
"<code>jumpToElement</code> is constant-time. The camera is an <code>(element, offset)</code> pair, so there is no pixel total to compute.",
"<code>updateTotalElements</code> grows or shrinks the dataset in place without moving the camera."
],
"docs": "https://github.com/ceriousdevtech/cerious-scroll/blob/main/docs/IMPLEMENTATION_GUIDE.md"
}));
</script>
</body>
</html>