JavaScriptのグラフライブラリを使うと、手軽にWebサイトにグラフやチャートを表示することができます。現場で使われているものには C3.jsやChart.jsなど、数多くのライブラリがあります。中でもHighchartsは汎用性が高く、作れるグラフの種類・タイプはおそらく一番多いのではないでしょうか。
今回はHighchartsのカスタマイズ、特にX軸の日時表示にフォーカスして解説しています。標準のままではできない表記をどのように実現するかについてまとめました。
ちなみにHighchartsは、商用利用するときは有料ライセンスとなるので注意が必要です。
Highcharts?
まず軽く、Highchartsがどんなものなのか理解しておきましょう。
もう使ってるから知ってるよ!という人は次のセクションにスキップしてください。
どういった代物か
Highchartsは美しいグラフ、チャートを作成できる、JavaScriptのグラフライブラリです。
短めのコードでWebサイトにグラフを表示できるので、初心者でも簡単に扱えるライブラリです。慣れている人なら10分くらいで最初のチャートを作れるでしょう。
どんなものが作れるのか
どんなものが表示できるかは、本家のデモページをみると早いです。
Highchartsの日時表示でできること
ここからが本題です。
以下の解説では、サンプルコードに変更を加えながら解説しています。
>>サンプルDemoページ
数ヶ月分の日次(毎日)のランダムデータを入力し、デフォルトの設定のまま表示しています。
いまのところは、1ヶ月間間隔で描画されていますね。
type: 'datetime' は自動で柔軟な表示に
HighchartsのX軸を日時ラベルにするには、以下のようにxAxisのtypeを'datetime'にします。
xAxis: {
type: 'datetime'
}
データから自動で適当な間隔が設定される
type: 'datetime'に設定すると、データを読み取りHighcharts自身が自動で「これがベストじゃ!」という間隔を決めてしまいます。
上記のサンプルでは1ヶ月間隔で表示されていましたね。
ここで、入力するデータを削って数日分のデータに調整すると、以下のように1週間単位に自動で切り替わります。
tickInterval の指定で間隔を小さくする
この日時間隔を明示的に狭める(小さくする)こともできます。
それには xAxisにtickIntervalを指定してあげます。
tickIntervalにはミリ秒(millisecond)を指定します。
ただし、短すぎる間隔を指定すると、一部のラベルが表示されない(自動で非表示となる)ため、注意深く確認する必要があります。
下はtickIntervalを14日間隔に設定(短く)したものです。
このデモでは、以下のようにミリ秒を指定しています。
xAxis: {
tickInterval: 14 * 24 * 3600 * 1000
}
1ヶ月間隔から14日間隔に短くなりましたね。
表示される間隔に合わせてHighchartsが自動で表示を切替
間隔はtickIntervalで設定できましたが、この間隔に従ってHighcharts側では自動的に表示内容が切り替わります。
どういうことかというと、datetime型の日時データをHighchartsで扱うときには、「日」単位・「週」単位・「月」単位…などと、表示される単位を内部的に保持しているというわけです。
具体的には以下のような感じ。
14日間隔では「週」単位の表示なので "日. 月" の表示になっています。
一方、30日間隔では「月」単位の表示がされているので、"月" だけが表示されるようになっています。
※この例では、後述のdateTimeLabelFormatsをあえて書き換えて分かりやすくしています。
このように、「どの単位で表示を行うか」はHighchartsによって自動で決定され、xAxis.tickPositions.info.unitNameに格納されています。
上の例では14日のときは'week'、30日のときは'month' が入っていますね。
該当箇所のマニュアル(xAxis.tickPositions)
type: 'datetime' で利用できるラベルの種類
さらに細かいところで、個別のラベル表示を変更するにはどうしたらいいでしょうか?
これは dateTimeLabelFormats で変更できます。
デフォルトのラベル設定は次のようになっています。(何も設定を変えなければこのとおり表示されているはず)
{
millisecond: '%H:%M:%S.%L',
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%e. %b',
week: '%e. %b',
month: '%b \'%y',
year: '%Y'
}
このフォーマット設定で使えるキーは以下の通り(公式ドキュメントより抜粋。和訳は適当)
%a
: 短い曜日表記 例:'Mon'%A
: 長い曜日表記 例: 'Monday'%d
: 日付(0埋め) (01 ~ 31)%e
: 日付(1 ~ 31)%w
: 週の経過日(0 ~ 6)%b
: 短い形式の月表記 例: 'Jan'%B
: 長い形式の月表記 例:'January'%m
: 0埋めされた月番号(01 ~ 12)%y
: 2桁表記の年 例:2009年なら '09'%Y
: 4桁表記の年 例:'2009'%H
: 24時間表記の時 (0埋め), (00 ~ 23)%k
: 24時間表記の時 (0 ~ 23)%I
: 12時間表記の時 (0埋め), (00 ~ 11)%l
: 12時間表記の時, (1~ 12)%M
: 0埋めされた分(00 ~ 59)%p
: 大文字の AM または PM%P
: 小文字の AM または PM%S
: 0埋めされた秒(00 ~ 59)%L
: ミリ秒 (名前はRuby由来)
dateTimeLabelFormats を使って、例えば以下のように設定します。
xAxis: {
dateTimeLabelFormats: {
hour: '%l',
day: '%e',
week: '%e,%b',
month: '%b',
year: '%Y',
}
}
自由自在に日時表示の間隔を変えたいとき
データから日時のラベル表示を自動化してくれるのは便利ですが、もう少し工夫したいときもあるでしょう。
以下の方法を使えば、設定の自由度がかなり上がります。
あらゆる場合に同じ形式の表示にする
unit(単位)によらず、すべての場合に同じ形式にしたい場合は、labelsを設定します。
xAxis: {
labels: {
format: '{value:%Y-%b-%e}'
}
}
最初のラベルだけ別の表示にする
最初のラベルだけを別の形式で表示したいときもあるでしょう。
例えば、最初のラベルにだけ、省略していた年や月を表示したいときなどです。
xAxis.isFirstをうまく使って、formatterを設定することで可能になります。
以下のような感じで、label.formatterを設定してあげます。
xAxis: {
labels: {
formatter: function() {
if (this.isFirst) {
return Highcharts.dateFormat('%b, %Y', this.value);
}
return this.axis.defaultLabelFormatter.call(this);
},
}
}
最初のラベルを isFirst で識別し、'%b, %Y'を設定しています。
その他のラベルはデフォルトのラベルを使うべく、this.axis.defaultLabelFormatter.call(this)を返しています。
このようにすると、以下のように最初のラベルだけ年(2020)が表示されます。
独自基準の間隔に自動設定したい
また、ラベル表示のロジックを完全にコントロールしたい場合もあるでしょう。
例えば、複数のデータセットを同じファイルで運用したい、しかもそれらのデータ期間がまったく違うというのはよくありますよね(無い)。
そんなときは tickPositioner にコールバック関数を設定してあげます。
以下のコードは45日間間隔でtickを設けるもの。
xAxis: {
tickPositioner: function() {
let new_ticks = [],
min = this.min,
max = this.max,
interval = 45 * 24 * 3600 * 1000;
let xAxis = this,
tickPositionsInfo = xAxis.tickPositions.info;
let i = min;
for (i; i<=max; i+=interval) {
new_ticks.push(i);
}
new_ticks.info = tickPositionsInfo;
return new_ticks;
}
}
デモ:http://jsfiddle.net/fZrxa/o30sq7vd/
ただ、デモの実装だけだとtickIntervalを変えるだけで同じ事ができちゃいます。
例えば、データ期間によってロジックを変える条件分岐を入れたりだとか、unit(DayとかWeekとか)を途中で変えたりしたりだとかもできるようになります。
自由度が一気に上がりますね。
補足
highchartsに入力されたデータを確認したい時。
xAxisから直接値を取得できることができます。
また、コンソールに出力するにはeventを使うとやりやすいです。
下記は最大値の取得
events: {
redraw: function() {
console.log(chart.yAxis[0].max);
}
}