Dynimically add step to linear gradient of an svg with javascript

I’m trying to add some step to a linear gradient tag inside an svg with js.

My code works, meaning the markup is correct after the script run, but the svg is not updated/re-rendered.

I start with something like this

<svg
      id="animatedPath"
      width="552"
      height="61"
      viewBox="0 0 552 61"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        id="pathToAnimate"
        d="M-22.125 45.875C42.5625 54.3125 56.625 31.8119 98.8125 20.5625C129.589 12.3558 166.31 9.3125 183.188 17.7506C205.688 29 218.018 54.3125 239.438 54.3125C261.938 54.3125 284.438 34.625 312.562 20.5625C340.688 6.5 345.75 9.3125 377.25 9.3125C416.625 9.3125 470.062 45.875 489.75 54.3125C509.438 62.75 524.639 55.9499 529.125 40.25C534.75 20.5625 534.75 6.5 616.312 3.6875"
        stroke-width="5.625"
        stroke-linecap="round"
      />
      <defs>
        <linearGradient
          id="logoGradient"
          x1="3.18749"
          y1="14.9375"
          x2="548.812"
          y2="20.5625"
          gradientUnits="userSpaceOnUse"
        ></linearGradient>
      </defs>
    </svg>

and in my js code i do a simple loop on a color array

let linearGradient = document.querySelector(
  "#animatedPath defs linearGradient"
);

let gradient=["#FFE600", "#05FF00", "#00D1FF", "#FF0000"];

gradient.forEach((color, index) => {
  let stop = document.createElement("stop");
  stop.setAttribute("offset", index / 4);
  stop.setAttribute("stop-color", color);
  linearGradient.appendChild(stop);
});

The code works, i can see the step inside the linear gradient but the svg is not updated.
If i put the step manually in the svg it clearly works, and if later in the code i try to manipulate the steps whit js, the svg get updated.

I’ve read some stuff about suspendRedraw, but also that is deprecated and may not apply to this case.

Does anybody has any suggestion?

let linearGradient = document.querySelector(
  "#animatedPath defs linearGradient"
);

let gradient = ["#FFE600", "#05FF00", "#00D1FF", "#FF0000"]

gradient.forEach((color, index) => {
  let stop = document.createElement("stop");
  stop.setAttribute("offset", index / 4);
  stop.setAttribute("stop-color", color);
  linearGradient.appendChild(stop);
});
 <svg
      id="animatedPath"
      width="552"
      height="61"
      viewBox="0 0 552 61"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        id="pathToAnimate"
        d="M-22.125 45.875C42.5625 54.3125 56.625 31.8119 98.8125 20.5625C129.589 12.3558 166.31 9.3125 183.188 17.7506C205.688 29 218.018 54.3125 239.438 54.3125C261.938 54.3125 284.438 34.625 312.562 20.5625C340.688 6.5 345.75 9.3125 377.25 9.3125C416.625 9.3125 470.062 45.875 489.75 54.3125C509.438 62.75 524.639 55.9499 529.125 40.25C534.75 20.5625 534.75 6.5 616.312 3.6875"
        stroke-width="5.625"
        stroke-linecap="round"
      />
      <defs>
        <linearGradient
          id="logoGradient"
          x1="3.18749"
          y1="14.9375"
          x2="548.812"
          y2="20.5625"
          gradientUnits="userSpaceOnUse"
        ></linearGradient>
      </defs>
    </svg>

>Solution :

For SVG elements, you need to use Document.createElementNS() instead of createElement(). The correct namespace to pass in for the first param is 'http://www.w3.org/2000/svg'.

let linearGradient = document.querySelector(
  "#animatedPath defs linearGradient"
);

let gradient = ["#FFE600", "#05FF00", "#00D1FF", "#FF0000"]

gradient.forEach((color, index) => {
  let stop = document.createElementNS("http://www.w3.org/2000/svg", "stop");
  stop.setAttribute("offset", index / 4);
  stop.setAttribute("stop-color", color);
  linearGradient.appendChild(stop);
});
<svg
      id="animatedPath"
      width="552"
      height="61"
      viewBox="0 0 552 61"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        id="pathToAnimate"
        d="M-22.125 45.875C42.5625 54.3125 56.625 31.8119 98.8125 20.5625C129.589 12.3558 166.31 9.3125 183.188 17.7506C205.688 29 218.018 54.3125 239.438 54.3125C261.938 54.3125 284.438 34.625 312.562 20.5625C340.688 6.5 345.75 9.3125 377.25 9.3125C416.625 9.3125 470.062 45.875 489.75 54.3125C509.438 62.75 524.639 55.9499 529.125 40.25C534.75 20.5625 534.75 6.5 616.312 3.6875"
        stroke-width="5.625"
        stroke-linecap="round"
      />
      <defs>
        <linearGradient
          id="logoGradient"
          x1="3.18749"
          y1="14.9375"
          x2="548.812"
          y2="20.5625"
          gradientUnits="userSpaceOnUse"
        ></linearGradient>
      </defs>
    </svg>

Leave a Reply