Reputation: 193
I'm using the function in this JSFiddle to fetch the percentage of an element seen within the viewport on scroll (capped at 100 once user scrolls beyond it):
// Track percentage of section seen within viewport
// Assign target section to var
const element = document.getElementById('section--example');
// Calculate percentage of section in viewport
const percentageSeen = () => {
// Get the relevant measurements and positions
const viewportHeight = window.innerHeight;
const scrollTop = window.scrollY;
const elementOffsetTop = element.offsetTop;
const elementHeight = element.offsetHeight;
// Calculate percentage of the element that's been seen
const distance = (scrollTop + viewportHeight) - elementOffsetTop;
const percentage = Math.round(distance / ((viewportHeight + elementHeight) / 100));
// Restrict range between 0 — 100
return Math.min(100, Math.max(0, percentage));
}
Then, I'm attempting to use that percentageSeen
value in the following function to animate an SVG path into view on scroll:
// Get a reference to the <path>
var path = document.querySelector('#path--example');
// Get length of SVG path
var pathLength = path.getTotalLength();
// Create dashes to match the length of the SVG path
path.style.strokeDasharray = pathLength + ' ' + pathLength;
// Initially offset dashes to hide SVG entirely
path.style.strokeDashoffset = pathLength;
path.getBoundingClientRect();
// Animate SVG on section scroll
window.addEventListener('scroll', function(e) {
// Fetch percentage seen
var scrollPercentage = percentageSeen;
// Length to offset the dashes
var drawLength = pathLength * scrollPercentage;
// Draw in reverse
path.style.strokeDashoffset = pathLength - drawLength;
});
I've created a JSFiddle here with my progress — I can log the visible percentage to the console without issue, but that value doesn't seem to be accepted when used in the above scroll function. I can also reveal the SVG based on page height (commented out in the JSFiddle), but not the section height. Can anyone help point me in the right direction that'll allow the use of the percentageSeen
var in the scroll function?
Upvotes: 0
Views: 970
Reputation: 2628
percentageSeen
is a percentage. When you multiply pathLength
by percentageSeen
you get a value that is 100 times larger than the value you want.scrollPercentage
did not store the result, but the function itself.strokeDasharray
to 0 pathLength
and then drawLength (pathLength-drawLenght)
.percentageSeen
at 100, which means that the last capping procedure is not necessary (also, you set the cap at 0.99 and you should have set it to 99).I have forked the fiddle with a working example. As you can see, percentageSeen
is never lower than 38 or larger than 61. You may want to fix the calculation.
// Animation — Stitch [Scroll]
// Reference: https://css-tricks.com/scroll-drawing/
// --------------------------------------------------
// Track percentage of animation container (section) in viewport
// Assign target section to var
const element = document.getElementById('section--example');
// Log percentage to console
const logPercentageSeen = () => {
//console.log(percentageSeen());
}
// Re-run 'logPercentageSeen' on scroll
window.addEventListener('scroll', logPercentageSeen);
// Calculate percentage of section in viewport
const percentageSeen = () => {
// Get the relevant measurements and positions
const viewportHeight = window.innerHeight;
const scrollTop = window.scrollY;
const elementOffsetTop = element.offsetTop;
const elementHeight = element.offsetHeight;
// Calculate percentage of the element that's been seen
const distance = (scrollTop + viewportHeight) - elementOffsetTop;
const percentage = Math.round(distance / ((viewportHeight + elementHeight) / 100));
// Restrict the range to between 0 and 100
return Math.min(100, Math.max(0, percentage));
}
// Log the initial value before any scrolling has happened
logPercentageSeen();
// Get a reference to the <path>
var path = document.querySelector('#path--example');
// Get length of path
var pathLength = path.getTotalLength();
// Make very long dashes (the length of the path itself)
path.style.strokeDasharray = '0 ' + pathLength;
// Offset the dashes so the it appears hidden entirely
path.style.strokeDashoffset = 0;
// Jake Archibald says so
// https://jakearchibald.com/2013/animated-line-drawing-svg/
path.getBoundingClientRect();
// When the page scrolls...
window.addEventListener('scroll', function(e) {
// What % down is it?
var scrollPercentage = percentageSeen();
// This runs, but is tied to the page height, NOT the section height
// var scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
// Length to offset the dashes
var drawLength = pathLength * scrollPercentage / 100;
// Draw in reverse
var rest = pathLength - drawLength;
path.style.strokeDasharray = drawLength + ' ' + rest;
// When complete, remove the dash array, otherwise shape isn't quite sharp
// Accounts for fuzzy math
});
<section id="section--example">
<h1>Section heading</h1>
<p>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.</p>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300" height="300"
viewBox="0 0 900 512" style="enable-background:new 0 0 900 512;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:1.24;stroke-miterlimit:10;}
</style>
<path id="path--example" class="st0" d="M30.5,58.3c0,0,60.4-124,372,4.3c109.4,45,230.4,82.8,350.2,76.8c33.5-1.7,76.9-4.2,101.8-28.6
c25.6-25.1,17.3-60.8-11-79.5c-63.6-42.1-221,5.4-354.8,74.4c-40.3,21.1-81.4,40.7-122.9,59.4c-57.5,25.9-116,53.7-179.2,62.3
C153.5,232,67.6,238,61.5,189.2c-5.9-47,80-58.5,111.4-54.4c41,5.4,112.1,14,282.5,100.3c58.8,29.8,123.4,52.2,189.8,55.2
c29.2,1.3,91.5,2.8,104.1-31.5c8.1-22.1-9.3-42.5-30-46.9c-23.5-5-49.5,1.5-72.1,8c-45,12.9-88.3,32.2-130.6,52.3
c-26.8,12.8-53.4,26.2-79.5,40.5c0,0-87.3,49.6-140.2,49.6c-17.4,0-39.6-1.3-53.5-13.5c-13.1-11.6-13-30.9,2-41.3
c36.8-25.8,86,3.2,119.9,20.7c25.1,13,49.8,26.9,73.9,41.7c0,0,45.3,28,96,28c13.6,0,30.7-2.8,32-19.8c1.1-15.6-16.7-25.9-30-28
c-22.5-3.5-43.6,8.8-58,25.2c-41,46.4-18.3,114.3,25.9,133.7"/>
</svg>
<p>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.</p>
</section>
Upvotes: 1