Solution 1 :

For each of your coloured lines, create a path that follows the course of that line back and forth. It’s stroke width should be wide enough to cover the line at its widest.

You then use that new line as a <mask> to reveal your colours.

The basic idea is described in my answer to a similar question. That question was about simulating animating handwriting. But the same approach will solve your problem also.

https://stackoverflow.com/a/37787761/1292848

Update

Did you check my codepen before answer?

Yes I did. The technique described there will work perfectly fine for your situation. To prove it, here is my own CodePen:

https://codepen.io/PaulLeBeau/pen/RwNOaZg

This is a proof of concept. I have only created a mask path for a short section of the paths. And to demo the concept, I have used a simple CSS animation, instead of implementing an onscroll handler.

It should be fairly obvious what’s happening. You will just need to change your onscroll handler to set the stroke-dashoffset based on how far you have scrolled.

If you don’t understand how the stroke-offset effect works to animat a line length, then there are plenty of tutorials all over the web, and here on Stack Overflow. For example, CSS-Tricks has a pretty good one:

https://css-tricks.com/svg-line-animation-works/

Solution 2 :

I have spent quite some time looking into this (few hours) and it is not so simple to solve. BUT I do have a solution. That said, the solution is also not so simple.

enter image description here

Note, the blue polygon is just there to help explain what shape is being used for the clip-path of the group element <g id="Line_Orange" >

I did not attach this to the scroll event because I needed a way to work on the logic behind the clip-path polygon with the simplest set-up I could get and allow me to start and stop the setInterval() to console.log() out the current x and y values etc. to compute where the turns needed to occur etc.

The full example is here: https://codepen.io/Alexander9111/pen/eYmbajB

And the JavaScript is:

    var running = false;
const g = document.querySelector("#Line_Orange");
const g_clone = g.cloneNode(true);
const svg = document.querySelector("svg");
g_clone.id = "Line_Grey";
//svg.appendChild(g_clone);
svg.insertBefore(g_clone, svg.childNodes[0]);

g.setAttribute('clip-path', "polygon(0 0, 0 100, 250 100, 250 0)");

const polygon = document.querySelector("#polygon_mask");
let segment_num = 0;
var temp_arr = [];
var polygon_points_arr = [80, 0, 80, 0];
var polygon_points_str = "80 0 80 0";
const polygon_segments = [
  {
    n: 0, dir: 1, progress: "y", boost: 1, init_x_y: [80,0], index: [3,5],
    points:[80, 0, 80, 250, 250, 250, 250, 0]
  },
  {
    n: 1, dir: 1, progress: "y", boost: 2, init_x_y: [80,100], index: [3,null],
    points:[80, 0, 80, 250, 250, 100, 250, 0]
  },
  {
    n: 2, dir: 1, progress: "x", boost: 2, init_x_y: [80,250], index: [4,null],
    points:[80, 0, 80, 250, 250, 250, 250, 100, 250, 100, 250, 0]
  },
  {
    n: 3, dir: 1, progress: "x", boost: 1, init_x_y: [250,100], index: [4,6],
    points:[80, 0, 80, 250, 450, 250, 450, 100, 250, 100, 250, 0]
  },
  {
    n: 4, dir: 1, progress: "x", boost: 2, init_x_y: [700,100], index: [null,6],
    points:[80, 0, 80, 250, 700, 250, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 5, dir: 1, progress: "y", boost: 2, init_x_y: [820,100], index: [null,9],
    points:[80, 0, 80, 250, 700, 250, 700, 250, 820, 100, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 6, dir: 1, progress: "y", boost: 1, init_x_y: [820,250], index: [7,9],
    points:[80, 0, 80, 250, 700, 250, 700, 250, 820, 100, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 7, dir: 1, progress: "y", boost: 2, init_x_y: [820,600], index: [null,9], 
    points:[80, 0, 80, 250, 700, 250, 700, 600, 820, 600, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 8, dir: -1, progress: "x", boost: 2, init_x_y: [820,750], index: [null,10],
    points:[80, 0, 80, 250, 700, 250, 700, 600, 700, 600, 820, 750, 820, 750, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 9, dir: -1, progress: "x", boost: 1, init_x_y: [700,750], index: [8,10],
    points:[80, 0, 80, 250, 700, 250, 700, 600, 700, 600, 820, 750, 820, 750, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 10, dir: -1, progress: "x", boost: 2, init_x_y: [150,600], index: [10,null],
    points:[80, 0, 80, 250, 700, 250, 700, 600, 150, 600, 150, 600, 150, 750, 150, 750, 820, 750, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 11, dir: 1, progress: "y", boost: 2, init_x_y: [0,600], index: [11,null],
    points:[80, 0, 80, 250, 700, 250, 700, 600, 0, 600, 0, 600, 150, 750, 150, 750, 820, 750, 820, 100, 250, 100, 250, 0]
  },
  {
    n: 12, dir: 1, progress: "y", boost: 1, init_x_y: [0,750], index: [11,13],
    points:[80, 0, 80, 250, 700, 250, 700, 600, 0, 600, 0, 600, 150, 750, 150, 750, 820, 750, 820, 100, 250, 100, 250, 0]
  }
];

var progressY = 0;
var progressX = 80;
const velocity = 1;
var boost = 1;
var direction = 1;
var timeInterval; //to be started at a later time
function myTimer() {
  //console.log(progress);
  direction = polygon_segments[segment_num].dir;
  polygon_points_arr = polygon_segments[segment_num].points;
  //console.log("null == 0", null == 0);
  var progress = polygon_segments[segment_num].progress == "x" ? progressX : progressY;
  var first_index = polygon_segments[segment_num].index[0];
  var second_index = polygon_segments[segment_num].index[1];
  if (first_index != null){
    polygon_points_arr[first_index] = progress;
  }
  if (second_index != null){
    polygon_points_arr[second_index] = progress;
  }
  polygon_points_arr.map((child, index) => {
      if (index % 2 == 0 && index < polygon_points_arr.length - 1){
          return child + ",";
      } else {
          return child 
      }      
  });
  temp_arr = polygon_points_arr.map((el, index, arr) => {
    if ((index + 1) % 2 == 0 && index < arr.length - 1){
      return el + ",";
    } else {
      return el;
    }
  });
  polygon_points_str = temp_arr.join(" ");
  console.log(polygon_points_str);

  function incrementAndSetValues(){
    segment_num +=1;
    boost = polygon_segments[segment_num].boost;
    progressX = polygon_segments[segment_num].init_x_y[0];
    progressY = polygon_segments[segment_num].init_x_y[1];
  }

  if (progressY>= 10000) {    
    clearInterval(timeInterval);
  } else {
    if (segment_num == 0) {
        progressY += (velocity * boost * direction);
        if (progressY >= 100) {
          incrementAndSetValues()
        }        
    } else if (segment_num == 1){
        progressY += (velocity * boost * direction);
        if (progressY >= 250) {
          incrementAndSetValues()
        }
        console.log(segment_num);
    } else if (segment_num == 2){
        progressX += (velocity * boost * direction);
        if (progressX >= 250) {
          incrementAndSetValues()
        }
    } else if (segment_num == 3){
        progressX += (velocity * boost * direction);
        if (progressX >= 700) {
          incrementAndSetValues()
        }
    } else if (segment_num == 4){
        progressX += (velocity * boost * direction);
        if (progressX >= 820) {
          incrementAndSetValues()
        }
    } else if (segment_num == 5){
        progressY += (velocity * boost * direction);
        if (progressY >= 250) {
          incrementAndSetValues()
        }
    } else if (segment_num == 6){
        progressY += (velocity * boost * direction);
        if (progressY >= 600) {
          incrementAndSetValues()
        }
    } else if (segment_num == 7){
        progressY += (velocity * boost * direction);
        if (progressY >= 750) {
          incrementAndSetValues()
        }
    } else if (segment_num == 8){
        progressX += (velocity * boost * direction);
        if (progressX <= 700) {
          incrementAndSetValues()
        }
    } else if (segment_num == 9){
        progressX += (velocity * boost * direction);
        if (progressX <= 150) {
          incrementAndSetValues()
        }
    } else if (segment_num == 10){
      progressX += (velocity * boost * direction);
      if (progressX <= 0) {
          incrementAndSetValues()
        }
    } else if (segment_num == 11){
      progressY += (velocity * boost * direction);
      if (progressY >= 750) {
          incrementAndSetValues()
        }
    } else if (segment_num == 12){
      progressY += (velocity * boost * direction);

    }

  }
  //console.log(segment_num);      
  g.setAttribute('clip-path', `polygon(${polygon_points_str})`);
  polygon.setAttribute('points', polygon_points_str);
}

function myStopFunction() {
  console.log("stop X,Y", progressX, progressY);
  document.querySelector("#start").removeAttribute('disabled', true);
  document.querySelector("#stop").setAttribute('disabled', true);
  clearInterval(timeInterval);
  running = false;
}

function myStartFunction() {
  timeInterval = setInterval(myTimer, 10);
  document.querySelector("#start").setAttribute('disabled', true);
  document.querySelector("#stop").removeAttribute('disabled', true);
  running = true;
}

document.querySelector("#start").addEventListener('click', myStartFunction);
document.querySelector("#stop").addEventListener('click', myStopFunction);
document.addEventListener('keydown', function(e){
  console.log(e.code);
  if (e.code == "Enter"){
    if (running){
      myStopFunction();
    } else {
      myStartFunction();
    }
  }
});

document.querySelector("#reset").addEventListener('click', function(){
  progressY = 0.00;
  progressX = 0.00;
  segment_num = 0;
  myTimer();
  document.querySelector("#start").removeAttribute('disabled', true);
  document.querySelector("#stop").removeAttribute('disabled', true);
});

document.addEventListener('DOMContentLoaded',
 function(){
  const g_grey = document.querySelector("#Line_Grey");
  //console.log(g_grey);
  const grey_paths = g_grey.querySelectorAll("path, polygon");

  for (i = 0; i< grey_paths.length; i++) {
    //console.log(grey_paths[i]);
    if (grey_paths[i].getAttribute('fill') == "none"){
      //do nothing
    } else if (grey_paths[i].getAttribute('fill') != "#bbbbbb"){
      //must be orange, change to grey
      grey_paths[i].setAttribute('fill',"#bbbbbb");

    }
  }  
  myTimer();
}, false);

And the most important part of the JavaScript is this array:

const polygon_segments = [
  {
    n: 0, dir: 1, progress: "y", boost: 1, init_x_y: [80,0], index: [3,5],
    points:[80, 0, 80, 250, 250, 250, 250, 0]
  }, ...

There is a segment for each segment of the polygon, as it grows and becomes more complex.

This diagram should help explain that a little bit:

enter image description here

And this one, explaining how the polygon increases in the number of points:

enter image description here

Problem :

How to correctly register clip-path so that the line is filled correctly that is, along the line and not from top to bottom as now. The screenshots show an example of filling in. On codepen, you can see the entire svg and see how the animation works (it is controlled by scrolling).

Screenshots:

Screenshot 1

Screenshot 2

Screenshot with problem:

Screenshot 3

Now clip-path its (For all code check codepen):

g.setAttribute('style', `clip-path: polygon(0 0%, 100% 0%, 100% ${progress+0.8}%, 0% ${progress+0.8}%);`)

UPDATE:
Please if you offer a solution show it on my example. Since my problem is specific and most just write without looking completely at the problem on codepen.

Comments

Comment posted by Anthony

Seems to work on my phone (chrome mobile). Well mostly. It’s got other problems but the animation follows the curve like you want.

Comment posted by Paul LeBeau

I have updated my answer.

Comment posted by stackoverflow.com/questions/23343890/…

Something like this:

Comment posted by Paul LeBeau

“How do I create a path for the entire animation and not just for the beginning?” The same way you got the design in the first place. Use a program to draw it.

Comment posted by Paul LeBeau

“Also, when you turn the line, you can notice a white triangle at the bend point. How can this be fixed?” Tweak the mask path corner curves.

Comment posted by Paul LeBeau

“How do I add gray lines until the line is filled with color?” In your original CodePen you are doing that by cloning the paths/groups. You can do the same thing here.

Comment posted by Alex L

8 values in polygon 0 is because 4 points of x & y coordinates. So it’s like (x1 y1, x2 y2, x3 y3, x4 y4) and the index[3,5] means change index 3 and 5 of that array. i.e y2 and y3 – this is because at one time we move 1 or 2 of the points of the polygon as we progress down or across (if we have index[3,null] then it means only move y2 – this happens on the curves)

By