【SVG制御妄想１】SVG解析しないと始まらない

この記事は「続・Mohoから出力したSVGを制御したい妄想の話」の一部です。

■記事一覧
【SVG制御妄想１】SVG解析しないと始まらない
https://qiita.com/flying_echidna/items/5a628db0d652d1558208

【SVG制御妄想２】Mohoから出力したSVGのマスクがバグる
https://qiita.com/flying_echidna/items/3930caf04626deec7bfb

【SVG制御妄想３】連番データをどげんかせんと
https://qiita.com/flying_echidna/items/ded3f3590c3d67fadb86

【SVG制御妄想４】変形させたいよなぁ？
https://qiita.com/flying_echidna/items/188634f35a05bbde9a51

【SVG制御妄想５】ボーンぐりぐり
https://qiita.com/flying_echidna/items/a34648da8a650fe34824

【SVG制御妄想６】助けてマルチスレッド
https://qiita.com/flying_echidna/items/80b101c1a1eedb534137

【SVG制御妄想７】SVGの限界
https://qiita.com/flying_echidna/items/2f53a461c5e6c05109df


#現状

改めて。
実際に作ったブツがこちら。

【GitHub】SourceOf0-HTML/path_control: SVGを制御したい願望
https://github.com/SourceOf0-HTML/path_control

【GitHub Pages】ベクターデータをいじり倒したい気持ち
https://sourceof0-html.github.io/path_control/


#これまでのあらすじ

【2019-03-06】「SVGでアニメーションさせたいんじゃ」の詳細報告
https://qiita.com/flying_echidna/items/ff3a061f4e348e62cca0

Mohoという2Dアニメーションソフトウェアでぬるぬるアニメを作れる。
SVGという画像形式の連番ファイルとして出力することもできる。
SVGはベクタ形式の画像であり、ファイルの中身はパスや塗りの入った文字列（XML）である。
簡単にHTML上で表示することも可能。
↓
JavaScriptを使って、HTML上でMohoから出力したSVG連番ファイル再生したろ！！
↓
出力したSVG、特定条件下でマスク情報飛ぶバグあるやんけ！
しかも連番SVGファイルめっちゃ重いやんけ！
↓
RubyでSVGにマスク情報を追加して、タグ情報の圧縮したった。
第一部完！！


【2020-02-13】Mohoから出力したSVGを制御したい妄想の話 - Qiita
https://qiita.com/flying_echidna/items/da7ecc721650fa9ab651

SVGから情報を引っ張り出して、Moho上での制御方法を真似ていけば、
ベクタ形式のアニメーションの制御できるんじゃね？
↓
やべっ、アニメーションの差分情報も増えると、SVG連番ファイルマジで重いわ。
タグ情報の圧縮とかいうレベルじゃねぇ…
↓
バイナリ化verも作るようにした。
JavaScriptの構成は現状こんな感じになったよ。

第二部完！！


いや、アフィン変換したいし、ボーン制御したいんだが？
フォーワードキネマティクスとか、インバースキネマティクスしたいんだが？
でもそれをするにはくぁｗせｄｒｆｔｇｙふじこｌｐ；＠：「」

第三部へ続く…になるんだけども。
第三部の話に入る前に、今まで概要しか話してなかった
「RubyでSVGにマスク情報を追加して、タグ情報の圧縮したった」
の部分について具体的に説明しておこうと思う。
で、そのままタグ情報をJavaScriptで読み取るところの話に繋げる感じで。

まず、今までSVGを表示する方法や、SVGの内容について具体的には触れてなかったので、ひとまず先にそっちを説明。


#SVGをHTMLで表示するには？

そもそもSVGファイル（hoge.svgとする）を
HTML（同階層に置かれているindex.htmlとする）で
表示するにはどうするのか。

```html：index.html
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <img src="hoge.svg"/>
  </body>
</html>
```

```xml：hoge.svg
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px">
  <path d="M 0 20 L 100 20 L 100 120 L 50 120 Z" stroke="black" fill="blue" stroke-width="2" />
</svg>
```

これでいい。
いや、究極言うとSVG『ファイル』なんていらない。
SVGはXML形式のタグでしかないし、HTMLに埋め込んで記述できてしまう。

```html
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <svg width="200px" height="200px">
      <path d="M 0 20 L 100 20 L 100 120 L 50 120 Z" stroke="black" fill="blue" stroke-width="2" />
    </svg>
  </body>
</html>
```

実際の見た目はこんな感じ。
QiitaではSVGをそのまま表示できないっぽいので、ラスタ形式なのはご愛敬。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542630/071dc860-e38a-086a-dd92-1ba13be7d37f.png)

こうなってくると、SVGの内容をDOMとして扱えてしまうわけで、もはやJavaScript無双である。
解析し放題。やったぜ。


#SVGのpathタグの説明

とはいえ、SVGがどういうタグで構成されているか知っていないと、解析もクソもない。
それに今回使うのはMohoというソフトで出力したSVGであり、Moho上のデータをどう出力しているのか、フォーマットについても調べる必要がある。

とりあえずsvgタグのwidth属性、heigth属性はSVGの幅と高さの設定で、200px × 200px のサイズですよーと。
どっちかってと問題なのは、なんといってもpathタグが持つd要素。
このサイトがわかりやすいかな…？

Paths - SVG: Scalable Vector Graphics | MDN
https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Paths

今回のd要素だと…

M 0 20 L 100 20 L 100 120 L 50 120 Z

M：開始点の座標を指定 (  0,  20)
L：線で繋ぐ座標を指定 (100,  20)
L：線で繋ぐ座標を指定 (100, 120)
L：線で繋ぐ座標を指定 ( 50, 120)
Z：線を閉じる ＝ 開始点の座標まで線で繋ぐ

って感じ。
M は MoveTo、L は LineToの意味だってさ。
Z は ClosePath なんだけども、
CurveTo があるせいで C が使えなかったっぽいね。

ちなみに、MやLを小文字でmやlと書いてしまうと相対座標になる。
Mohoが出力するSVGでは小文字使ってないっぽいけど。

座標系は、左上を原点にして、右方向がx軸のプラス方向、下方向がy軸のプラス方向。

<details><summary>「普通、上方向がy軸のプラス方向じゃねぇの！？逆じゃね！？」について</summary><div>

いや、Webページって上から下に読み進んでいくし、下に情報を追加していくもんだし、スクロールバーも下に進むじゃん？
ついでに言うと、GPUやディスプレイの描画処理って、上から下に進むのが一般的だったりするのよね。
とはいえ、デジタルコンテンツがすべて「下方向がy軸のプラス方向」ってわけでもないのよね。
DirectX と OpenGL が最たる例だと思う。
扱う媒体によってはy軸の向きが違ったりするから、気を付けよう。

</div></details>

pathタグに付いてるd以外の属性は見た目の設定。

stroke： 線の色 black
fill： 塗りの色 blue
stroke-width：線の太さ 2

今のところMohoが出力されるSVGに L が含まれてたパターンを見たことがない。
どっちかってとメインは C(CurveTo) で出力される。
三次ベジェ曲線ってやつである。

Paths - SVG: Scalable Vector Graphics | MDN
https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Paths#B%C3%A9zier_Curves

このサイトの説明がわかりやすいんだけど…


#フォーマットが自由度高くて便利＆大変

SVGであれこれ書くには
単純にタグの内容を文字列として解析するには、という話。

```html
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <svg width="200px" height="200px">
      <path class="curveTest" d="M0,100C60,150,140,150,200,100" />
      <circle cx="60" cy="150" r="5" style="fill:rgb(255, 0, 0)"/>
      <circle cx="140" cy="150" r="5" fill="rgba(0,0,0,.5)"/>
    </svg>
    <style>
      .curveTest{stroke:#0000FF;fill:#00000000;stroke-width:2;}
    </style>
  </body>
</html>
```

実物はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542630/53e4a6b3-1e67-2745-dd7f-d6f1fb5df4ca.png)

pathタグのd要素の説明から。

M0,100C60,150,140,150,200,100

M：開始点の座標を指定 (0, 100)
C：曲線を繋ぐ
　　制御点1の座標 ( 60, 150)
　　制御点2の座標 (140, 150)
　　終点の座標    (200, 100)

ここで注目すべきは、d属性のフォーマット。
スペースを一切使わず、カンマで区切ってる。

で、2つの制御点の位置が分かりやすいように、circleタグを使って円を書いてる。
circleタグの各属性はこんな感じ。

cx：円の中心のx座標
cy：円の中心のy座標
r：円の半径

Moho上で円を描いても、SVGで出力するとCurveToで出力されるから、今回はあくまで説明用。
今回の例は、特に見た目の設定部分を荒ぶらせてる。

まず、各々の図形タグで見た目の設定をする方法の他のパターンとして、styleとclassを使ってる。
pathのタグはclass属性にcurveTestを設定して、styleタグの中で見た目の設定をしているパターン。
制御点1用のcircleタグはstyleをダイレクトで指定してるパターン。
色の設定方法に至っては、めちゃくちゃある。

<color> - CSS: カスケーディングスタイルシート | MDN
https://developer.mozilla.org/ja/docs/Web/CSS/color_value#RGB_%E8%89%B2

挙句、HTML/CSSの特性上、小数点の整数部が0のときは省略することもできてしまう。
つまり、0.1は.1と書いてもいいわけで…

文字情報を減らせる仕様でもあり、
文字列処理させるには発狂しそうな仕様がわんさかわんさか…わぁお…


#実際解析したいSVGについて

そもそも自分が扱っているのは「Mohoから出力したSVG」と「自分で圧縮したSVG」だけである。
ということで、実際にMohoから出力したSVGを見てみよう。

【GitHub】SVGTest/walk_00001.svg at master ・ SourceOf0-HTML/SVGTest
https://github.com/SourceOf0-HTML/SVGTest/blob/master/source/walk_00001.svg?short_path=4404bb7

195行目から。

```xml:source/walk_00001.svg
<g id="layer_head">
<path fill="#000000" fill-rule="evenodd" stroke="none" d="M 143.997 192.044 C 129.445 192.628 114.808 158.110 136.329 159.604 C 139.819 159.847 142.659 165.744 143.217 168.350 C 145.292 178.034 154.403 191.626 143.997 192.044 M 142.009 148.122 C 138.720 146.074 134.643 145.339 131.068 146.832 C 120.139 149.464 114.151 162.243 115.924 173.402 C 118.041 185.852 131.684 199.756 143.172 202.164 C 146.205 202.816 152.452 205.002 155.361 203.493 C 162.061 199.476 155.339 189.125 153.440 183.297 C 151.554 177.051 146.683 152.279 142.009 148.122 Z"/>
<path fill="none" stroke="#f8a087" stroke-width="1" stroke-linecap="butt" stroke-linejoin="round" d="M 136.329 159.604 C 139.819 159.847 142.659 165.744 143.217 168.350 "/>
<path fill="none" stroke="#f8a087" stroke-width="1" stroke-linecap="butt" stroke-linejoin="round" d="M 143.217 168.350 C 145.292 178.034 154.403 191.626 143.997 192.044 "/>
<path fill="none" stroke="#f8a087" stroke-width="1" stroke-linecap="butt" stroke-linejoin="round" d="M 143.997 192.044 C 129.445 192.628 114.808 158.110 136.329 159.604 "/>
<path fill="#f8a087" fill-rule="evenodd" stroke="none" d="M 136.329 159.604 C 139.819 159.847 142.659 165.744 143.217 168.350 C 145.292 178.034 154.403 191.626 143.997 192.044 C 129.445 192.628 114.808 158.110 136.329 159.604 Z"/>
<g id="face_Mask">
<path fill="#000000" fill-rule="evenodd" stroke="none" d="M 160.975 103.553 C 169.644 93.255 202.534 86.647 216.207 84.891 C 231.544 83.164 247.137 85.767 262.024 90.687 C 267.318 92.445 274.933 94.575 279.525 98.315 C 287.397 104.777 292.306 116.138 295.018 125.540 C 297.180 132.370 301.125 141.579 299.137 148.051 C 290.107 177.454 285.936 191.046 279.872 199.200 C 272.387 209.264 259.090 212.812 247.437 217.155 C 235.722 221.331 223.890 222.495 217.790 222.011 C 205.500 221.035 179.102 214.543 170.140 206.864 C 159.385 197.297 158.490 182.950 154.265 169.828 C 151.862 163.086 147.771 152.986 146.531 146.084 C 144.721 135.000 153.842 111.950 160.975 103.553 M 283.677 90.712 C 270.276 78.254 234.064 74.806 216.386 77.139 C 208.050 77.983 200.054 78.501 192.367 80.358 C 186.679 81.920 181.638 84.490 176.282 86.059 C 164.561 90.178 159.776 88.655 151.758 99.280 C 146.003 106.716 136.605 136.256 137.506 145.456 C 138.304 152.358 145.645 167.684 147.979 175.429 C 151.013 185.710 153.143 200.491 159.620 208.551 C 166.932 217.384 177.005 222.091 192.469 226.448 C 203.657 229.600 216.078 230.659 228.042 231.067 C 232.428 231.486 240.629 229.160 252.527 224.478 C 264.714 219.506 278.153 215.433 286.671 204.261 C 296.818 190.954 300.938 168.822 309.687 146.787 C 316.942 128.516 292.030 98.309 283.677 90.712 Z"/>
<path fill="none" stroke="#f8a087" stroke-width="1" stroke-linecap="butt" stroke-linejoin="round" d="M 216.207 84.891 C 231.544 83.164 247.137 85.767 262.024 90.687 "/>
<path fill="none" stroke="#f8a087" stroke-width="1" stroke-linecap="butt" stroke-linejoin="round" d="M 262.024 90.687 C 267.318 92.445 274.933 94.575 279.525 98.315 "/>
<path fill="none" stroke="#f8a087" stroke-width="1" stroke-linecap="butt" stroke-linejoin="round" d="M 279.525 98.315 C 287.397 104.777 292.306 116.138 295.018 125.540 "/>
```

こんな感じ。
gタグはMoho上のレイヤーに該当していて、id属性にレイヤー名が設定されてる。
レイヤー別で取得できるし、レイヤー名が取得できるの、非常にありがたい。
でも、各タグで同じような見た目の設定を毎回指定しているわけで、これだけで文字数どんだけあるのやら状態。

ということで、タグを圧縮させたときは、この指定をclassとstyleに移行させてる。
dタグもスペースをカンマにしつつ圧縮。
圧縮するのに使ったのはRuby。

【GitHub】path_control/addMaskTag.rb at master ・ SourceOf0-HTML/path_control
https://github.com/SourceOf0-HTML/path_control/blob/master/convert/addMaskTag.rb

マスク回りのタグもいじってるけど、その話は次の記事で…
実際に圧縮したのがこっち。

【GitHub】SVGTest/walk_00001.svg at master ・ SourceOf0-HTML/SVGTest
https://github.com/SourceOf0-HTML/SVGTest/blob/master/destination/walk_00001.svg?short_path=a6ac2ec

192行目から。

```xml:destination/walk_00001.svg
<g id="layer_head">
<path class="path-0" d="M143.997,192.044C129.445,192.628,114.808,158.110,136.329,159.604C139.819,159.847,142.659,165.744,143.217,168.350C145.292,178.034,154.403,191.626,143.997,192.044M142.009,148.122C138.720,146.074,134.643,145.339,131.068,146.832C120.139,149.464,114.151,162.243,115.924,173.402C118.041,185.852,131.684,199.756,143.172,202.164C146.205,202.816,152.452,205.002,155.361,203.493C162.061,199.476,155.339,189.125,153.440,183.297C151.554,177.051,146.683,152.279,142.009,148.122Z"/>
<path class="path-15" d="M136.329,159.604C139.819,159.847,142.659,165.744,143.217,168.350"/>
<path class="path-15" d="M143.217,168.350C145.292,178.034,154.403,191.626,143.997,192.044"/>
<path class="path-15" d="M143.997,192.044C129.445,192.628,114.808,158.110,136.329,159.604"/>
<path class="path-16" d="M136.329,159.604C139.819,159.847,142.659,165.744,143.217,168.350C145.292,178.034,154.403,191.626,143.997,192.044C129.445,192.628,114.808,158.110,136.329,159.604Z"/>
<g id="face_Mask">
<path class="path-0" d="M160.975,103.553C169.644,93.255,202.534,86.647,216.207,84.891C231.544,83.164,247.137,85.767,262.024,90.687C267.318,92.445,274.933,94.575,279.525,98.315C287.397,104.777,292.306,116.138,295.018,125.540C297.180,132.370,301.125,141.579,299.137,148.051C290.107,177.454,285.936,191.046,279.872,199.200C272.387,209.264,259.090,212.812,247.437,217.155C235.722,221.331,223.890,222.495,217.790,222.011C205.500,221.035,179.102,214.543,170.140,206.864C159.385,197.297,158.490,182.950,154.265,169.828C151.862,163.086,147.771,152.986,146.531,146.084C144.721,135.000,153.842,111.950,160.975,103.553M283.677,90.712C270.276,78.254,234.064,74.806,216.386,77.139C208.050,77.983,200.054,78.501,192.367,80.358C186.679,81.920,181.638,84.490,176.282,86.059C164.561,90.178,159.776,88.655,151.758,99.280C146.003,106.716,136.605,136.256,137.506,145.456C138.304,152.358,145.645,167.684,147.979,175.429C151.013,185.710,153.143,200.491,159.620,208.551C166.932,217.384,177.005,222.091,192.469,226.448C203.657,229.600,216.078,230.659,228.042,231.067C232.428,231.486,240.629,229.160,252.527,224.478C264.714,219.506,278.153,215.433,286.671,204.261C296.818,190.954,300.938,168.822,309.687,146.787C316.942,128.516,292.030,98.309,283.677,90.712Z"/>
<path class="path-15" d="M216.207,84.891C231.544,83.164,247.137,85.767,262.024,90.687"/>
<path class="path-15" d="M262.024,90.687C267.318,92.445,274.933,94.575,279.525,98.315"/>
<path class="path-15" d="M279.525,98.315C287.397,104.777,292.306,116.138,295.018,125.540"/>
```

で、345行目からstyleタグでまとめて設定してる。

```xml
<style>
.path-0{fill:#000000;fill-rule:evenodd;stroke:none;}
.path-1{fill:none;stroke:#a60d3f;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;}
.path-2{fill:#a60d3f;fill-rule:evenodd;stroke:none;}
```


#うるせーしらねー解析処理なんて大体でおｋー！！

ぶっちゃけ、この手に限る。
とりあえず「Mohoから出力したSVG」と「自分で圧縮したSVG」にだけ対応して、
SVGというSVGすべてに対応するのは後でいいんだよぉ！！

さて問題は…
このSVGをどうやってJavaScriptで解析して表示するか、である。
最初にやったのは、imgタグにSVG連番ファイルのパスを順番に設定して、愚直に表示するだけの方法。

【GitHub】SVGTest/main.js at master ・ SourceOf0-HTML/SVGTest
https://github.com/SourceOf0-HTML/SVGTest/blob/master/main.js

これだとSVGのタグが取得できないので、実際にやってるのはSVGの内容をHTMLに展開して、自力でCanvasに描画する方法。

【GitHub】path_control/path_svg_loader.js ・ SourceOf0-HTML/path_control
https://github.com/SourceOf0-HTML/path_control/blob/18b79532596a558ba95cb23404e21107b536292f/src/path_svg_loader.js

別のところでXMLHttpRequest()を使ってSVGファイルをそのままロードして、
530行目のところで、新しい要素としてHTMLに追加してる。
まだ表示はしたくないので、display:noneで不可視にしておく。

```Javascript:path_svg_loader.js
  addSvgDOM: function(svg) {
    let div = document.createElement("div");
    div.setAttribute("style", "display:none;");
    div.innerHTML = svg;
    let svgDOM = div.firstElementChild;
    document.body.append(div);
    this.domList[parseInt(svg.match(/id="Frame_(\d+)"/)[1]) - 1] = svgDOM;
    div = null;
    svgDOM = null;
  },
```

え？そのまま表示するわけでもないのに、なんでHTMLに追加してるのかって？
SVGファイルから読み込んだデータをそのまま解析すりゃいいじゃんって？
それは見た目の情報を取得で楽ができるから。
後々説明しますだ。

まずは、読み込んだSVGタグのSVGの表示サイズを取得。
465行目から。

```Javascript:path_svg_loader.js
    this.width = parseInt(groupsDOM.getAttribute("width").replace("px", ""));
    this.height = parseInt(groupsDOM.getAttribute("height").replace("px", ""));
```

SVGをそのままDOM扱いできるので、getAttribute()で属性の内容を取得できる。
で、pxって単位を取っ払って、数字として値を格納。
ん～。最強。

各レイヤーに該当するgタグを取得＆id属性を参照してレイヤー名を取得。
レイヤー名を使って内部処理をする際に使うgroupID（数字）をハッシュテーブルで作成して格納。
ただMohoでは同じ名前のレイヤーも作れてしまうので、ここでチェックして、はじいておく。
476行目のところ。

```Javascript:path_svg_loader.js
    Array.prototype.slice.call(groupsDOM.getElementsByTagName("g")).forEach(group=>{
      let name = group.getAttribute("id");
      if(this.groupNameToIDList[name] != null) {
        console.error("group ID is duplicated : " + name);
        return;
      }
      this.groupNameToIDList[name] = Object.keys(this.groupNameToIDList).length;
    });
```

なんでテーブルを作ってるのかのかって？
アニメーションさせていくと、レイヤーの順序変更とかが発生するから、先に存在するレイヤーの一覧を作って、後々同じレイヤーか照合するのに使う。
で、レイヤー名をあちこち文字列で持っておくと、それだけでデータ量がえぐくなるから、groupID（数字）で指定するようにしてる。

あとはtagNameでswitch文を書いて、ひたすら各タグを読み込みをしていく。
問題のpathタグのd属性の読み込みはこんな感じ。
37行目のところ。

```Javascript:path_svg_loader.js
  makePathDataList: function(dataAttribute) {
    let ret = [];
    
    let data;
    if(dataAttribute.indexOf(",") < 0) {
      data = dataAttribute.split(/ /);
    } else {
      data = dataAttribute.replace(/([MCZ])/g,",$1,").replace(/[^,]-/g,",-").split(/[, ]/);
    }
    
    let baseX = this.width;
    let baseY = this.height;
    let base = (baseX > baseY)? baseX : baseY;
    let getX=()=>parseFloat(data.shift())/base;
    let getY=()=>parseFloat(data.shift())/base;
    
    while(data.length > 0) {
      let type = data.shift();
      switch(type) {
        case "M":
          // USEGE : path2D.moveTo(pos[0], pos[1])
          ret.push({type:"M", pos:[getX(), getY()]});
          break;
        case "C":
          // USEGE : path2D.bezierCurveTo(pos[0], pos[1], pos[2], pos[3], pos[4], pos[5])
          ret.push({type:"C", pos:[getX(), getY(), getX(), getY(), getX(), getY()]});
          break;
        case "Z":
          // USEGE : path2D.closePath()
          ret.push({type:"Z"});
          break;
        case "":
          // do nothing.
          break;
        default:
          console.error("unknown type : " + type);
          console.log(type);
          break;
      }
    }
    return ret;
  },
```

スペースのみで分割されている場合（Mohoから出力したSVG）は、
`data = dataAttribute.split(/ /);`
で処理して、自分で圧縮したSVGの方は
`data = dataAttribute.replace(/([MCZ])/g,",$1,").replace(/[^,]-/g,",-").split(/[, ]/);`
で一度カンマ区切りに統一して、データの配列化をしてる。

マイナス部分の置換は何してんだって？
d属性でマイナスを含んだ値を指定するとき、スペースもカンマも入れる必要がないってところの対策。
(120, -50) という座標だったら、120-50と書けてしまうから、間にスペースもカンマも入らないのよね…
解析してできたデータはオブジェクト化してる。

baseなるもので割ってるのは、画面サイズを1とした座標に変換するため。
後で表示したいサイズを掛けるだけで拡縮処理ができるので、こうしておくのが個人的には楽。

さて、見た目の設定情報の取得はどうすんだ？
実は便利すぎる機能がある。
`window.getComputedStyle()`
これを使えば、DOMの属性を全部チェックしなくても、DOMに適応されている見た目の情報を全部取得できる。
見た目の設定だから、全部CSS扱いの模様。

Window.getComputedStyle() - Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/Window/getComputedStyle

これで取得したCSSStyleDeclarationのデータstyleを解析する。
86行目から。

```Javascript:path_svg_loader.js
    let fillStyle = style.fill;
    if(fillStyle == "none") {
      fillStyle = "transparent";
    }
    
    let lineWidth = 0;
    let strokeStyle = style.stroke;
    if(strokeStyle == "none") {
      strokeStyle = "transparent";
    } else {
      lineWidth = parseFloat(style.strokeWidth.match(/([\d\.]+)/)[1]);
    }
```

設定が存在しない場合は"none"で返ってくるから、透過するように設定してる。
線の設定が存在しないときは線の太さを0として扱って、そうでなければ文字列を数字に変換して取得してる。


#描画しなきゃ意味ないでしょ

描画するときは、Canvasタグを取得して、getContext("2d")を使って取得できるRenderingContext2Dを利用する。

CanvasRenderingContext2D - Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D

さらにSVGにガチで対応したPath2Dというものもある模様。
今回はSVGを直接ぶち込むわけではないけども。

Path2D() - Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/Path2D/Path2D

あら便利。

【GitHub】path_control/PathObj.js ・ SourceOf0-HTML/path_control
https://github.com/SourceOf0-HTML/path_control/blob/18b79532596a558ba95cb23404e21107b536292f/src/org/PathObj.js

ということで、これの178行目のところ。

```Javascript:PathObj.js
  draw(pathContainer, context, path2D, isMask) {
    this.resultPathList.forEach(d=>{
      let pos = d.pos;
      let ratio = pathContainer.pathRatio;
      switch(d.type) {
        case "M":
          path2D.moveTo(pos[0]*ratio, pos[1]*ratio);
          break;
        case "L":
          path2D.lineTo(pos[0]*ratio, pos[1]*ratio);
          break;
        case "C":
          path2D.bezierCurveTo(pos[0]*ratio, pos[1]*ratio, pos[2]*ratio, pos[3]*ratio, pos[4]*ratio, pos[5]*ratio);
          break;
        case "Z":
          path2D.closePath();
          break;
        default:
          console.error("unknown type");
          break;
      }
    });
    if(isMask) return;
    if(!!this.lineWidth.result) {
      context.lineJoin = "round";
      context.lineCap = "round";
      context.lineWidth = this.lineWidth.result;
      context.strokeStyle = this.strokeStyle.result;
      context.stroke(path2D);
    }
    context.fillStyle = this.fillStyle.result;
    context.fill(path2D, this.fillRule);
  };
```

一部めんどくさがって値を取得せず、直接ぶち込んでるけど、元々Mohoの段階でそこらへんの設定を自分がいじってないので、
設定をいじりたくなったときに読みとるようにすりゃええじゃんという雑なやーつー。

で。
見た目の設定の直前にisMaskとか言うのがあるけども、マスクとして使うパスに見た目の設定は不要だから、という理由。
マスクの話は…しないわけにもいかないか。
次の記事でしましょう…

次の記事：【SVG制御妄想２】Mohoから出力したSVGのマスクがバグる
https://qiita.com/flying_echidna/items/3930caf04626deec7bfb