13

What I have achieved:

// 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 drawing
myline.style.strokeDasharray = length;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = length;

// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled
window.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: absolute;
  top: 15%;
  width: 100%;
  height: 1000px;
  
}

.st1 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: grey;
  stroke-width: 4;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 5;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <path  class="st1" 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>

<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>

What I want is no matter which size or shape the SVG <path> is the growing line should be in the middle of the screen.

I tried changing the values of myline.style.strokeDashoffset = length //+newvalue - draw; and all but all it did was just ruins the consistency. so is there anyone who can help me solve this issue.?

Any help would be highly appreciatable.

Jithin Raj P R
  • 6,667
  • 8
  • 38
  • 69
  • I know using fixed solves this issue to an extent but I need to go with the position `absolute` as I need this to `relative` to some other element on my page – Jithin Raj P R Jul 03 '18 at 09:24
  • Guys you can see in this link - https://stackoverflow.com/questions/45540161/make-the-on-scroll-growing-path-to-dashed-line , I know that will work but I have many other UI's in whcih I want the path to se `relative` to another element. – Jithin Raj P R Jul 03 '18 at 09:28

4 Answers4

8

(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>
Devansh J
  • 4,006
  • 11
  • 23
  • Your answer is one of the best among the answer I got here. But still, this is only one SVG `path` there are many `path` in different shapes with many lengths on my website. So every time tweaking this **speed** wont be much help as there are some curves in the `path` and same speed will not help me. If we can varry the speed according to the `patch` *shape* then that will be great. – Jithin Raj P R Jul 11 '18 at 06:58
  • @weBBer Can you achieve what you want by changing `completeOn` instead of `speed`? Basically what `completeOn` and `speed` values works for you in _this_ case, so that I have a visual picture of what you want. (Speed was never meant to be part of my solution... It was just an addon that should ideally be never used because as you said it brings arbitrary values into the picture...) – Devansh J Jul 11 '18 at 08:45
  • @weBBer I hope you know that `speed = 1` is the default speed... So if `speed = 1` works for you in _this_ it will most probably work in _every_ case – Devansh J Jul 11 '18 at 10:57
  • It was fast, I changed it to 0.5 and it worked for me in a case, but for another case in which the `path` is lengthy from 2/3 of the page to the end of the page. The animation starts before I reach the line and also it finishes it to the end only after I scrolled past the end of the line.[the `path` is curved in some areas] – Jithin Raj P R Jul 11 '18 at 11:52
  • @weBBer Can you achieve what by only changing `completeOn`? Also can you add some more paths or the paths on which you are actually working on in the question? – Devansh J Jul 11 '18 at 11:58
  • Also can you give a more specific problem statement? Bcoz I can't understand what exactly are you looking for. Do you want the ball to in the view always? Do you want to be the ball always 100px above the top of the screen? What exactly is the problem statement – Devansh J Jul 11 '18 at 12:01
  • I want the ball to remain on the centre to the `viewport` always on scroll. – Jithin Raj P R Jul 11 '18 at 16:05
  • Initially the path will be at the top, in that case the ball won't be at the starting position because the ball as to be at the center of viewport... That won't work for you, right? So you'll have to change the problem statement to match what you have in your mind... – Devansh J Jul 11 '18 at 17:23
  • Actually if the user refresh the page on the middle of the scroll then the ball should remain in the centre, but if he scrolls from the top then the ball should start its scroll once it reaches the middle of the page and remain the same position till the end of the path. may be this will help - https://jsfiddle.net/jithinrajpr7/d8gayxsb/ – Jithin Raj P R Jul 11 '18 at 18:03
  • Am pleased to see your answer, well explained and proven with a great sample. You have proven that you are a member of SO. Happy to give you the bounty, one more thing please if you can do some easing for the curves. – Jithin Raj P R Jul 13 '18 at 05:35
  • @weBBer Thank you and welcome! :) Also added the easing as you wanted... – Devansh J Jul 13 '18 at 13:39
  • Ty bro but you miss to give easing to the dot I think :) – Jithin Raj P R Jul 13 '18 at 15:20
  • @weBBer Welcome and I have purposely not given easing to the dot... I have mentioned why in the answer.... – Devansh J Jul 13 '18 at 18:24
  • Bro, I have a doubt I used your code and came across an animation jumping to the end bug and as a solution I commented - `//if(currentY > trackBounds.height) return totalLength;` and changed `let centreY = window.innerHeight / 2;` to `let centreY = window.innerHeight / 1.2;` and solved the issue but what is the condition I commented meant for, can you edit the answer and comment that for me and future users. – Jithin Raj P R Aug 08 '18 at 11:58
  • @weBBer I guess you want me to explain `if(currentY > trackBounds.height) return totalLength;`... I have added a comment explaining it... Also the bug you are referring will only occur when the user has made a jump scroll... I don't think it has anything to do with the code that you commented. But you solved the bug anyway so that's good. – Devansh J Aug 08 '18 at 13:17
  • Ty. By the way, don't waste time on the old answer I made some adjustment to the `var scrolltop = (document.documentElement.scrollTop / someValue) - mylineBounds.top;` and it works well so re-post it also, may come in handy to some people. – Jithin Raj P R Dec 19 '18 at 07:46
7

I tried several ways to get point moving

  • inside the box
  • not sliding away until end
  • with minimal changes to original.

I made the following changes (working example below):

  • divider for percent I put 2000 (equal to 2000px, the containing body height)
  • I multiplied the scroll amount from top by 18 (suitable value was a compromise whether the top or bottom becomes behaving wierdly)
  • then finally I checked the percent value is not greater to one (it started to eat the 'worm' from the other end).

That's it! Maybe not the fanciest, but works.

Problematic here is the svg line is not linear from top to down, so direct element related values could not be chosen, or I at least did not find some. Thus, I ended up to simple solution and playing with parameters.

// 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 drawing
myline.style.strokeDasharray = length;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = length;

// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled
window.addEventListener("scroll", myFunction);

function myFunction() {
  // What % down is it?
  var scrollpercent = (document.documentElement.scrollTop * 18) / 2000;
  if (scrollpercent > 1) scrollpercent = 1;
  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: absolute;
  top: 15%;
  width: 100%;
  height: 1000px;
  
}

.st1 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: grey;
  stroke-width: 4;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 5;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <path  class="st1" 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>

<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>
mico
  • 12,730
  • 12
  • 59
  • 99
  • In this case also the point is not always centre. Is it only for me.? – Jithin Raj P R Jul 07 '18 at 05:55
  • No, it is same for me also. I cite my own answer: 'Problematic here is the svg line is not linear from top to down'. This all means, the curvature expands non-linearly (not same velocity all time), but you scroll vertically with same velocity AND you rely on point location and line drawing on percentage of scroll bar (so do I) and they are actually not comparable directly, thus the point does not stay on center with this approach. Something else should be used to control the line and dot location on screen, I yet don't have ideas what it would be. – mico Jul 07 '18 at 06:11
  • 1
    I tried adjusting the offsets, but ended up with static image that did not scroll at all :/ – mico Jul 07 '18 at 06:13
  • Your answer is on of the best among the answer I got here. But still, this is only one SVG `path` there are many `path` in different shapes with many lengths on my website. So every time tweaking this JS is not a good idea for me. In your opinion, there is no other way.? – Jithin Raj P R Jul 11 '18 at 06:59
  • I am sorry, that is the end of my knowledge on the subject. The ccprog's answer, that shows for me as deleted, is my best bet for next alternative, to be extended to some new direction, of course. – mico Jul 11 '18 at 16:19
  • 1
    Thank you for your time bro. It's ok every day new things to learn, please check Devansh's answer, I think that's a better solution.! – Jithin Raj P R Jul 13 '18 at 05:33
3

As per the comments and few modification to css and svg code, i was able to get the line to the center of the page, please check the working example below:

// 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 drawing
myline.style.strokeDasharray = length;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = length;

// Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled
window.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 {
  margin: 0;
  height: 1000px;
  background: #f1f1f1;
}
#circle {
  fill: red;
}
#mySVG {
  top: 15%;
  position: absolute;
  width: 100%;
}
.st1 {
  fill: none;
  stroke-dashoffset: 1;
  stroke: grey;
  stroke-width: .5;
  stroke-miterlimit: 1;
  stroke-dasharray: 2;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 1;
  stroke-miterlimit: 1;
  stroke-dasharray: 2;
}
.grid {
  position: fixed;
  width: 1px;
  height: 100%;
  background: blue;
  left: 50%;
  top: 0;
}
<div class="grid"></div>
<svg id="mySVG" viewBox="0 0 200 72" preserveAspectRatio="xMidYMin slice">
  <path class="st1" stroke-dasharray="10,9" d="m 0,5 0,4 c 0,3 2,6 5,6 l 108,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -25,0 c -3,0 -6,3 -6,6 0,3 3,6 6,6 l 35,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -18,0 c -3,0 -5,3 -5,6 l 0,4" />
</svg>

<svg id="mySVG" viewBox="0 0 200 72" preserveAspectRatio="xMidYMin slice">
  <circle id="circle" cx="0" cy="3" r="2" />
  <path id="myline" class="st0" stroke-dasharray="10,9" d="m 0,5 0,4 c 0,3 2,6 5,6 l 108,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -25,0 c -3,0 -6,3 -6,6 0,3 3,6 6,6 l 35,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -18,0 c -3,0 -5,3 -5,6 l 0,4" />
</svg>
Girisha C
  • 1,922
  • 1
  • 12
  • 20
  • Bro, please do read the comments in the **Question** I know it can be fixed using `position: fixed` but I need it to be work with `position: absolute`, and I don't need the full SVG to be center to the page, I only need the Indication the redline to be in the middle of the page. – Jithin Raj P R Jul 10 '18 at 12:22
  • @weBBer, please check the updated snippet in full page mode, cheers :) – Girisha C Jul 12 '18 at 09:24
-3

I'd choose a different approach. I understand you want to find the point on the path that is closest to the middle of the screen. Let's do that:

  1. Find the coordinates of the middle of the screen and convert them to the coordinate system of the path. The SVG API has two functions for that: .getScreenCTM() and SVGPoint.matrixTransform().
  2. Find the point on the path (and its distance along the path) that is nearest to these coordinates. There is a bit of math and a search algorithm involved to do that. Mike Bostock has shown such an algorithm, and it's used here. Note that his function is open to a bit of tweaking (the precision parameter).
  3. Use these data to draw the circle and the dashoffset.

It is probably a good idea to refine this by introducing a throttle for the scroll events (second variant) and then set CSS transitions to avoid visible jumps.

Transitions for the circle positioning only work with a CSS transform property. (My solution does not neccessarily move the circle along the path while transitioning. It's possible to achieve that, but goes far beyond the scope of this answer.)

var mySVG = document.getElementById("mySVG");
// Get the id of the <path> element and the length of <path>
var myline = document.getElementById("myline");
var pathLength = myline.getTotalLength();
circle = document.getElementById("circle");
// The start position of the drawing
myline.style.strokeDasharray = pathLength;

// Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw
myline.style.strokeDashoffset = pathLength;

// throttled scroll event listener
function throttle(ms, callback) {
    var timer, lastCall=0;

    return function() {
        var now = new Date().getTime(),
            diff = now - lastCall;
        if (diff >= ms) {
            lastCall = now;
            callback();
        }
    };
}

window.addEventListener("scroll", throttle(100, myFunction));

// one initial execution
myFunction();

function myFunction() {
  var center = mySVG.createSVGPoint();
  // middle of browser viewport
  center.x = window.innerWidth / 2;
  center.y = window.innerHeight / 2;
  // transform to path coordinate system
  var matrix = myline.getScreenCTM().inverse();
  center = center.matrixTransform(matrix);

  //find nearest length on path
  var draw = getNearestLength(center);

  // Reverse the drawing (when scrolling upwards)
  myline.style.strokeDashoffset = -draw - pathLength;

  //get point at length
  endPoint = myline.getPointAtLength(draw);
  circle.style.transform = "translate(" + endPoint.x + "px, " + endPoint.y + "px)";
}

function getNearestLength(point) {
  var precision = 8,
      best,
      bestLength,
      bestDistance = Infinity;
  // linear scan for coarse approximation
  for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {
    if ((scanDistance = distance2(scan = myline.getPointAtLength(scanLength))) < bestDistance) {
      best = scan, bestLength = scanLength, bestDistance = scanDistance;
    }
  }
  // binary search for precise estimate
  precision /= 2;
  while (precision > 0.5) {
    var before,
        after,
        beforeLength,
        afterLength,
        beforeDistance,
        afterDistance;
    if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = myline.getPointAtLength(beforeLength))) < bestDistance) {
      best = before, bestLength = beforeLength, bestDistance = beforeDistance;
    } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = myline.getPointAtLength(afterLength))) < bestDistance) {
      best = after, bestLength = afterLength, bestDistance = afterDistance;
    } else {
      precision /= 2;
    }
  }
  return bestLength;

  function distance2(p) {
    var dx = p.x - point.x,
        dy = p.y - point.y;
    return dx * dx + dy * dy;
  }
}
body {
  height: 2000px;
  background: #f1f1f1;
}

#circle {
  fill: red;
}

#mySVG {
  position: absolute;
  top: 15%;
  width: 100%;
  height: 1000px;
  
}

.st1 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: grey;
  stroke-width: 4;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
}
.st0 {
  fill: none;
  stroke-dashoffset: 3px;
  stroke: red;
  stroke-width: 5;
  stroke-miterlimit: 10;
  stroke-dasharray: 20;
  transition: stroke-dashoffset 0.2s;
}

#circle {
   transform: translate(10px, 10px);
   transition: transform 0.2s;
   }
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">
  <path  class="st1" 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>

<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="0" cy="0" 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>
ccprog
  • 20,308
  • 4
  • 27
  • 44
  • Can we somehow ease the scroll or make it smooth because it's feeling very jerky on the browser scroll.? now at the curves of the `` the animation is just jumping off.! – Jithin Raj P R Jul 05 '18 at 05:43
  • I've expanded the answer with a few ideas. – ccprog Jul 05 '18 at 13:27
  • In the fiddle as I can see the **dot** is now skipping the curve and bouncing to the centre. – Jithin Raj P R Jul 05 '18 at 15:56
  • As I said, my solution does not neccessarily move the circle along the path while transitioning. Solving that is a separate problem. – ccprog Jul 05 '18 at 16:10
  • 1
    then sorry to say I can't mark this as an answer as it's just not the result or answer am looking for. The line not moving with the scroll it's just jumping of here to there. – Jithin Raj P R Jul 06 '18 at 05:36
  • After my first version of the answer, you asked about another problem that was never part of your original question. Then, against better judgement, I answer you not with a short hint, but with a partial implementation of a concept. And now you try to pressure me into answering a third question? Think again. – ccprog Jul 06 '18 at 13:12
  • 1
    @ccprog "And now you try to pressure me", I guess *you are* putting pressure on yourself, he did not. I have to say his question was clear from the start, you didn't provide the answer he was looking for **from the start**. It's down to you if you have to edit it three times to get to the actual result. I don't see why you got offended by it... – Ivan Jul 08 '18 at 13:58