Chart.jsの線グラフに選択機能をつける


# chart.jsとは

HTML5のcanvasを使って、フラットなグラフが簡単に作れてしまうJavascriptのライブラリ。
入門記事はQiita内にも既に投稿があるので割愛します。

# 本記事の目的
#### 完成イメージ
![模試偏差値グラフ.png](https://qiita-image-store.s3.amazonaws.com/0/42884/369f5b29-efbb-0618-92f1-b2a4a307250d.png)

上図のようなグラフをクリックすると該当箇所の詳細が表示されるような機能を想定し、グラフクリックで選択できるように拡張する。

#### 今回やること
* 選択された軸を強調表示できるようライブラリを拡張（上図の赤い線は標準機能ではない）
* クリックイベントハンドラの作成

# やってみた
#### はじめに

Chart.jsを拡張する方法としては、以下の二通りがあります。
1. Chart.jsを直接編集する
2. src/Chart.Core.jsや、src/Chart.Line.jsといったソースファイルを編集し、同梱のgulpfile.jsでビルドする。
(gulpのインストールが必要 ※要npm)

色々拡張していったり、きちんと構成管理するなら後者がオススメですが、今回は前者で説明していきます。

尚、説明にあたっては執筆時点での最新版である Chart.js Version: 1.0.2 を使用します。
バージョンアップで行数とかは微妙にずれると思いますが、ご了承ください。


#### chart.jsを拡張する

オプションの追加箇所としては、56行目付近の全グラフ共通のオプション項目と、各グラフ種ごとのオプション項目のいずれかになります。
今回は線グラフにのみ追加してみました。
(円グラフとかレーダーチャートだと考え方が異なるので)

```javascript:Chart.js
2531		//Boolean - Whether to show vertical lines (except Y axis)
2532		scaleShowVerticalLines: true,
+
+           //Boolean - Whether to highlight selected vertical line
+           scaleHighlightVerticalLine: false,
+
+           //String - Colour of the highlighted line
+           scaleHighlightLineColor: "rgba(176,0,0,1)",
+   
+           //Number - Width of the highlighted line
+           scaleHighlightLineWidth: 2,
2533
2534		//Boolean - Whether the line is curved between points
2535		bezierCurve : true,
```
上から順に、強調表示をするかどうか、強調色、線の幅のデフォルト値になります。

そして、上で追加したオプションを、目盛線描画の際に使用できるようにしていきます。

```javascript:Chart.js
2711                gridLineColor: (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
+                   highlightVerticalLine: this.options.scaleHighlightVerticalLine,
+                   highlightLineColor: this.options.scaleHighlightLineColor,
+                   highlightLineWidth: this.options.scaleHighlightLineWidth,
2713                padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
```

そして縦のグリッド線描画時に選択した軸の場合、強調表示するためのコードを追加します。

```javascript:Chart.js
+                       if (this.highlightVerticalLine && index == this.selectedIndex) {
+                           ctx.lineWidth = this.highlightLineWidth;
+                           ctx.strokeStyle = this.highlightLineColor;
+                       }
+   
1691                    if (drawVerticalLine) {
1692                        ctx.moveTo(linePos, this.endPoint);
1693                        ctx.lineTo(linePos, this.startPoint - 3);
1694                        ctx.stroke();
1695                        ctx.closePath();
1696                    }
```

これで scaleHighlightVerticalLine オプションが true で、選択した軸の時に強調色になります。
次に選択した軸をセットするためのイベントハンドラを作成します。


#### イベントハンドラの作成
Chart.jsに同梱されているsamplesフォルダ内のline.htmlを使って解説します。
44行目以降のJavascriptを改変します。

```javascript:line.html
44  	window.onload = function(){
45  		var ctx = document.getElementById("canvas").getContext("2d");
+           helpers = Chart.helpers;
46  		window.myLine = new Chart(ctx).Line(lineChartData, {
+-47			responsive: true,
+               scaleHighlightVerticalLine: true
48  		});
+           helpers.addEvent(canvas, 'mousemove', function (evt) {
+                var points = myLine.getPointsAtEvent(evt);
+                if (points.length > 0) {
+                    canvas.style.cursor = "pointer";
+                } else {
+                    canvas.style.cursor = "default";
+                }
+            });
+            helpers.addEvent(canvas, 'click', function (evt) {
+                var points = myLine.getPointsAtEvent(evt);
+                if (points.length > 0) {
+                    myLine.scale.selectedIndex = myLine.datasets[0].points.indexOf(points[0])
+                    myLine.update();
+                }
+            });
49  	}
```
mousemoveイベントと、clickイベントのハンドラを追加しています。
前者はグラフにマウスが載った時に指カーソルに変更することで、クリックできることが視覚的にわかるようにしています。
肝心なのは後者のclickイベントで、Chart.jsのLineクラスのgetPointsAtEventメソッドを使用して、クリックされたポイント(データ値がプロットされている点)を取得しています。
ポイントオブジェクトを利用して様々な情報が取得できるのですが、今回はどの軸がクリックされたかを知りたいので、インデックスを取得しています。

それを先ほど拡張したScaleクラスのselectedIndexにセットします。
そして再描画させるため、updateメソッドを呼びます。

これでクリック時に赤い線が表示されるようになりました。

あとは同じイベントハンドラ内で、取得したインデックスを利用してデータを取得し、表を書き換えてあげればOKです。
(ここはChart.js関係ないので割愛)

# 最後に
Chart.jsはそこまで高機能というわけではないですが、見た目と同様に作りもシンプルなので、足りない部分は結構カスタマイズしやすいです。
是非皆さんも使ってみてください。