Snap.svg入門

2020/12/15に公開

Snap.svgとは

まず、SVG(Scalable Vector Graphics)は名前の通りベクター形式の画像で形式で拡大しても綺麗に表示されるという特徴がある。
(一方でビットマップ等のラスタ形式では写真等の色のグラデーションなどに強いとされる)
内部形式はXMLベースなのでコード自体はHTMLに似たものになるがHTMLがCSSでデザインをするのに対してSVGは画像そのものなので基本的にデザイン的なものも属性プロパティで指定される。
W3Cが策定・標準化しているのでもちろんDOM APIライクなSVG APIが提供されているがHTMLと違いタグ毎の属性プロパティなどがありより複雑になっているのでそれらを吸収するためjQueryライクなラッパーライブラリとしてデファクトスタンダードなものとしてSnap.svgがある。

SVG ElementのラッパーオブジェクトとしてのPaper

HTML文章であれば必ずHTML要素があるし、head要素、body要素などはない場合も自動生成される。
一方でSVGは必ずしも存在するわけではない。そのため、SVG要素自体を作る必要がある。
例えば下のように作って親要素に明示的にぶら下げる。(ぶら下げないとhtmlと繋がらないので表示されない)

makePaper.js
function makePaper(elem){
   const width=elem.clientWidth, height=elem.clientHeight;
   const paper=Snap(width, height);
   paper.appendTo(elem);
   return paper;
}

widthheightは自ら設定することもできる。
もちろんSnap(selectorSnap(svgelement)のように文章中にSVGタグを用意しておいて利用することもできる。

group要素

Paperオブジェクトと同様の子要素を作れるオブジェクトとしてg(roup)要素がある。
これは、paper.g()のようにして作ることができる。

シェープの生成

makeShapes.js

const rect2    = paper.rect(x, y, width, height, rx, ry); //端が丸められる

const line     = paper.line(x0, y0, x1, y1);
const polyline = paper.polyline(x0, y0, ...., xn, yn);
// const polyline = paper.polyline([x0, y0, ..., xn, yn]); でもOK
const polygon  = paper.polygon(x0, y0, ...., xn, yn);

const circle   = paper.circle(x, y, r);
const ellipse  = paper.ellipse(x, y,rx, ry); //楕円

const text     = paper.text(x, y, "content");

のようなものでSVGの各タグ要素を作ることができる。これらの返り値はSVGElementのラッパーオブジェクト(nodeメンバー変数に要素を持っているオブジェクト)である。
このオブジェクトは.attr()メソッドを通じてプロパティ値を変更したりできる。これはjQueryと同じようにオブジェクト自身を返すのでメソッドチェーンさせることも可能で

const rect = paper.rect(x, y, width, height).attr({ stroke: "red", strokeWidth: 3, fill: "Orange" });

のようにできる。
より汎用的なpathオブジェクトも存在する。

テキストの位置を示す属性値

テキストの位置を示す属性値としてtextAnchor'(横方向)とdominantBaseline`(縦方向)がある。

  • textAnchor: startで右側(始まり)が点
  • textAnchor: middleで中央配置
  • textAnchor: endで左側(終わり)が点
  • dominatBaseline: hangingで下に吊るす。
  • dominatBaseline: middleで中央配置
  • dominatBaseline: ideographicで線上になる。

になる。デフォルトではtextAnchor: startで縦方向は英語表記の普通のベースラインになる、つまりpqgなどは下がはみ出る。

textAttr.js
    const hline=paper.line(x, y+0.5*dy, x+dx, y+0.5*dy).attr({ stroke: 'black' });
    const vline=paper.line(x+0.5*dx, y, x+0.5*dx, y+dy).attr({ stroke: 'black' });
    const bline=paper.line(x+0.5*dx, y+1.2*dy, x+dx, y+1.2*dy).attr({ stroke: 'red' });

    const text11=paper.text(x,        y,        'start & hanging' ).attr({ textAnchor: "start",  dominantBaseline: "hanging"});
    const text12=paper.text(x+0.5*dx, y,        'middle & hanging').attr({ textAnchor: "middle", dominantBaseline: "hanging"});
    const text13=paper.text(x+dx,     y,        'end & hanging'   ).attr({ textAnchor: "end",    dominantBaseline: "hanging"});
    const text21=paper.text(x,        y+0.5*dy,  'start & middle' ).attr({ textAnchor: "start",  dominantBaseline: "middle"});
    const text22=paper.text(x+0.5*dx, y+0.5*dy,  'middle & middle').attr({ textAnchor: "middle", dominantBaseline: "middle"});
    const text23=paper.text(x+dx,     y+0.5*dy,  'end & middle'   ).attr({ textAnchor: "end",    dominantBaseline: "middle"});
    const text31=paper.text(x,        y+dy, 'start & ideographic' ).attr({ textAnchor: "start",  dominantBaseline: "ideographic"});
    const text32=paper.text(x+0.5*dx, y+dy, 'middle & ideographic').attr({ textAnchor: "middle", dominantBaseline: "ideographic"});
    const text33=paper.text(x+dx,     y+dy, 'end & ideographic'   ).attr({ textAnchor: "end",    dominantBaseline: "ideographic"});

    const defaultText=paper.text(x+0.5*dx, y+1.2*dy, "Default pqg");

このようなコードで


このような画像になる。(x,y,dx,dyは適宜調節)
これらの属性値はあまり見ないので覚えておく(知っておくと)便利だと思う。

属性値、widthやheightなどの取得

これはSnapのしようと言うよりはSVGElemntそのものの仕様であろうがこれらの取得はSVGElement[property].animVal.valueのような方法で取得する。(参考: animVal(MDN)

座標系について

SVGに限らずWeb系の座標系は左上が原点で右下に行くほどx,y共に増加する方向になる。
これは普通の数学系の座標系が右上がx,yが増加する方向であるのに対してそれなりに混乱するのできちんと理解するべきです。
また表の単位は基本的にpxで100%とかは使えない(はず)なのでグラフなどに使うときは適切に一次変換してやる必要がある。

ひとまず終わりに

画像系なのでHTMLよりは設定項目が多くいろいろなものがあるがひとまずこれだけあるとまあ何かができると思います。
レファレンス代わりとしてはSnap.svgの使い方まとめ - Xdomain サーバー初期ページが有用であると思う。
他にSVG系のデファクトスタンダードとしてはD3.jsが有名である。これはグラフ(データ表示特化型)なのでSVGそのものを学びつつというのには適さないと思ったので手を出していない。
このSnap.svgはSVGを使ったいろいろな画像系ライブラリの基礎に使われていたりするので知っているといいかもしれない。

Discussion