LoginSignup
34
30

More than 1 year has passed since last update.

AngularでSVG使おうぜ!

Last updated at Posted at 2017-12-21

本記事は Angular Advent Calendar 2017 の21日目の記事です。


みなさん、SVG使っていますか~!

HTMLと同じように文書構造を表現できるSVGですが、Angularで利用するにあたって、その利便性や注意点にはどのようなモノがあるのでしょうか?

Angularとの親和性

svgファイルをイメージタグで読み込んだりして利用する分には特に旨味はなく、「eventListnerでonclickを取得できるベクター画像」くらいの機能性しか持たず、特にAngularとのシナジーを感じるようないいことはないかもしれません。。。:tired_face:

しかし、SVGはHTMLテンプレート上にそのまま記述でき、描写されるという特徴を持っています。
このため、バインディングやディレクティブなど、Angularを象徴する機能のほとんどがHTMLのテンプレートと同じように、遜色なく利用することができます。

SVGには、HTML/CSSだけでは実現できないような、見た目を装飾する数多くの属性やフィルターなどの仕組みが準備されております。 これらの仕組みとAngularの機能を組み合わせれば、最強のインターフェース/エクスペリエンスが簡単に実現できることでしょう。

また、コンポーネントの入れ子やCSSのカプセル化にもバッチリ対応しております。

Canvasとの比較

大きな違いはやはりテンプレートがあるかどうかです。
Canvasでは描写をすべてjsコード側で行わなければいけないので、どうしてもロジックがふくらみがちです。
また、HTML/CSSがわかればSVGは割りとすぐ書けるようになりますが、Canvasはある程度学習が必要でコストになるかもしれません。

他にも、SVGとCanvasではパフォーマンスに差が出ます。
どちらが優秀というわけではないのですが、パーティクル表現など、オブジェクトの数が多い場合にはCanvasのほうがパフォーマンスが良く、大きい解像度での表示にはSVGが強い、という結果になるようです。
pafformance.png
Microsoft | Developer Network - SVG と Canvas: どちらを選ぶか

CanvasとSVGの比較については以下のMicrosoftのDeveloper Networkのページで詳細にまとめられておりますので、技術選択に迷ったときには御覧ください。

AngularでSVGを利用するにあたって、考慮すること

ここまで読んでAngularでSVGを早速使ってみたくなったかもしれませんが、実はSVGをそのままAngular内で使おうとすると、結構壁にぶつかります。

SVG内の要素には svg:を付与すべし

Angularは<svg></svg>で囲われた要素を自動的にSVGの要素だと判断しますが、コンポーネントを入れ子にした場合など、未知の要素だと誤判定してしまいうまく動かないことが有るようです。

なので、

<svg>
  <g>
    <rect x="0" y="0" width="60" height="60"/>
  </g>
</svg>

のようなコードは、svg:プリフィクスをつけてあげましょう。

<svg>
  <svg:g>
    <svg:rect x="0" y="0" width="60" height="60"/>
  </svg:g>
</svg>

属性バインディングするときは attr.を付与すべし

SVG要素はAngular側に属性が定義されておらず、そのまま値をバインディングすることができないようです。 以下のように書きましょう。

<svg>
  <svg:rect [attr.x]="x" attr.y="{{ y }}" attr.class="box {{ cls }}" width="60" height="60"/>
</svg>

Angular側で定義しているngClassなどはそのまま利用できます。

SVG内にコンポーネントを入れ子にする場合は、属性セレクタなどでコンポーネントを作成すべし

SVGはXMLであるため、svgタグ内に未知の要素を許しません。 そのため、<svg><my-cmp></my-cmp></svg>のように利用するコンポーネントはエラーになってしまいます。

以下のようなセレクターのコンポーネントを作成し、<svg><svg:g my-cmp></svg:g></svg>のように利用しましょう。

@Component({
  selector: '[myCmp]',
  templateUrl: './my-cmp.component.html'
})

普通はg要素やsvg要素を利用するようです。

その他・所感

  • 今回の記事を書くにあたって、ババっと作ってみたSVGとAngularで制作したインタラクションコンテンツをGithub Pagesに上げましたソースコードはこちらです。
  • アニメーションはすべてCSSです。 AngularAnimationとも相性がいいと思うので、試してみたいですね。
    • SVGにはSMILというアニメーション実装があり、結構これが表現豊かなのですが、Chromeが廃止するとかしないとか言ったりしているので、利用しないほうがよいでしょう。
  • templateUrlに.svgのファイルを食わせたいのだけれどもangular-cliだけだとできないのだろうか?

参考・関連


ありがとうございました。 明日は puku0x さんです。

34
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
30