Preface

Goal: Generating SVG in DOM using Native Javascript.

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


Multiple Bezier Areas

We can reuse our last single path example, and generate multiple bezier path.

HTML: Head

Simple Refactoring

First thing first, make the main HTML tidy, by putting everything on external file.

<head>
  <title>Bezier Curves</title>
  <link rel="stylesheet"
        href="24-bezier.css"/>
  <link rel="stylesheet"
        href="24-style.css"/>
  <script src="25-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>

Instead pouring a bunch of path tags, we simplfy our process by using javascript. The SVG path can be drawan inside svg_root element.

Javascript: Skeleton

The main skeleton is containing loop.

document.addEventListener(
  "DOMContentLoaded", function(event) {
    const svg_root  = document.getElementById("svg_root");

    const xmlns = 'http://www.w3.org/2000/svg';
    const blueScale = [...];

    // Initialize base points
    ...

    [...Array(10)].forEach((_, index) => {...});
});

While the loop itself is just, drawing nine bezier area as below:

    [...Array(10)].forEach((_, index) => {

      // Defining variant points
      ...

      // material blue index 0i
      const area = document.createElementNS(xmlns,"path"); 
      ...

      svg_root.appendChild(area);
    });

The beziers are areas, no longer just guidelines.

Javascript: Material Color

I prefer blue gradient for example:

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

But the choice is yours.

Javascript: Points Initialization

We need to have starting points.

    // Initialize base points
    // 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];

Javascript: Points Variants

And for each loop, the base points changed.

As imply by its name. This variable is just variant. You can have any calculation as you want, and get different exotic bezier result.

      // Defining variant points
      my  -= 20;
      c1x += 10;
      [c1y, c2y, c3y] = [my-10, my-10, my+10]
      s1y -= 20;
      s2y -= 20;

The braver you are, the more creative you can get.

Javascript: D Property

Inside the loop, we can setup the full string, of the d property of the tag path.

      const d_property = 
              `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: Writing The DOM

Still inside the loop:

      // material blue index 0i
      const area = document.createElementNS(xmlns,"path"); 
      area.setAttribute("class", "area");
      area.setAttribute("fill", blueScale[index]);
      area.setAttribute("d", d_property);

      svg_root.appendChild(area);

Javascript: Writing The DOM

You can check the result in inspect element.

Preview

Enjoy the preview.

SVG Bezier: Javascript Automation: Multiple Bezier

Precaution

This limited viewbox, might truncate your SVG.

SVG Bezier: Viebox: space

To solve this, just add the height of the viewbox.


Javascript Refactoring

What if I say that my previous code is horrible?

Of course, my first attempt is not good. this is why we need refactoring.

Javascript: Skeleton

While the HTML code is remain the same, the javascript would be very different.

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

function getBezierParams(index) {...}

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

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

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

With code above, you can go further with class if you want. But I avoid premature optimization.

Javascript: Create Path

First of all constant initialization.

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'];
  ...
}

Then the loop.

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

Notice that 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.

My bad.

The first, a little bit strange. I have to add index by one, to match my previous script.

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

  ...
}

Then we can continue using our last script. Getting the base point.

  // Initialize base points
  // 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];

Then we can have change the variant. You can be as creative as you want. This code below is just an example.

  // Defining variant points
  my  -= 20*i;
  c1x += 10*i;
  [c1y, c2y, c3y] = [my-10, my-10, my+10]
  s1y -= 20*i;
  s2y -= 20*i;

And finally return the points value as dictionary.

  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
  };

So we can destructure later on.

Javascript: Modify Path

This is also a loop, that each set the d attribute property.

function modifyPaths(svg_root, range) {
  range.forEach((_, index) => {
    ...

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

    area.setAttribute("d", ...);
  });
}

For each loop, we destructure our bezier params first.

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

Still in the loop, We can then just write away the d attribute.

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

    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 preview is exactly the same. Because we just refactor the javascript.

SVG Bezier: Javascript Automation: Multiple Bezier


Different Looks

Strong color could be nice for animation, but some design require clean background.

The fact that I can play with color, does not mean I should abuse my design.

So I present, another looks. You can change the entire color array, or for quick fix, you can just change the opacity, and get very thin color instead.

Stylesheet

.area {
  stroke: none;
  stroke-width: 0px;
  opacity: 0.1;
}

Preview

SVG Bezier: Javascript Automation: Multiple Bezier

This is just a tips. But the choice is yours to decide.


What is Next ?

One example to modify the DOM is, by animating the bezier line.

Consider continue reading [ Bezier SVG - Javascript Animation ].

Thank you for reading.