Make the on Scroll Growing <Path> to Dashed Line

Make the on scroll growing path to dashed line

There is a way to do it. You can use a dashed line as a mask for the animated line.

// Get the id of the <path> element and the length of <path>var myline = document.getElementById("myline");var length = myline.getTotalLength();circle = document.getElementById("circle");// The start position of the drawingmyline.style.strokeDasharray = length;
// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll drawmyline.style.strokeDashoffset = length;
// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolledwindow.addEventListener("scroll", myFunction);
function myFunction() { // What % down is it? var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight); // Length to offset the dashes var draw = length * scrollpercent;
// Reverse the drawing (when scrolling upwards) myline.style.strokeDashoffset = length - draw;
//get point at length endPoint = myline.getPointAtLength(draw); circle.setAttribute("cx", endPoint.x); circle.setAttribute("cy", endPoint.y);
}
body {  height: 2000px;  background: #f1f1f1;}
#circle { fill: red;}
#mySVG { position: fixed; top: 15%; width: 100vw; height: 100vh; margin-left: -50px;}
.st0 { fill: none; stroke-dashoffset: 3px; stroke: red; stroke-width: 5; stroke-miterlimit: 10; stroke-dasharray: 20;}
.mask-style { stroke: white; stroke-width: 7;}
<h2>Scroll down this window to draw my path.</h2><p>Scroll back up to reverse the drawing.</p>
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible"> <defs> <mask id="dash-mask"> <path class="st0 mask-style" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> </mask> </defs> <circle id="circle" cx="10" cy="10" r="10"/> <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" mask="url(#dash-mask)"/> Sorry, your browser does not support inline SVG.</svg>

Drawing a curved dashed line SVG on scroll

With your link to Snap.svg I came up with this solution:

<script src="./snap.svg.js"></script>
<script>

var line;
var subPaths = [];
var percentDrawn = 0;

window.onload = function(){
line = Snap(document.getElementById("drawMe"));
getSubPaths();
loop();
}

function loop(){
setTimeout(function(){
line.attr({
d: subPaths[percentDrawn]
});
percentDrawn++;
if( percentDrawn < 101) loop();
}, 50);
}

function getSubPaths(){
var maxLength = line.getTotalLength();
for(var i = 0; i<101; i++){
var currentLength = maxLength*i/100;
subPaths[i] = line.getSubpath(0, currentLength);
}
}
</script>

So what we do is building up an array with sub paths of the original line from the start up to x% of it's total length: getSubPaths().
For this we actually need Snap.svg as it provides us the getSubpath(0, currentLength) functionality.

And that's actually all the magic! The loop() function is just a setTimeout block with an abort-condition once we've finished drawing. The actual drawing however is applying the corresponding subPath from the previous stored array to your line's d attribute.

Animate a circle with the growth of path on scroll

Use getPointAtLength()

Looks like another answer already suggested this :)

// Get the id of the <path> element and the length of <path>var myline = document.getElementById("myline");var length = myline.getTotalLength();circle = document.getElementById("circle");// The start position of the drawingmyline.style.strokeDasharray = length;
// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll drawmyline.style.strokeDashoffset = length;
// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolledwindow.addEventListener("scroll", myFunction);
function myFunction() { // What % down is it? var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight); // Length to offset the dashes var draw = length * scrollpercent;
// Reverse the drawing (when scrolling upwards) myline.style.strokeDashoffset = length - draw; //get point at length endPoint = myline.getPointAtLength(draw); circle.setAttribute("cx", endPoint.x); circle.setAttribute("cy", endPoint.y); }
body {  height: 2000px;  background: #f1f1f1;}
#circle{fill:red;}
#mySVG { position: fixed; top: 15%; width: 100vw; height: 100vh; margin-left: -50px;}
.st0 { fill: none; stroke-dashoffset: 3px; stroke: red; stroke-width: 5; stroke-miterlimit: 10; stroke-dasharray: 20;}
<h2>Scroll down this window to draw my path.</h2><p>Scroll back up to reverse the drawing.</p>
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible"> <circle id="circle" cx="10" cy="10" r="10"/> <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.</svg>

Animate dashed SVG line

One of the ways to do this is with Javascript. It duplicates a path by creating a polyline.
Try the example below:

<!DOCTYPE HTML><html><head><style>polyline{stroke-dasharray:8;stroke:black;fill:none;stroke-width:1;}
</style>

</head><body >This builds a smooth/dashed polylines that replicates your paths.<br><button onClick=animateDashPaths()>Animate Paths</button><br>
<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" viewBox="0 0 830 500" enable-background="new 0 0 830 500" xml:space="preserve">
<path class="path" fill="none" stroke="#000000" stroke-miterlimit="10" d="M234.3,119c-31-0.7-95,9-128.7,50.8"/>
<!-- Vienna Dash --><path id="pathVienna" display="none" stroke-miterlimit="10" d="M382.8,243.8c2.9-36.1,15.8-110.3,110.1-145.4"/>
<!-- Budapest Dash --><path id="pathBudapest" display="none" stroke-miterlimit="10" d="M550.6,319.4c34-2.7,109-2.1,174.8,50.5"/>
<!-- Salzburg Dash --><path id="pathSalzburg" display="none" stroke-miterlimit="10" d="M265,323c21.5,12.1,57.2,39.5,60.7,85.1"/>
<!-- Tyrol Dash --><path id="pathTyrol" display="none" stroke-miterlimit="10" d="M147.8,319.5 c-27.1,7-79.7,31.3-92.8,74.2"/>
</svg>
<script>//---button---function animateDashPaths(){var NS="http://www.w3.org/2000/svg"
//----Vienna----------------var endLengthVienna=pathVienna.getTotalLength()var lengthDeltaVienna=endLengthVienna/200var polylineVienna=document.createElementNS(NS,"polyline")Layer_1.appendChild(polylineVienna)var pntListVienna=polylineVienna.pointsvar iTVienna=setInterval(drawPathVienna,5)var cntVienna=0function drawPathVienna(){ var len=lengthDeltaVienna*cntVienna++ if(len<endLengthVienna) { var pnt=pathVienna.getPointAtLength(len) pntListVienna.appendItem(pnt) } else clearInterval(iTVienna)}
//----Budapest----------------var endLengthBudapest=pathBudapest.getTotalLength()var lengthDeltaBudapest=endLengthBudapest/200var polylineBudapest=document.createElementNS(NS,"polyline")Layer_1.appendChild(polylineBudapest)var pntListBudapest=polylineBudapest.pointsvar iTBudapest=setInterval(drawPathBudapest,5)var cntBudapest=0function drawPathBudapest(){ var len=lengthDeltaBudapest*cntBudapest++ if(len<endLengthBudapest) { var pnt=pathBudapest.getPointAtLength(len) pntListBudapest.appendItem(pnt) } else clearInterval(iTBudapest)}
//----Salzburg----------------var endLengthSalzburg=pathSalzburg.getTotalLength()var lengthDeltaSalzburg=endLengthSalzburg/200var polylineSalzburg=document.createElementNS(NS,"polyline")Layer_1.appendChild(polylineSalzburg)var pntListSalzburg=polylineSalzburg.pointsvar iTSalzburg=setInterval(drawPathSalzburg,5)var cntSalzburg=0function drawPathSalzburg(){ var len=lengthDeltaSalzburg*cntSalzburg++ if(len<endLengthSalzburg) { var pnt=pathSalzburg.getPointAtLength(len) pntListSalzburg.appendItem(pnt) } else clearInterval(iTSalzburg)}
//----Tyrol----------------var endLengthTyrol=pathTyrol.getTotalLength()var lengthDeltaTyrol=endLengthTyrol/200var polylineTyrol=document.createElementNS(NS,"polyline")Layer_1.appendChild(polylineTyrol)var pntListTyrol=polylineTyrol.pointsvar iTTyrol=setInterval(drawPathTyrol,5)var cntTyrol=0function drawPathTyrol(){ var len=lengthDeltaTyrol*cntTyrol++ if(len<endLengthTyrol) { var pnt=pathTyrol.getPointAtLength(len) pntListTyrol.appendItem(pnt) } else clearInterval(iTTyrol)}
}</script>
</body>
</html>

Smooth Transition of Path using Specified Styling

You could 'grow' a line making a transition from 0px to total-lenghtpx. Like so:

var points = [
[100, 10],
[100, 10]
];

var line = d3.svg.line()

var svg = d3.select("body").append("svg")
.datum(points)
.attr("width", 960)
.attr("height", 500);

svg.append("path")
.attr("id","grow")
.style("stroke-dasharray", "5,3")
.attr("d", line)
.transition()
.duration(7500) // <-- transition time
.attr("d", "M100,400L100,10") // <-- final lenght

Here the working code

Not the most optimized option. Here's a clean one:

<style>
line {
fill: none;
stroke: #000;
stroke-width: 3px;
stroke-dasharray:5 3;
}
</style>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);

svg.append('line')
.attr({
x1: 25,
y1: 400,
x2: 25,
y2: 400
})
.transition()
.duration(1500)
.attr({
x2: 25,
y2: 15
})
</script>
  • and the working code

  • with a button

  • with Scale functionality

SVG `path` javascript animation not working as expected

(Update / New answer)

I think this is exactly what you want...

Update (added easing as OP wanted):

Made increase in length of #body smooth by adding transition: stroke-dashoffset ease-in-out 0.2s; to #body

Movement of #head can't be made smooth by adding transition: cx ease-in-out 0.2s, cy ease-in-out 0.2s; on #head because that will make it jump instead of moving along the path.

If you want #head to move smoothly along the track you'll have to do it by manually implementing an easing with js, which is a lot of work. So skipped that part.

let roadmapSvg = document.getElementById("roadmap-svg");let track = document.getElementById("track");let body = document.getElementById("body");let head = document.getElementById("head");
let totalLength = track.getTotalLength();let trackPoints = [];let getTrackBounds = () => track.getBoundingClientRect();let scaleFactor;
body.style.strokeDasharray = totalLength;body.style.strokeDashoffset = totalLength;
function setScaleFactor(){ scaleFactor = roadmapSvg.getBoundingClientRect().width / roadmapSvg.viewBox.baseVal.width;} setScaleFactor();
function setTrackPoints(){ let divisions = 1000; let unitLength = totalLength / divisions; trackPoints = []; for(let i=0; i < divisions; i++){ let length = unitLength * i; let {x,y} = track.getPointAtLength(length); trackPoints.push({x: x*scaleFactor, y: y*scaleFactor, length}); }}setTrackPoints();

function draw(){ let currentLength = getCurrentLength(); body.style.strokeDashoffset = totalLength - currentLength; headPos = track.getPointAtLength(currentLength); head.setAttribute("cx", headPos.x); head.setAttribute("cy", headPos.y);}
function getCurrentLength(){ let centreY = window.innerHeight / 2; let trackBounds = getTrackBounds(); let currentY = centreY - trackBounds.y; if(currentY < 0) return 0; // if currentY is greater that track height, that means the user has scrolled pass the track (and the whole svg) in such case the animation should be completed i.e. the head should be at the final position i.e. at totalLength if(currentY > trackBounds.height) return totalLength; for(let point of trackPoints){ if(point.y >= currentY){ return point.length; } } // (For safety) Sometimes none of the conditions match bcoz of low precision... Such situation only occurs a point very close to total length... Thus... return totalLength;}
document.addEventListener("scroll", draw);
window.addEventListener("resize", () => { setScaleFactor(); setTrackPoints(); draw();});
body {  background: #f1f1f1;  margin: 0;  padding: 0 20%;  font-family: sans-serif;}
#roadmap-svg{ display: block; max-width: 600px; margin: 20px auto; overflow: visible;}
#roadmap-svg #head{ fill: red;}
#roadmap-svg #track{ fill: none; stroke-dashoffset: 3px; stroke: grey; stroke-width: 4; stroke-miterlimit: 10; stroke-dasharray: 20;}#roadmap-svg #body{ fill: none; stroke-dashoffset: 3px; stroke: red; stroke-width: 5; stroke-miterlimit: 10; stroke-dasharray: 20; transition: stroke-dashoffset ease-in-out 0.2s;}
.center-line{ position: fixed; left: 0; right: 0; top: 50%; border-top: 1px solid red; background-color: rgba(255,255,255,0.9);}
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempora in eaque rem eligendi corrupti voluptate, maxime cum cumque, eius delectus minus neque, dolorem optio cupiditate ratione! Excepturi fugit culpa quo?Cum optio error ex voluptatem rerum eius sunt, nemo necessitatibus, exercitationem voluptatum illum, rem quibusdam accusamus deserunt sed. Iste odio obcaecati enim voluptate temporibus ab illo maxime et sit minima.Odio ut dignissimos sed dicta recusandae esse, at molestiae quibusdam, consequatur aspernatur facilis, perferendis voluptatum adipisci. Dolores molestiae quos, doloribus excepturi officiis laborum ex officia reprehenderit esse perspiciatis alias itaque.Delectus illum, asperiores at a ab quibusdam corporis necessitatibus. Libero eos vero blanditiis modi cum rem maxime delectus quisquam, facilis saepe sed eius corrupti nobis sunt, unde obcaecati commodi velit.Saepe adipisci consectetur blanditiis quos enim praesentium, at magnam quibusdam nisi! Dolore, esse beatae! Enim, quam cum, qui voluptates fugiat, nihil mollitia possimus doloremque porro aspernatur nesciunt velit. Cum, adipisci?Dolores doloribus nihil delectus consequuntur id assumenda tempora, illum, earum ab quasi quaerat sequi et hic veniam excepturi eligendi quod perspiciatis voluptatem ratione reprehenderit! Corrupti minima facilis soluta adipisci animi!Iure, sed exercitationem. Quidem assumenda omnis dicta ducimus sunt, quibusdam excepturi molestias cumque! Illum ipsum perferendis dicta optio eum consequuntur soluta, corrupti nostrum est sed quaerat voluptates dolores perspiciatis? Ex!Consequatur corporis ratione beatae. Magni amet doloribus deserunt, accusamus suscipit earum accusantium perferendis adipisci inventore, ab commodi odio necessitatibus aut omnis. Et quisquam esse deleniti, reprehenderit nihil optio aperiam fugit.Aliquid error voluptatibus, quis quo eveniet nulla corrupti veniam culpa voluptas possimus tenetur nisi recusandae quae modi, animi dolores. Provident saepe nobis quos tenetur, veritatis laborum cupiditate molestias fugit consectetur.A, perspiciatis illo sequi non eos facere temporibus dignissimos blanditiis ipsum harum eius culpa adipisci est ab nobis saepe mollitia quis laboriosam tenetur, repellat molestias. Quos ipsa magni dolores rerum.</div><svg id="roadmap-svg" viewBox="0 0 760 300">  <path  id="track" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" />  <path id="body" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" />  <circle id="head" cx="10" cy="10" r="10"/></svg><div class="center-line">Center Line</div><div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente officia saepe facilis? Cupiditate rem vel, quaerat ratione ipsam magnam fugiat praesentium incidunt! Eveniet cum officia impedit obcaecati id animi rerum?Non beatae inventore quos optio temporibus ratione doloremque ullam animi dolore reiciendis sint, esse consequatur asperiores assumenda repudiandae obcaecati ab quas molestias harum eveniet amet natus ea? Ipsum, dolore suscipit.Explicabo assumenda minus, reprehenderit modi, laboriosam placeat saepe at repudiandae perferendis fugit asperiores itaque. Vero fugiat voluptas asperiores dolores dolorum quis ipsa sapiente deleniti odio, deserunt, iure voluptates. Error, tempore.Doloribus nesciunt praesentium ad aut minus aliquam aspernatur quas qui incidunt sunt, maxime tempora facilis, cum assumenda. Dolorum a tempore itaque impedit, ad, corporis tenetur enim nulla quas, harum fuga!Quae repellat, obcaecati voluptate inventore quidem, labore quo corporis repudiandae, vel doloremque perferendis numquam aliquam nisi? Vel architecto ullam fugiat error corrupti? Cumque amet illo, possimus assumenda eos unde deleniti.Enim tenetur possimus a neque, voluptatum reprehenderit, cum magni blanditiis quam atque dolorum veniam eveniet repellendus. Modi quibusdam maxime corrupti harum! Ullam vitae assumenda laboriosam nam officia eaque. Totam, dolorem.Ad sapiente itaque blanditiis, sint iusto nemo laborum corrupti cupiditate obcaecati quam ipsa quis perferendis vitae enim atque ex a ratione. Doloribus aspernatur id ipsa recusandae labore aliquid, totam aperiam?Recusandae delectus quidem, aspernatur nulla expedita accusantium quod praesentium inventore qui, pariatur ullam maxime! Numquam, sed sequi rem voluptates asperiores qui, culpa nesciunt magnam, quas doloribus praesentium et adipisci tempora.Veniam, placeat vel nesciunt recusandae voluptates laboriosam totam doloremque saepe. Nam quo similique vero esse possimus architecto officiis harum ratione perspiciatis dolor ut, molestias odit consequatur quam asperiores? Id, quasi!Ex expedita impedit aliquam et commodi voluptatibus, consequatur voluptate ea explicabo deserunt. Sapiente quo consequuntur enim dolores ea officia. Inventore ipsa dignissimos iste qui magnam reiciendis eveniet optio laudantium fugiat!</div>

Animated line drawing (SVG) with CSS

Maybe you should use getTotalLength() to get the current path length.
Then, this script is an example where the line grows until the middle of the scroll, then it disappears like in your drawings.

Here is a demo: https://jsfiddle.net/Ltbvyepj/

And here is the Javascript code:

var path = document.querySelector(".path");
// Get the actual length of your path.
var len = path.getTotalLength();
// Dashes have the exact length of the path.
path.style.strokeDasharray = len + " " + len;
// Shift of the length of the path, so the line is quite not visible.
path.style.strokeDashoffset = len;
// Attach to the window's scroll event.
window.addEventListener( 'scroll', function() {
// Getting the page dimensions.
var rect = document.querySelector( 'html' ).getBoundingClientRect();
// Height is the size of the page which is out of screen.
var height = rect.height - window.innerHeight;
// Percent of scroll bar. 0 Means the top, 1 the bottom.
var percent = height < 0 ? 1
: -rect.top / height;
// If you omit the `2 *` you will get a growing only path.
path.style.strokeDashoffset = len * (1 - 2 * percent);
}, false);


Related Topics



Leave a reply



Submit