Preface

Goal: Generating SVG in DOM using Native Javascript.

Preview

The looks from the preview below is nice, but the animation is horrible, as we can see the video later.

SVG Bezier: Javascript Automation: Animation

SetInterval

I’m using SetInterval method to run javascript. I learnt it from w3schools.

I do not know if javascript animation is not a good idea. Or maybe just my script that is bad.

But we need this example, so we can compare with @keyframes method counterpart.

Disclaimer

We are still discussing about, generating SVG in DOM using javascript.

This article is intended to be sort. You can skip this entire section. And click right away to @keyframes method.


Alter D Attribute on the Fly

The HTML document is remain the same. But the javascript has many enhancement.

HTML: Head

<head>
  <title>Bezier Curves</title>
  <link rel="stylesheet"
        href="24-bezier.css"/>
  <link rel="stylesheet"
        href="24-style.css"/>
  <script src="28-bezier.js"></script>
</head>

HTML: Body

Also prepare the HTML body.

<body>
  <div id="svg_container">
    <svg xmlns="http://www.w3.org/2000/svg"
         id="svg_root" viewbox="0 0 200 160">
    </svg>
  </div>

  <div id="sitedesc_image"></div>
  <p style="text-align: center;">
    Paragraph Test on SVG Background</p>
</body>

Javascript: Skeleton

While the HTML code is remain the same, the javascript would slightly different, with variant for each animation.

function createPaths(svg_root, range) {...}

function getBezierParams(index, variant) {...}

function modifyPaths(svg_root, range) {
  ...
  function frame() {...}
}

document.addEventListener(
  "DOMContentLoaded", function(event) {...});

Notice the variant argument. And frame function inside modifyPaths.

Javascript: Create Path

Exactly the same as previous function.

function createPaths(svg_root, range) {
  const xmlns = 'http://www.w3.org/2000/svg';
  const blueScale = [     '#E3F2FD', 
    '#BBDEFB', '#90CAF9', '#64B5F6',
    '#42A5F5', '#2196F3', '#1E88E5',
    '#1976D2', '#1565C0', '#0D47A1'
  ];

  range.forEach((_, i) => {
    area = document.createElementNS(xmlns,"path");
    area.setAttribute("class", "area");
    area.setAttribute("id", `svg_area_${i}`);
    area.setAttribute("fill", blueScale[i]);
    svg_root.appendChild(area)
  });
}

We haven’t set any d property yet. No points initialized.

Javascript: Get Bezier Params

Be functional.

The idea is, to have the point result by index. And calculate without any loop.

function getBezierParams(index, variant) {
  const i = index + 1;

  // Initialize with destructuring style
  let [mx, my] = [0, 190];
  let [c1x, c2x, c3x] = [-10, 70, 120];
  let c1y, c2y, c3y;
  let [s1x, s1y, s2x, s2y] = [170, 230, 200, 220];

  my  -= 20*i;
  c1x += 10*i;
  [c1y, c2y, c3y] = [my-10, my-10, my+10]
  s1y -= 20*i;
  s2y -= 20*i;
  
  c1x += variant;
  c1y += variant;
  c3x -= variant;
  c3y += variant;
  s1x -= variant;
  s1y += variant;

  return {
    mx: mx,  my: my,
    c1x: c1x, c1y: c1y, c2x: c2x, c2y: c2y,
    c3x: c3x, c3y: c3y,
    s1x: s1x, s1y: s1y, s2x: s2x, s2y: s2y
  };
}

The only different with our previous script is, we have this variant argument.

function getBezierParams(index, variant) {
  ...
  
  c1x += variant;
  c1y += variant;
  c3x -= variant;
  c3y += variant;
  s1x -= variant;
  s1y += variant;

  ...
}

Again. You can be as creative as you want. This code above is just an example.

Javascript: Modify Path

This is also a loop, with each has different interval.

function modifyPaths(svg_root, range) {
  range.forEach((_, i) => {
    let id = null;
    clearInterval(id);
    id = setInterval(frame, 100+10*i);

    let variant = 0;

    const area  = document
      .getElementById(`svg_area_${i}`);

    function frame() {...}
  });
}

Javascript: Frame

For each loop, we destructure our bezier params first. Then set the d attribute property.

    function frame() {
      if (variant == 20) {
        variant = 0; 
      } else {
        variant++; 

        const {
          mx, my,
          c1x, c1y, c2x, c2y, c3x, c3y,
          s1x, s1y, s2x, s2y
        } = getBezierParams(i, variant);

        area.setAttribute("d",
          `M ${mx}  ${my}
           C ${c1x} ${c1y}, ${c2x} ${c2y}, ${c3x} ${c3y}
           S ${s1x} ${s1y}, ${s2x} ${s2y}
           L   200,     0  L    0,     0
           Z ${mx}  ${my}`);
      }
    }

Javascript: Main Entry Point

The program entry point in web development, could be DOM Ready or DOM Content Loaded.

document.addEventListener(
  "DOMContentLoaded", function(event) {
    const svg_root  = document
      .getElementById("svg_root");
    const range = [...Array(10)];

    createPaths(svg_root, range);
    modifyPaths(svg_root, range);
});

That is all.

Preview

The result is similar as below:

It does not feel smooth. And I do not know about high CPU usage.


What is Next ?

Instead of javascript, we can smooth the animation, using @keyframes in stylesheet.

Consider continue reading [ Bezier SVG - Keyframe Animation ].

Thank you for reading.