自分が開発しているサービス(Vueを主に使用)で分析系の機能をつくるにあたり
「やっぱりこれ、縦の折れ線グラフが一番わかりやすい」
となり、ググる...
しかし、そのまま使えそうなパッケージは見つからず、自前でつくることを決意。
Vueの公式ページにSVGで描かれたグラフがあったのでやってみました。
サンプル
https://jsfiddle.net/Wave7KN/5th9k53n/SVGとは
SVGは画像フォーマットの1つでもあり、XMLを使用したマークアップ言語でもあり、なかにはHTMLやCSSと同じような感覚で書けるものもあります。例えば、このように:hover
も使えたりします。※サンプルの点の部分にマウスを乗せてみてください。
また、HTML同様にJavaScriptで制御できるため、今回はVue.jsを使用して折れ線グラフを描いていきます。
サンプルデータを用意する
0~100の数値を5つずつ適当に用意しました。(ぜひランダム関数使ってください。)
data: {
all_data: [
{
type: 'a',
scores: [34, 46, 28, 39, 60]
},
{
type: 'b',
scores: [47, 32, 52, 33, 52]
},
{
type: 'c',
scores: [38, 29, 42, 53, 41]
},
{
type: 'd',
scores: [52, 57, 69, 48, 46]
}
],
ratio: 3, //横幅を3倍に拡大するために使う
row_height: 30,
},
SVGの土台を用意する
<svg :width="100 * ratio"
:height="svgHeight"
:viewBox="'0 0 ' + 100 * ratio + ' ' + svgHeight"
class="line-graph">
<!-- ... -->
</svg>
width
とheight
は、画面上に表示されるサイズを表します。
viewBox
はどこからどこまでを切り取って詰め込むかを表し、viewBox="x y width height"
のように4つの値を指定します。
x: viewBox左上のx座標
y: viewBox左上のy座標
width: viewBoxの幅
height: viewBoxの高さ
今回は0~100のデータを扱っていますが、そのままでは小さすぎるので3倍(ratio: 3
)にして表示させます。高さは、グラフの点の数に合わせて計算して出したいと思います。
svgHeight(){
return (this.all_data[0].scores.length - 1) * this.row_height
}
all_data
1番目のscores
のデータの数を参照して計算し、この :height="svgHeight"
:viewBox="'0 0 ' + 100 * ratio + ' ' + svgHeight"
2つの値を入れました。
1本の折れ線グラフをグループ化し、繰り返す
<g v-for="data in all_data" :class="'type-' + data.type">
<!-- ... -->
</g>
SVGのg要素は子要素を束ねるもので、いわゆる「グループ化」です。画像のような1本の折れ線グラフを1つのグループとして、v-for
を活用し、4本分繰り返してもらいます。
:class="'type-' + data.type"
とすることで、1本ずつに.type-a
、.type-b
といったそれぞれ異なるclassを付与し、色を変えています。
間の線と点をグループ化し、繰り返す
<g v-for="(score, index) in data.scores" :key="index">
<line v-if="index != 0"
:x1="data.scores[index - 1] * ratio"
:y1="(index - 1) * row_height"
:x2="score * ratio"
:y2="index * row_height"/>
<circle
:cx="score * ratio"
:cy="index * row_height"/>
</g>
1本のグラフの中で間を結ぶ線(line)と点(circle)をグループ化し、データの数だけ繰り返します。
line要素は、始点と終点の座標を指定することで描画できます。この場合、始点は1つ前の点の位置なので、index - 1
でx座標・y座標それぞれの値を求めています。v-for
でindex
を渡すことで、自身が何番目のデータかを知ることができます。
また、1つ目のlineは不要なのでv-if="index != 0"
で描画しないようにします。
circle要素は、円の中心の座標と半径を指定することで描画できます。半径rはCSSの方で指定しました。
この場合、「x2
=cx
」「y2
=cy
」となります。
まとめ
**「各属性に適切な座標を入れれば描画できる」**という当たり前のことに気がつけたので、大きな収穫です。それほど時間をかけずにグラフを作成することができました。