diff --git a/web/views/timeline.ejs b/web/views/timeline.ejs index 9e1d4dd..5426b60 100644 --- a/web/views/timeline.ejs +++ b/web/views/timeline.ejs @@ -431,6 +431,7 @@ var nodes = Array.prototype.slice.call(timeline.querySelectorAll('.timeline-node')); var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; var drawProgress = 0; // 0 to 1, how much of the line is drawn + var maxDrawProgress = 0; var ticking = false; // Build a rounded-corner path that threads through a list of points. @@ -490,22 +491,6 @@ comet.style.opacity = 1; } - // Reveal a node once the drawn line has reached its anchor. - function revealNodes() { - var len = progress.getTotalLength(); - var drawnLen = len * drawProgress; - nodes.forEach(function (node) { - if (node.classList.contains('is-visible')) return; - var marker = node.querySelector('.timeline-marker'); - var r = (marker || node).getBoundingClientRect(); - var box = timeline.getBoundingClientRect(); - var pt = { x: r.left - box.left + r.width / 2, y: r.top - box.top + r.height / 2 }; - // approximate the node's distance along the path - var nodeLen = lengthAtPoint(pt, len); - if (drawnLen >= nodeLen - 8) node.classList.add('is-visible'); - }); - } - // Find roughly how far along the path a point sits (coarse sampling). var _samples = null; function lengthAtPoint(target, len) { @@ -526,23 +511,34 @@ return best; } - function clamp(value, min, max) { - return Math.max(min, Math.min(max, value)); - } - function updateFromScroll() { ticking = false; var len = progress.getTotalLength(); - var rect = timeline.getBoundingClientRect(); var viewport = window.innerHeight || document.documentElement.clientHeight; - var start = viewport * 0.35; - var end = -rect.height + viewport * 0.45; - var raw = (start - rect.top) / (start - end); + var revealLine = viewport * 0.9; + var targetProgress = maxDrawProgress; - drawProgress = clamp(raw, 0, 1); + nodes.forEach(function (node, index) { + var cardRect = node.getBoundingClientRect(); + if (cardRect.top > revealLine) return; + + node.classList.add('is-visible'); + + var marker = node.querySelector('.timeline-marker'); + var markerRect = (marker || node).getBoundingClientRect(); + var box = timeline.getBoundingClientRect(); + var pt = { + x: markerRect.left - box.left + markerRect.width / 2, + y: markerRect.top - box.top + markerRect.height / 2 + }; + var nodeProgress = index === nodes.length - 1 ? 1 : lengthAtPoint(pt, len) / len; + targetProgress = Math.max(targetProgress, nodeProgress); + }); + + maxDrawProgress = Math.max(maxDrawProgress, targetProgress); + drawProgress = maxDrawProgress; progress.style.strokeDashoffset = len * (1 - drawProgress); updateComet(len); - revealNodes(); if (drawProgress >= 1) { comet.style.opacity = 0; nodes.forEach(function (n) { n.classList.add('is-visible'); });