前回はこちら
d3.jsでチャートを作る ラインチャートとバーチャートを2つのy軸上に描画する
次回はこちら
d3.jsでチャートを作る パイチャート

JSFiddleはこちら
X軸。今回はtimeを使用している。またrange()の指定は少しずらすために30からとなっている。
// x軸は日付。y軸にくっつけたくなかったので30からはじめている
var x = d3.time.scale().nice()
.domain(d3.extent(data, function (d) { return d.date; }))
.range([30, width]);
var yearMonthFormat = d3.time.format("%Y/%m");
var xAxis = d3.svg.axis().scale(x)
.orient('bottom')
.tickFormat(yearMonthFormat);
svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0, ' + height + ')')
.call(xAxis);
ツールチップ。
// ツールチップ
var focus = svg.append('g')
.attr('class', 'focus');
focus.append('rect')
.attr({ x: -10, y: -25, width: 105, height: 50 });
// circle
focus.append('circle')
.attr('class', 'profit')
.attr({ r: 5, cy: -15 });
focus.append('circle')
.attr('class', 'sales')
.attr({ r: 5 });
focus.append('circle')
.attr('class', 'expense')
.attr({ r: 5, cy: 15 });
// text
focus.append('text')
.attr('class', 'profit')
.style('text-anchor', 'end')
.attr({ x: 90, y: -15, dy: '.35em' });
focus.append('text')
.attr('class', 'sales')
.style('text-anchor', 'end')
.attr({ x: 90, dy: '.35em' });
focus.append('text')
.attr('class', 'expense')
.style('text-anchor', 'end')
.attr({ x: 90, y: 15, dy: '.35em' });
オーバーレイとツールチップの表示場所の指定。チャート上のどこにマウスがあっても表示したいのでオーバーレイはチャート全体を覆っている。mousemove()の冒頭でマウスの現在座標からその位置よりも左側に位置するデータをbisector()で取得している。それだけだとマウスが二つのデータ間にある場合、必ず左側のものが選ばれてしまうのでマウスとデータ間の距離を比較してツールチップを表示するべきデータを取得している。このx.invert()の使用方法はtime()でしか使用できないので注意。ordinal(), linear()の場合(linear()は違うのかも。調査していないので不明)はデータの幅とrange()、マウスの座標から当該のデータを探し出す必要がある(詳細は下記参考を参照してもらいたい)。
// オーバーレイ
svg.append('rect')
.attr('class', 'overlay')
.attr({ width: width, height: height })
.on('mouseover', function () { focus.style('display', 'block'); })
.on('mouseout', function () { focus.style('display', 'none'); })
.on('mousemove', mousemove);
var bisectDate = d3.bisector(function (d) { return d.date; }).left
, formatValue = d3.format(",.2f")
, formatCurrency = function (d) { return formatValue(d) + '億円'; };
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0])
, i = bisectDate(data, x0, 1);
if (i < data.length) {
var d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0; // 一番近いデータを取得
focus.attr('transform', 'translate(' + (x(d.date)) + ',' + y(d.sales) + ')');
focus.select('text.profit').text(formatCurrency(d.profit));
focus.select('text.sales').text(formatCurrency(d.sales));
focus.select('text.expense').text(formatCurrency(d.sales - d.profit));
}
}
参考
Inversion with ordinal scale
0 件のコメント:
コメントを投稿