Chart.jsのlegend: generateLabelsの規定処理

Chart.jsの凡例はクリックするだけで、紐づいているdatasetのグラフ表示をOn/Offできる。このデフォルト機能のおかげで、複数のdatasetを一つのグラフに表示する場合に、とあるdatasetの最大値が大きすぎて、他のdatasetのフラフが軸線に埋もれて見えなくなる場合に、見えなくなったグラフのみをOnにすることができる。

一つのグラフに何でもかんでも詰め込んで表示することは良くないだろうが、この凡例の機能を使えば、見たいデータに絞って表示することを、ユーザー操作によって可能となるメリットはあると思う。

さて、複数のdatasetがあるグラフは、表示直後は全てのデータを表示するため、みてもらいたいデータが最初から埋もれて見づらくなってしまった場合に、凡例のクリック機能をうまく使えないだろうかと考えてみた。

Chart.jsのドキュメントによると、凡例クリックによるデフォルド処理のコードと、応用例が書いてある。ただこれはクリックをした場合であって、グラフ表示直後にできる話ではない。(javascriptの精通者なら、onClickイベントを表示時に発行させて目的を達成できるだろう…でも僕にそのスキルは無いようだorz)

そこで着目したのが、generateLabelsプロパティだ。これはfunctionで定義し、戻り値は規定のインターフェースを設定しなければならない。

やりたいことは、表示時にとあるdatasetの項目をあたかもクリックしたかのように非表示にしたい…というものだ。そのためには、表示・非表示の項目のみを操作したいのだが、ドキュメントのgenerateLabelsは、onClickの説明と違って、デフォルト動作も応用例も載っていない。

僕はどうしたかというと、

  • ブラウザでグラフを表示する
  • F12キーを押してデバッグモードにし、グラフオブジェクト生成後の場所にブレークポイントを設定する
  • 再読み込みをして、ブレークポイントにヒットさせる
  • 生成されたグラフオブジェクトの中身から、generateLabelsのコードを見つけて、コピーする(これは、Chart.js内にある)
  • コピーしたコードを自分のページに張り付ける

これで、デフォルトのgenerateLabels処理を取得した。

後で気づいたけど、Chart.jsのソースコードからgenerateLabelsを検索してもよかった。ただ、これだと複数ヒットするので、どのgenerateLabelsが使われるのかを調べておく必要がある。このとき、なぜドキュメントにgenerateLabelsのデフォルト処理が書いていないのかが分かった。グラフによって違うからだ。

抜き出したコードを改修して目的の動作をするコードを最後に乗せておく。これは3個めのdatasetのグラフを初期表示したときのみ非表示にするというものだ。

var isFirstload = true;
・・・・
var chartX = new Chart(ctx, {
    ・・・
     options: {
        legend: {
            labels: {
                generateLabels: function (chart) { // このプロパティは、グラフ描画毎に使用される
                    var data = chart.data;
                    return Array.isArray(data.datasets) ? data.datasets.map(function (dataset, i) {
                       // 付け加えたコード ここから
                        var meta = chart.getDatasetMeta(i);
                        if (isFirstLoad) {
                            if (i == 2) {
                                isFirstLoad = false;
                                meta.hidden = meta.hidden == null ? !data.datasets[i].hidden : null;
                           }
                       }
                       // 付け加えたコード ここまで
                      return {
                         text: dataset.label,
                         fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
                         hidden: !chart.isDatasetVisible(i),
                         lineCap: dataset.borderCapStyle,
                         lineDash: dataset.borderDash,
                         lineDashOffset: dataset.borderDashOffset,
                         lineJoin: dataset.borderJoinStyle,
                         lineWidth: dataset.borderWidth,
                         strokeStyle: dataset.borderColor,
                         pointStyle: dataset.pointStyle,

                         // Below is extra data used for toggling the datasets
                        datasetIndex: i
                      };
                  }, this) : [];
             },
  ・・・
},

デフォルト処理は、mapメソッドを使った実にうまいコードだと思う。Chart.jsのスタッフさん、素晴らしいコードをみせてくれてありがとう