diff --git a/progress-nav/script.js b/progress-nav/script.js index 2c1117d..4abc7d3 100644 --- a/progress-nav/script.js +++ b/progress-nav/script.js @@ -1,128 +1,92 @@ window.onload = function() { - var toc = document.querySelector( '.toc' ); - var tocPath = document.querySelector( '.toc-marker path' ); - var tocItems; + const toc = document.querySelector('.toc'); + const tocPath = document.querySelector('.toc-marker path'); + let tocItems = []; - // Factor of screen size that the element must cross - // before it's considered visible - var TOP_MARGIN = 0.1, - BOTTOM_MARGIN = 0.2; + const TOP_MARGIN = 0.1, + BOTTOM_MARGIN = 0.2; - var pathLength; + let pathLength, lastPathStart, lastPathEnd; - var lastPathStart, - lastPathEnd; + window.addEventListener('resize', drawPath); + window.addEventListener('scroll', sync); - window.addEventListener( 'resize', drawPath, false ); - window.addEventListener( 'scroll', sync, false ); + drawPath(); - drawPath(); + function drawPath() { + tocItems = Array.from(toc.querySelectorAll('li')).map(item => { + const anchor = item.querySelector('a'); + const target = document.getElementById(anchor.getAttribute('href').slice(1)); - function drawPath() { + return { listItem: item, anchor, target }; + }).filter(item => item.target); - tocItems = [].slice.call( toc.querySelectorAll( 'li' ) ); + let path = []; + let pathIndent; - // Cache element references and measurements - tocItems = tocItems.map( function( item ) { - var anchor = item.querySelector( 'a' ); - var target = document.getElementById( anchor.getAttribute( 'href' ).slice( 1 ) ); + tocItems.forEach((item, i) => { + const x = item.anchor.offsetLeft - 5, + y = item.anchor.offsetTop, + height = item.anchor.offsetHeight; - return { - listItem: item, - anchor: anchor, - target: target - }; - } ); + if (i === 0) { + path.push(`M${x},${y}L${x},${y + height}`); + item.pathStart = 0; + } else { + if (pathIndent !== x) path.push(`L${pathIndent},${y}`); - // Remove missing targets - tocItems = tocItems.filter( function( item ) { - return !!item.target; - } ); + path.push(`L${x},${y}`); - var path = []; - var pathIndent; + tocPath.setAttribute('d', path.join(' ')); + item.pathStart = tocPath.getTotalLength() || 0; - tocItems.forEach( function( item, i ) { + path.push(`L${x},${y + height}`); + } - var x = item.anchor.offsetLeft - 5, - y = item.anchor.offsetTop, - height = item.anchor.offsetHeight; + pathIndent = x; - if( i === 0 ) { - path.push( 'M', x, y, 'L', x, y + height ); - item.pathStart = 0; - } - else { - // Draw an additional line when there's a change in - // indent levels - if( pathIndent !== x ) path.push( 'L', pathIndent, y ); + tocPath.setAttribute('d', path.join(' ')); + item.pathEnd = tocPath.getTotalLength(); + }); - path.push( 'L', x, y ); + pathLength = tocPath.getTotalLength(); + sync(); + } - // Set the current path so that we can measure it - tocPath.setAttribute( 'd', path.join( ' ' ) ); - item.pathStart = tocPath.getTotalLength() || 0; + function sync() { + const windowHeight = window.innerHeight; - path.push( 'L', x, y + height ); - } + let pathStart = pathLength, + pathEnd = 0, + visibleItems = 0; - pathIndent = x; + tocItems.forEach(item => { + const { top, bottom } = item.target.getBoundingClientRect(); - tocPath.setAttribute( 'd', path.join( ' ' ) ); - item.pathEnd = tocPath.getTotalLength(); + if (bottom > windowHeight * TOP_MARGIN && top < windowHeight * (1 - BOTTOM_MARGIN)) { + pathStart = Math.min(item.pathStart, pathStart); + pathEnd = Math.max(item.pathEnd, pathEnd); + visibleItems++; - } ); + item.listItem.classList.add('visible'); + } else { + item.listItem.classList.remove('visible'); + } + }); - pathLength = tocPath.getTotalLength(); + if (visibleItems > 0 && pathStart < pathEnd) { + if (pathStart !== lastPathStart || pathEnd !== lastPathEnd) { + tocPath.setAttribute('stroke-dashoffset', '1'); + tocPath.setAttribute('stroke-dasharray', `1, ${pathStart}, ${pathEnd - pathStart}, ${pathLength}`); + tocPath.setAttribute('opacity', 1); + } + } else { + tocPath.setAttribute('opacity', 0); + } - sync(); + lastPathStart = pathStart; + lastPathEnd = pathEnd; + } - } - - function sync() { - - var windowHeight = window.innerHeight; - - var pathStart = pathLength, - pathEnd = 0; - - var visibleItems = 0; - - tocItems.forEach( function( item ) { - - var targetBounds = item.target.getBoundingClientRect(); - - if( targetBounds.bottom > windowHeight * TOP_MARGIN && targetBounds.top < windowHeight * ( 1 - BOTTOM_MARGIN ) ) { - pathStart = Math.min( item.pathStart, pathStart ); - pathEnd = Math.max( item.pathEnd, pathEnd ); - - visibleItems += 1; - - item.listItem.classList.add( 'visible' ); - } - else { - item.listItem.classList.remove( 'visible' ); - } - - } ); - - // Specify the visible path or hide the path altogether - // if there are no visible items - if( visibleItems > 0 && pathStart < pathEnd ) { - if( pathStart !== lastPathStart || pathEnd !== lastPathEnd ) { - tocPath.setAttribute( 'stroke-dashoffset', '1' ); - tocPath.setAttribute( 'stroke-dasharray', '1, '+ pathStart +', '+ ( pathEnd - pathStart ) +', ' + pathLength ); - tocPath.setAttribute( 'opacity', 1 ); - } - } - else { - tocPath.setAttribute( 'opacity', 0 ); - } - - lastPathStart = pathStart; - lastPathEnd = pathEnd; - - } - -}; \ No newline at end of file +};