Home > Software design >  CSS motion path for svg and use of CSS variable
CSS motion path for svg and use of CSS variable

Time:06-15

I am working with a svg element as following where I am trying to apply motion-path to a svg circle.

let u = 0;
let curve = document.querySelector('#curve')
let totalLength = curve.getTotalLength();
let dot = document.querySelector('#dot');
let p = curve.getPointAtLength(u * totalLength);
dot.setAttribute("transform", `translate(${p.x}, ${p.y})`);
let d = curve.getAttribute('d');
dot.style.setProperty('--mp', d)
#dot {
  offset-path: path('M 29.928125,119.32884 C 59.868756,78.85387 99.789596,30.283895 138.66049,30.104515 c 80.46172,-0.37133 90.87185,137.794285 140.7729,129.699295 40.35037,-6.54568 49.90105,-80.94994 86.53937,-78.86548 33.24073,1.89117 22.2547,70.77048 73.14399,70.77048 39.92084,0 58.65264,-56.66496 99.80211,-56.66496 49.90105,0 69.86147,80.94995 99.8021,48.56997');
  animation: move 3000ms infinite alternate ease-in-out;
}

@keyframes move {
  100% {
    offset-distance: 100%;
  }
}
<div id="container" ></div>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <g>
    <circle id="dot" r="10" cy="0.5" cx="0.5" style="fill: #dd1819; "></circle>
  </g>
  <path id="curve" d="M 29.928125,119.32884 C 59.868756,78.85387 99.789596,30.283895 138.66049,30.104515 c 80.46172,-0.37133 90.87185,137.794285 140.7729,129.699295 40.35037,-6.54568 49.90105,-80.94994 86.53937,-78.86548 33.24073,1.89117 22.2547,70.77048 73.14399,70.77048 39.92084,0 58.65264,-56.66496 99.80211,-56.66496 49.90105,0 69.86147,80.94995 99.8021,48.56997" style="fill: none; stroke:black; stroke-width: 1; /*transform:translate(100px, 100px);*/" />
</svg>

I can't make the circle follow the path with the code above.

Also, I intend to use CSS variable instead of manually copying the path. So if I do the following it does not even work

let u = 0;
let curve = document.querySelector('#curve')
let totalLength = curve.getTotalLength();
let dot = document.querySelector('#dot');
let p = curve.getPointAtLength(u * totalLength);
dot.setAttribute("transform", `translate(${p.x}, ${p.y})`);
let d = curve.getAttribute('d');
dot.style.setProperty('--mp', d)
#dot {
  offset-path: path(var(--mp);
  animation: move 3000ms infinite alternate ease-in-out;
}

@keyframes move {
  100% {
    offset-distance: 100%;
  }
}
<div id="container" ></div>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <g>
    <circle id="dot" r="10" cy="0.5" cx="0.5" style="fill: #dd1819; "></circle>
  </g>
  <path id="curve" d="M 29.928125,119.32884 C 59.868756,78.85387 99.789596,30.283895 138.66049,30.104515 c 80.46172,-0.37133 90.87185,137.794285 140.7729,129.699295 40.35037,-6.54568 49.90105,-80.94994 86.53937,-78.86548 33.24073,1.89117 22.2547,70.77048 73.14399,70.77048 39.92084,0 58.65264,-56.66496 99.80211,-56.66496 49.90105,0 69.86147,80.94995 99.8021,48.56997" style="fill: none; stroke:black; stroke-width: 1; /*transform:translate(100px, 100px);*/" />
</svg>

To summarize, what is the correct way to apply CSS motion path on a svg element by using CSS variable.

Update With the suggestion from G-Cyrillus and biberman, the following works

    let u = 0;
    let curve = document.querySelector('#curve')
    let totalLength = curve.getTotalLength();
    let dot = document.querySelector('#dot');
    let p = curve.getPointAtLength(u * totalLength);
    // dot.setAttribute("transform", `translate(${p.x}, ${p.y})`);
    let d = curve.getAttribute('d');
    dot.style.setProperty('--mp', '"'   d   '"')
#dot {
    offset-path: path(var(--mp));
    animation: move 3000ms infinite alternate ease-in-out;
}

@keyframes move {
    100% {
        offset-distance: 100%;
    }
}
<div id="container" ></div>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
         <g>
        <circle id="dot" r="10" cy="0.5" cx="0.5" style="fill: #dd1819; "></circle>
    </g>
     
        
  <path
     id="curve"
     d="M 29.928125,119.32884 C 59.868756,78.85387 99.789596,30.283895 138.66049,30.104515 c 80.46172,-0.37133 90.87185,137.794285 140.7729,129.699295 40.35037,-6.54568 49.90105,-80.94994 86.53937,-78.86548 33.24073,1.89117 22.2547,70.77048 73.14399,70.77048 39.92084,0 58.65264,-56.66496 99.80211,-56.66496 49.90105,0 69.86147,80.94995 99.8021,48.56997" 
     style="fill: none; stroke:black; stroke-width: 1; /*transform:translate(100px, 100px);*/" />


</svg>

CodePudding user response:

Your code works (not only in FF;), if you omit the JavaScript, because the animation is done with CSS.

Working example: (i removed the svg container, because it isn't used)

#dot {
  offset-path: path('M 29.928125,119.32884 C 59.868756,78.85387 99.789596,30.283895 138.66049,30.104515 c 80.46172,-0.37133 90.87185,137.794285 140.7729,129.699295 40.35037,-6.54568 49.90105,-80.94994 86.53937,-78.86548 33.24073,1.89117 22.2547,70.77048 73.14399,70.77048 39.92084,0 58.65264,-56.66496 99.80211,-56.66496 49.90105,0 69.86147,80.94995 99.8021,48.56997');
  animation: move 3000ms infinite alternate ease-in-out;
}

@keyframes move {
  100% {
    offset-distance: 100%;
  }
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <g>
    <circle id="dot" r="10" cy="0.5" cx="0.5" style="fill: #dd1819; "></circle>
  </g>
  
  <path id="curve" d="M 29.928125,119.32884 C 59.868756,78.85387 99.789596,30.283895 138.66049,30.104515 c 80.46172,-0.37133 90.87185,137.794285 140.7729,129.699295 40.35037,-6.54568 49.90105,-80.94994 86.53937,-78.86548 33.24073,1.89117 22.2547,70.77048 73.14399,70.77048 39.92084,0 58.65264,-56.66496 99.80211,-56.66496 49.90105,0 69.86147,80.94995 99.8021,48.56997" style="fill: none; stroke:black; stroke-width: 1;" />
</svg>

CodePudding user response:

You are missing the " from your d string , and you have a typo with path(var(--mp)) that you did not close properly ;)

let u = 0;
let curve = document.querySelector('#curve')
let totalLength = curve.getTotalLength();
let dot = document.querySelector('#dot');
let p = curve.getPointAtLength(u * totalLength);
//dot.setAttribute("transform", `translate(${p.x}, ${p.y})`);// is this usefull?
let d = curve.getAttribute('d');
dot.style.setProperty('--mp', '"' d '"')
#dot {
  offset-path: path(var(--mp));
  animation: move 3000ms infinite alternate ease-in-out;
}

@keyframes move {
  100% {
    offset-distance: 100%;
  }
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <g>
    <circle id="dot" r="10" cy="0.5" cx="0.5" style="fill: #dd1819; "></circle>
  </g>
  <path id="curve" d="M 29.928125,119.32884 C 59.868756,78.85387 99.789596,30.283895 138.66049,30.104515 c 80.46172,-0.37133 90.87185,137.794285 140.7729,129.699295 40.35037,-6.54568 49.90105,-80.94994 86.53937,-78.86548 33.24073,1.89117 22.2547,70.77048 73.14399,70.77048 39.92084,0 58.65264,-56.66496 99.80211,-56.66496 49.90105,0 69.86147,80.94995 99.8021,48.56997" style="fill: none; stroke:black; stroke-width: 1; /*transform:translate(100px, 100px);*/" />
</svg>

  • Related