サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

D3.js入門 04: グラフにアニメーションを加える


D3.js入門 03: 立て棒グラフに軸の記載を加える」(以下「D3.js入門 03」)で数値軸と項目軸のついた縦棒グラフをつくりました。グラフにするデータを差し替えて手直ししたうえで、アニメーションも加えてみましょう。今回は先にでき上がりのサンプル001をお見せします。

サンプル001■D3.js: Vertical SVG Bar Chart with Transition


>>画像をクリックでjsdo.itへ

01 棒グラフのデータを差し替える

まずは、TSV(タブ区切り)ファイルを、つぎのデータで差し替えましょう。これは、アルファベット26文字が英語に使われる割合で、Robert Lewand『Cryptological Mathematics』による統計です(Googleスプレッドシート)[*1]。「D3.js入門 03」で書いたコード002は、読み込んだTSVのデータにもとづいて、グラフの棒の長さと幅だけでなく、数値や項目の軸も差し替えるようにしました。ですから、これだけで新しいグラフができてしまうのです(図001)。

data.tsv

name	value
A	.08167
B	.01492
C	.02782
D	.04253
E	.12702
F	.02288
G	.02015
H	.06094
I	.06966
J	.00153
K	.00772
L	.04025
M	.02406
N	.06749
O	.07507
P	.01929
Q	.00095
R	.05987
S	.06327
T	.09056
U	.02758
V	.00978
W	.02360
X	.00150
Y	.01974
Z	.00074

図001■グラフの棒だけでなく数値と項目の軸も変わった

図001
[*1] アーサー・コナン・ドイル『踊る人形』でシャーロック・ホームズは、この事実から暗号文の「E」をただちに見抜きました。

02 数値軸の書式を変える

数値軸の書式を変えましょう。データの値からは、パーセンテージの方が適しているからです(図002)。axis.ticks()メソッドで、軸のメモリ間隔と単位が定められます。第1引数は、軸をメモリでいくつに分けるかです。大まかな数値でかまいません(値を少し増減しても調整されて、メモリは変わらなかったりします)。第2引数には'%'を渡します。また、項目数が多いので、左右マージンは値を少し減らしました。


// var margin = {top: 20, right: 30, bottom: 30, left: 40};
var margin = {top: 20, right: 20, bottom: 30, left: 30};

d3.tsv('data.tsv', type, function(error, data) {

	elements.append('g')

		// .call(d3.axisLeft(y));
		.call(d3.axisLeft(y).ticks(10, '%'));

		});
});

図002■グラフの数値軸の単位が%になった

図002

03 グラフの棒をアニメーションで伸ばす

selection.transition()メソッドを使うと、CSSのtransitionプロパティと同じようなやり方でアニメーションが加えられます。戻り値のオブジェクトに対して、つぎのようにメソッドtransition.duration()でアニメーションの時間、 transition.delay()は始まるまでのタメ(遅れ)、 transition.attr()に変化させる属性と値をそれぞれ与えます。これで、ページを読み込んだとき、グラフの棒が伸びながら表れます。 もっとも、アニメーションの動きは期待と大きく異なるでしょう(図003)。


d3.tsv('data.tsv', type, function(error, data) {

	elements.selectAll('.bar')

		.attr('y', function(d) {
			return getY(d);
		})
		.attr('width', x.bandwidth())
		.transition()
		.duration(500)
		.delay(function(d, i) {
			return i * 50;
		})
		.attr('height', function(d) {
			return height - getY(d);
		});
});

図003■グラフの棒が上端から項目軸に向かって伸びる

図003

画面の垂直軸は下が正の方向です。したがって、グラフの棒は上端を決めて、下に向けて長さが定められています。そのため、映画『The Matrix』の有名な映像のような、下に向かうさみだれのアニメーションになってしまったのです。しかし、下端から上に向けて長方形は描けませんでした。ではどうしたらよいかといいますと、垂直座標(y属性)を、つぎのように項目軸の位置から、棒の伸びに合わせて上端に動かしてゆくのです。なお、transition.ease()メソッドで、アニメーションの動きに変化を与えました。引数のイージング関数d3.easeElasticOut()で、アニメーションの終わりがバネのように弾みます。


d3.tsv('data.tsv', type, function(error, data) {

	elements.selectAll('.bar')

		.attr('y', height)  /* function(d) {
			return getY(d);
		}) */

		.transition()
		.duration(500)
		.delay(function(d, i) {
			return i * 50;
		})
		.ease(d3.easeElasticOut)
		.attr('y', function(d) {
			return getY(d);
		})
		.attr('height', function(d) {
			return height - getY(d);
		});
});

これで、前掲サンプル1の伸びる動きで表れる棒グラフができ上がりました。スクリプトは以下のコード001にまとめたとおりです。つぎのCSSを加えて、棒にポインタが重なったときの色を変えました。


.bar:hover {
	fill: brown;
}

コード001■棒グラフを伸びる動きで表示する


var chart = d3.select('.chart');
var margin = {top: 20, right: 20, bottom: 30, left: 30};
var width =  +chart.attr('width') - margin.left - margin.right;
var height = +chart.attr('height') - margin.top - margin.bottom;
var x = d3.scaleBand()
	.rangeRound([0, width]).padding(0.1);
var y = d3.scaleLinear()
	.rangeRound([height, 0]);
var elements = chart.append('g')
	.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
d3.tsv('data.tsv', type, function(error, data) {
	x.domain(data.map(getName));
	y.domain([0, d3.max(data, getValue)]);
	elements.append('g')
		.attr('class', 'axis axis--x')
		.attr('transform', 'translate(0,' + height + ')')
		.call(d3.axisBottom(x));
	elements.append('g')
		.attr('class', 'axis axis--y')
		.call(d3.axisLeft(y).ticks(10, '%'));
	elements.selectAll('.bar')
		.data(data)
		.enter().append('rect')
		.attr('class', 'bar')
		.attr('x', function(d) {
			return getX(d);
		})
		.attr('y', height)
		.attr('width', x.bandwidth())
		.transition()
		.duration(500)
		.delay(function(d, i) {
			return i * 50;
		})
		.ease(d3.easeElasticOut)
		.attr('y', function(d) {
			return getY(d);
		})
		.attr('height', function(d) {
			return height - getY(d);
		});
});
function type(d) {
	d.value = +d.value;
	return d;
}
function getName(d) {
	return d.name;
}
function getValue(d) {
	return d.value;
}
function getX(d) {
	return x(d.name);
}
function getY(d) {
	return y(d.value);
}


作成者: 野中文雄
更新日: 2017年3月4日 スクリプトの無駄を1箇所修正。
作成日: 2017年2月4日


Copyright © 2001-2017 Fumio Nonaka.  All rights reserved.