問題
chart.jsの公式プラグインで、チャートのズームアップ・ズームダウンを実現するZoom and pan pluginですが、時系列データ(type:"time")の場合、maxとminを指定してもそれ以上の領域が表示されてしまいます。
できればこれを制限して、maxとmin範囲外のものは表示しないようにしたい。
解決法1
解決する方法は二つあります。
一つはスクロールボタンではなく、ドラッグによる拡大表示を有効にする方法。
具体的には以下のようにパンのenable
をfalse
、ズームのenable
とdrag
をtrue
にする
zoom: {
enabled: true,
drag: true,
mode: "x",
rangeMin: {
x: 3600000
},
rangeMax: {
x: ((new Date(data[3].timestamp).getTime()) - (new Date(data[0].timestamp).getTime())) + offset
}
},
scales: {
xAxes: [{
type: "time",
time: {
min: new Date(data[0].timestamp).getTime(),
max: new Date(data[3].timestamp).getTime()
}
}]
}
これでドラッグで拡大、ダブルクリックで拡大解除ができると思います。
参考: How to set time scale zoom in ChartJS?
解決法2
解決法2は、chartjs-plugin-zoom.js自体を書き換える方法です。
おそらくGithubで公開されているソースはツール(たぶん gulp)などでminifyする前のものですが、
問題の箇所としてはzoomNumericalScale()
関数を書き換えればいいです。
たとえばminDelta
は最小値の変更数を保存される変数で、これがゼロ以下の場合は拡大されます。つまりminDelta
の総合計がゼロ以下なら拡大、ゼロ以上ならmaxを超えた縮小がされるということです。
……言葉にするとややっこしいので、minifyされたままの状態で書き換えるなら以下のように書き換えてください。コードを読む方が分かりやすいかと思います。
(以下のコードはjavascriptの整形ツールで一度展開したコードです)
変更前
function u(o, e, t, n) {
var a = o.max - o.min,
i = a * (e - 1),
m = o.isHorizontal() ? t.x : t.y,
r = (o.getValueForPixel(m) - o.min) / a,
l = i * r,
u = i * (1 - r);
o.options.ticks.min = c(n, o.min + l)
o.options.ticks.max = s(n, o.max - u)
}
変更後
var old_l=0;
var old_u=0;
function u(o, e, t, n) {
var a = o.max - o.min,
i = a * (e - 1),
m = o.isHorizontal() ? t.x : t.y,
r = (o.getValueForPixel(m) - o.min) / a,
l = i * r,
u = i * (1 - r);
old_l += l;
old_u += u;
if (old_l < 0) {old_l = l=0;}
if (old_u < 0) {old_u = u=0;}
o.options.ticks.min = c(n, o.min + l)
o.options.ticks.max = s(n, o.max - u)
}
シンプルにグローバル変数を加えて、minDeltaとmaxDeltaのそれぞれの総計を記憶しています。
これで範囲を超えずに拡大と縮小ができます。