【「createElementNS()」を使う必要あり】 p5.js Web Editor上の JavaScript で SVG を動的に生成（SVGフィルターで試す）

以前、以下の SVG を使ったモーションパスを JavaScript で生成したかったので、色々調べてみて試した内容があり、それを記事にしてみます。

https://twitter.com/youtoy/status/1534536910416543744

将来の自分へのメモも兼ねているので、見返しやすいようにシンプルな内容の記事にできればと思います。

## 今回扱う事例
JavaScript で SVG を動的に生成する話を書いていくのに、冒頭のモーションパスの例だと内容がシンプルにならなそうでした。
そのような中、最近書いた以下の記事は SVG の内容がシンプルなので、それを題材にしてみようと思います。

●p5.js で SVGフィルターを使う（p5.js Web Editor上の HTML・JavaScript に手を加えて利用） - Qiita
　https://qiita.com/youtoy/items/217bfe7e940f2a7e2626

## JavaScript で SVG を動的に生成する時のポイント（「createElementNS()」を使う）
冒頭に書いた、モーションパスの事例をあれこれ試していた当時、最初は [createElement()](https://developer.mozilla.org/ja/docs/Web/API/Document/createElement) を使って SVG を生成ようとしたのですが、それがうまくいかないという状況がありました。

そして試行錯誤や調査をした結果、SVG を動的に生成する場合は「createElementNS()」を使う必要がある、というのが分かり、その後は大きなハマりポイントもなく進められました。
なお、調べて参照した情報源は、こんな感じです。

- [Creating SVG elements dynamically with javascript inside HTML - Stack Overflow](https://stackoverflow.com/questions/20539196/)
- [JavaScript | createElementNSでSVGの図形を描画する基本 | ONE NOTES](https://1-notes.com/javascript-draw-svg-shapes-with-createelementns/)
- [SVGをcreateElementするには「NS」が必要。](https://fuuno.net/ani/ani81/ani81.html)

## createElementNS() を使った SVG の動的な生成
### p5.js Web Editor上で試す
タイトルにも書いたとおり、今回のお試しは「[p5.js Web Editor上](https://editor.p5js.org/)」で行います。

[上で記載していた記事](https://qiita.com/youtoy/items/217bfe7e940f2a7e2626)では、HTML の「\</body>」の前に、以下のタグを直書きしていました。
この記事では、この SVG要素とその中身の部分を JavaScript で生成します。

```html
    <svg>
      <filter id="feGaussianBlur">
        <feGaussianBlur stdDeviation="10 3" />
      </filter>
    </svg>
```

その SVG の動的生成の処理は、以下の内容を p5.js Web Editor の「sketch.js」の「setup()」の中に書きました。

```javascript
  const parentnode = document.body;
  const svgElt = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  parentnode.appendChild(svgElt);
  
  svgFilter = document.createElementNS('http://www.w3.org/2000/svg', 'filter');
  svgFilter.id = "feGaussianBlur";
  svgElt.prepend(svgFilter);
  
  const feGaussianBlur = document.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur');
  feGaussianBlur.setAttribute("stdDeviation", "10 3");
  svgFilter.prepend(feGaussianBlur);
```

1つ目のまとまりの処理で SVG要素を生成しています。
そして 2つ目のまとまりが、その1つ下の「filter」の部分で、最後のまとまりが「feGaussianBlur」になる形です。

また、上記の処理の後には、canvas要素に SVGフィルターを適用する処理を忘れず入れておきます。
以下に、描画処理なども合わせた「sketch.js全体の内容」を掲載します。

```javascript:sketch.js
let canvas;

function setup() {
  canvas = createCanvas(400, 300);
  fill(100, 100, 150);

  const parentnode = document.body;
  const svgElt = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  parentnode.appendChild(svgElt);
  
  svgFilter = document.createElementNS('http://www.w3.org/2000/svg', 'filter');
  svgFilter.id = "feGaussianBlur";
  svgElt.prepend(svgFilter);
  
  const feGaussianBlur = document.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur');
  feGaussianBlur.setAttribute("stdDeviation", "10 3");
  svgFilter.prepend(feGaussianBlur);
  
  canvas.style("filter", 'url(#feGaussianBlur)');
}

function draw() {
  background(220);
  circle((frameCount * 5) % width, frameCount % height, 50);
}
```

ちなみに、HTML は p5.js Web Editor　のデフォルトの内容から、「p5.sound.min.js」の読み込みを削っただけの内容です。CSS（style.css）は、デフォルトの内容に何も手を加えていない、そのままの内容です。

```html:index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />
  </head>
  <body>
    <main>
    </main>
    <script src="sketch.js"></script>
  </body>
</html>
```

そして、p5.js Web Editor でプログラムを実行し、ブラウザの開発者ツールを使って処理結果を確認してみます。
そうすると、以下の画像のように SVG が動的に生成されているのが確認できました。
![SVG が動的に生成された後の状態](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/45757890-4733-fc84-1add-6b2076a5e371.png)

そして、p5.js Web Editor のプレビューでも、以下のように Blur が適用されているのが確認できました。
![p5.js Web Editor のプレビュー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/54337abb-e859-275d-3064-6f15a48dc52a.png)

ちなみに動いている時の様子は、前の記事に掲載していた以下と全く同じになります。

https://twitter.com/youtoy/status/1550713084649811969