Skip to content
Advertisement

Smoothly move an SVG line along a rectangular path

I am trying to recreate the following animation:

enter image description here

I am having trouble with getting a line to properly animate around corners. I’ve tried using an animateMotion-element like so:

<line class="testLine" x1="10" y1="10" x2="100" y2="10" stroke="white"> 
        <animateMotion dur="1.6s" repeatCount="indefinite" 
            path="M 10 10 L 390 10
             M 390 10 L 390 290
             M 390 290 L 10 290
             M 10 290 L 10 10"> 
        </animateMotion>
</line> 

But the line is not smoothly rounding corners. Any idea on how to get it to make it move smoothly around corners as shown in the GIF?

Advertisement

Answer

You will need to create a path with srtoke-dasharray = 1/2 of the side of the rect and animate the stroke-dashoffset of the path to 0

Please read the comments in the code:

const SVG_NS = "http://www.w3.org/2000/svg";
let sz = 50;//initial size 1/2 rect side
//the array of the paths. Inside the array uou have a first object for the path #p
let sqRy = [{ s: sz, d: "", l: p.getTotalLength(), el: p }];

//create several paths and rotate those paths accordingly
for (let i = 1; i < 8; i++) {
  let o = {};
  let size = sqRy[i - 1].s / 2;
  
  o.s = Math.sqrt(2 * size * size);
  //the value od the d attribute of the new path
  o.d = `M-${o.s},-${o.s}L${o.s},-${o.s} ${o.s},${o.s} -${o.s},${o.s} -${o.s},-${o.s}z`;

  o.el = document.createElementNS(SVG_NS, "path");
  o.el.setAttribute("d", o.d);//set the d attribute
  o.el.setAttribute("transform", `rotate(${45 * i})`);//set the rotation
  svg.appendChild(o.el);//append the new path to the svg element
  o.l = o.el.getTotalLength();//calculate the total length of the new path
  //push the object for the path to the array
  sqRy.push(o);
}


//for every element in the array set the stroke-dasharray and the stroke-dashoffset.
sqRy.map((sq) => {
  sq.el.setAttribute("style", `stroke-dasharray:${sq.s};stroke-dashoffset:${sq.l}`);
});
svg{fill:none;stroke:black;}

path{
     animation: dash 16s linear infinite;
}

@keyframes dash {
  to {
    stroke-dashoffset: 0;
  }
}
<svg width="300" viewBox="-60 -60 120 120" id="svg">
  <path id="p" d="M-50,-50L50,-50 50,50 -50,50 -50,-50z" />  
</svg>
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement