with the flow

WEBプログラマを目指すWEBデザイナーが書き綴る開発日誌のようなもの

SVGでドーナツ型チャートに特化したjQueryプラグインを作った

予告通り、このチャートSVGで書き直しました。

前バージョンとは違って、マウスオーバーするとTooltipが出て数字がわかるようになりました。

作ってみた感想: グラフはSVGで作ったほうがいい。但しcanvasより面倒。

SVGで円弧を描くのはなかなか大変。。。
アンカーポイントの位置を一点ずつ計算して指定してあげないといけないので。
canvasはある程度よろしくやってくれるところがあったんだけどなぁ。。。

そのかわり、mouseenter, mousemoveなどの標準のイベントを監視できるように!
なので、マウスオーバー監視してグラフの値を出すTooltipをつけました。

SVGでやってみて、やっぱりインタラクティブなものはSVGのほうが有利だと実感。
DOMの中にちゃんとパスごとのエレメントが作成されるので操作出来るしなによりデバッグが楽。
CSSである程度装飾も可能だし(box-shadowが使えないのは残念だけど)。
あと、スマホタブレットで拡大しても輪郭がきれい。
canvasだとひと手間加えないといけないし、結局は画像なので細かい部分の小回りが利きにくい。
加工しやすく扱いやすいので好きなんですけどね。Canvas

SVGで円弧を描くのは(ほんとに)大変。

一方SVGはちょっと複雑な図形を書こうとすると途端に難しくなるのが難点。
今回Canvasと同じノリでやろうとしたら、意外と複雑で時間を食った。

Canvasだと円弧を描くのは簡単。
実際に描いてる部分を抜き出すとこんな感じ。

canvas

context.arc(x, y, radius, startAngle, endAngle, anticlockwise)

日本語にすると、

context.arc(中心点x座標, 中心点y座標, 半径, 開始ラジアン, 終了ラジアン, 反時計回りに描画するかどうか)

参考にしたChart.jsでもそうなんですが、ドーナツの一部を切り取った形を作るのに、
単に円弧を描いて線をぶっとくする、といった形ではなく、
円弧の形に一周するようにパスを書いてから中身を塗りつぶすという方式になっています。
該当箇所を抜き出すとこんな感じ。

ctx.beginPath();//描画開始
ctx.arc(centerX, centerY, doughnutRadius, startRadius, startRadius + segmentAngle, false);//外側の線を描く
ctx.arc(centerX, centerY, cutoutRadius, startRadius + segmentAngle, startRadius, true);//内側の線を描く
ctx.closePath();//パスを閉じる

中心2行部分のarc関数を日本語で書き換えるとこうなります。


ctx.arc(中心点X座標, 中心点Y座標, 外側の円弧半径, 開始点ラジアン, 終了点ラジアン, 時計回りに描く);
ctx.arc(中心点X座標, 中心点Y座標, 内側の円弧半径, 終了点ラジアン, 開始点ラジアン, 反時計回りに描く);

2行目の最後が「true」、つまり反時計周りになっているのは、そうしないと円弧の周りをパスが一周しないから。
外側の線を描いた後、内側の線を描くわけなんですが、外と内をつなぐ部分の線を描かなくても、
自動的につないでくれるのがCanvasのよいところ。

一方SVGは…

SVG

SVGでパスを描く構文は複雑なので細かい説明は省きますが、こんな感じ。

var cmd = [
  'M', startX, startY,
  'A', doughnutRadius, doughnutRadius, 0, largeArc, 1, endX, endY,
  'L', startX2, startY2,
  'A', cutoutRadius, cutoutRadius, 0, largeArc, 0, endX2, endY2,
  'Z'
];
$paths[i][0].setAttribute("d",cmd.join(' '));

先頭のM,A,L,A,Zって部分でどんなパスを描くかを宣言しています。日本語だとこう。

'M'(線は描かずペン先を移動) 開始点X座標, 開始点Y座標
'A'(円弧を描く), 外側の円弧半径(X方向), 外側の円弧半径(Y方向), 回転角(度), 長弧or短弧, 時計周り, 終点X座標, 終点Y座標
'L'(線を描く), 円弧終点の内側の点X座標, 円弧終点の内側の点Y座標
'A'(円弧を描く), 内側の円弧半径(X方向), 内側の円弧半径(Y方向), 回転角(度), 長弧or短弧, 反時計周り, 終点X座標, 終点Y座標
'Z'(パスを閉じる)

はい、複雑すぎ。

複雑になっちゃうのは、開始点と終了点のX,Y座標を
いちいち計算して出してあげないといけないところから来てると思います。
Canvasだと、半径と角度を指定すれば自動計算してくれるのに。。。
今回はまともに向き合ったのでいろいろ勉強しなおすことに。

ともかくこんな感じでチクチク点を指定して描くことでやっと完成。根本的に理解するためには三角関数からやり直さないといけなかった。

一応参考にしたリンクを貼っときます。

・10分でわかるSVG 基礎編
http://www.atmarkit.co.jp/fwcr/design/benkyo/webgraphics02/02.html

・中学生でもわかるベジェ曲線
http://ruiueyama.tumblr.com/post/11197882224

・三角比・三角関数
http://www24.atpages.jp/venvenkazuya/math1/trigonometric_ratio1.php

・360度ではなく、ラジアンで角度を記述する意味は?
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1211672837