D3.js 基本7 – transitionでアニメーションを表示する

このページは"D3.jsチュートリアル"シリーズの7 / 20です。

いよいよアニメーションでSVG要素を動かしてみます。といっても簡単にできます。基本的には.transition()の後に続いて、変化させた結果の状態を設定すれば、自動的に動きます。基本的にはどんな属性でも動かすことができます。
まず手始めに、大きさを小さくするアニメーションを作ってみます。

 

transition()で大きさを変える

結果:

d3基本7-2transition_smaller
画像をクリックするとアニメーションのページが開きます。

javascriptのコード:

var width = 960,
height = 700;

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);

var data = [100,200,300];

var circles = svg.selectAll("circle").data(data).enter()
				.append("circle")
				.attr("cx", function(d){ return d;})
				.attr("cy", function(d){ return d;})
				.attr("r", 30)
				.attr("fill", "green");

// .transition()で半径を3にする。
circles.transition().delay(500).duration(1000)
		.attr("r",3);

解説:
まずはごく普通にデータを使って3つの円を作っています。これが最初に表示される円です。半径rは30になっています。
アニメーションを作る時は、それにつづいて.transition()を挟んで、その後に結果の状態を設定するだけでOKです。

circles.transition().delay(500).duration(1000)
		.attr("r",3);

.attr(“r”,3)で半径を3にしています。実はこれだけで半径が30から3になります。
しかしそれではページを開いてすぐに、素早くアニメーションが終わってしまうので、ここではtransitionのオプションとして、delay()とduration()を設定しています。
delay()はアニメーションが始まるまでの待ち時間で、delay(500)ならばページを開いて0.5秒後にスタートします。
duration()はアニメーションが始まってから終わるまでにかかる時間です。duration(1000)なので1秒で半径が30から3に変わるように設定しました。

 

アニメーションの動き方を変える

結果:

d3基本7-3transition_multi_and_ease
画像をクリックするとアニメーションのページが開きます。

javascriptのコード:

var width = 960,
height = 700;

var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);

var data = [100,200,300];

var circles = svg.selectAll("circle").data(data).enter()
				.append("circle")
				.attr("cy", 10)
				.attr("cx", function(d){ return d;})
				.attr("r", 10)
				.attr("fill", "green");

// transition()の設定。
circles.transition()
		.delay(400)
		.duration(function(d){return d*10; }) //
		.ease("bounce") // ボールが跳ねるアニメーション。
		.attr("cy", function(d){ return d;})
		.attr("fill", "red");

解説:
今回はtransition()の後に、ease(“bounce”)を加えています。またcyで円の高さの位置、durationでアニメーションの長さもデータにしたがって変えています。
ease()でアニメーションの動きを変えることができます。bounceはボールが跳ねるような動き、backは車のバックのような動き、linearなら一定、expなら加速度的に速くなります。
詳しくは、D3.js tips&tricks:D3で使えるアニメーションの動きをまとめてデモンストレーションで、アニメーションのデモで見ることができます。

 

3.散布図をアニメーションで表示してみる:

D3.js 基本5 – Axisで軸を表示して散布図を作ると同じコードを使ってアニメーションで表示してみます。ほとんど同じなので、変更する部分は少しです。
結果:

d3基本7-4transition_scatterplot
画像をクリックするとアニメーションのページが開きます。

変更した部分のコード:

var circles = svg.selectAll("circle")
				.data(gdp)
				.enter()
				 .append("circle")
				 .attr({cx:0,r:1,fill:"gray"}) //最初はcx:0で、色は灰色にしておく。
				 .attr("cy", function(d){ return yScale(d["gdp"]); });

 circles.transition().duration(2000)
		 .delay(function(d,i){ return xScale(d["年"]); }) // 年ごとに動き始める時間を変える。
	 	.ease("circle-out")
 		.attr("r",10)
		.attr("cx", function(d){ return xScale(d["年"]); }) // cxを所定の位置に。
		.attr("fill", function(d){ return colorCategoryScale(d["増減"]); }); //色を所定の色に。

解説:
アニメーションは左から右に動いて、所定のデータの位置に収まるようになっています。また色も灰色から徐々に色がつくようにしています。
そうするためには、最初の円ではcxを0に、fillをgrayにしています。

次にtransition()のうしろでいろいろなアニメーションの設定をしています。
delay()を年ごとに変えることで、最近の年ほど始まるのが遅くしています。
ease()ではcircleという動きの逆方向であるcircle-outを使っています。
cxを年にして、x方向の所定の位置に向かって動くようにしています。
さらにfillにカラーを設定して、最終的には灰色からカラフルな色に変わるようにしています。

 

線グラフをアニメーションで動かす

D3.js 基本6 – pathで線グラフを作るで作った線グラフでもやってみます。
結果:

d3基本7-5transition_linechart
画像をクリックするとアニメーションのページが開きます。

変更した部分のコード:

var line = d3.svg.line()
.x(function(d) { return xScale(d["年"]); })
.y(function(d) { return height; }) //最初にheight=一番下に直線を作る。
.interpolate("cardinal");

linePath.transition().delay(1000).duration(1000).ease("elastic-in")
.call(moveLine) // callでlineを更新する。
.attr("d", line);

function moveLine(){
line.x(function(d) { return xScale(d["年"]); })
.y(function(d) { return yScale(d["gdp"]); });
}

解説:
線グラフはpathを使っているので少しややこしいところがあります。
最初にラインpathを作る時は、.y(function(d) { return height; }) のようにして、グラフの一番下に寝かせるように直線を引くだけにします。

次にtransition()以下でアニメーションの設定をしていますが、ラインpathを新たにデータの位置に作り直すために、moveLine()という関数を下で作った後、call(moveLine)で関数を呼び出しています。.call()を使えばこのように、transition()
の下でも関数を使うことができます。

 

3と4の実際のコード

「3.散布図をアニメーションで表示してみる」と「4.線グラフをアニメーションで動かす」の実際のコードは長いので下に載せておきます。

「3.散布図をアニメーションで表示してみる」の実際のコード:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<!-- 軸の属性を決めている。特にfill:none;にしないと真っ黒になる。-->
	<style>
		.axis text {
		  font: 10px sans-serif;
		}

		.axis path,
		.axis line {
		  fill: none;
		  stroke: #000;
		  stroke-width: 2;
		  shape-rendering: crispEdges;
		}
	</style>
	<title>3.散布図をアニメーションで表示してみる</title>
</head>
<body>

	<script src="http://d3js.org/d3.v3.min.js"></script>

	<script>

// 軸の分も表示されるように、マージンを作っておく。
var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 700 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// transfromでマージンの分だけ位置をずらしている。
var svg = d3.select("body").append("svg")
			.attr("width", width + margin.left + margin.right)
			.attr("height", height + margin.top + margin.bottom)
			.append("g")
			.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var gdp = [
			{年: 2007, gdp: 524, 増減: "up"},
			{年: 2008, gdp: 518, 増減: "down"},
			{年: 2009, gdp: 490, 増減: "down"},
			{年: 2010, gdp: 512, 増減: "up"},
			{年: 2011, gdp: 510, 増減: "down"},
			{年: 2012, gdp: 517, 増減: "up"},
			{年: 2013, gdp: 525, 増減: "up"}
			];

var xScale = d3.scale.linear()
				.domain([2007,2014])
				.range([0,width]);

var yScale = d3.scale.linear()
				.domain([480,530])
				.range([height,0]);

var colorScale = d3.scale.linear()
					.domain([480,550])
					.range(["blue","red"]);

var colorCategoryScale = d3.scale.category10();

// 軸を設定する。
var xAxis = d3.svg.axis()
			    .scale(xScale)
			    .orient("bottom")
			    .tickSize(6, -height) // 棒の長さと方向。
				.tickFormat(function(d){ return d+"年"; }); // 数字に年をつけている。

var yAxis = d3.svg.axis()
				.ticks(5) // 軸のチックの数。
			    .scale(yScale)
			    .orient("left")
			    .tickSize(6, -width);

// gの中でyAxisをcallして、y軸を作る。
svg.append("g")
	.attr("class", "y axis")
	.call(yAxis)
    .append("text")
      .attr("y", -10)
	  .attr("x",10)
      .style("text-anchor", "end")
      .text("GDP(兆円)");

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);		 

var circles = svg.selectAll("circle")
				.data(gdp)
				.enter()
				 .append("circle")
				 .attr({cx:0,r:1,fill:"gray"}) //最初はcx=0で、色は灰色にしておく。
				 .attr("cy", function(d){ return yScale(d["gdp"]); });

 circles.transition().duration(2000)
		 .delay(function(d,i){ return xScale(d["年"]); }) // 年ごとに動き始める時間を変える。
	 	.ease("circle-out")
 		.attr("r",10)
		.attr("cx", function(d){ return xScale(d["年"]); }) // cxを所定の位置に、
		.attr("fill", function(d){ return colorCategoryScale(d["増減"]); }); //色を所定の色に。

	</script>

</body>
</html>

「4.線グラフをアニメーションで動かす」の実際のコード:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<!-- 軸の属性を決めている。特にfill:none;にしないと真っ黒になる。-->
	<style>
		.axis text {
		  font: 10px sans-serif;
		}

.axis path {
/*
fillとopacityで半透明な背景色。
		*/
		  fill: Aquamarine;
		  opacity: 0.1;
		  stroke: #000;
		  stroke-width: 1;
		  shape-rendering: crispEdges;
		}

		.axis line {
  		  stroke: #000;
  		  stroke-width: 1;
  		  shape-rendering: crispEdges;
		}

		.line {
		  fill: none;
		  stroke: DarkGreen;
		  stroke-width: 1.5px;
		}

	</style>
	<title>4.線グラフをアニメーションで動かす</title>
</head>
<body>	

	<script src="http://d3js.org/d3.v3.min.js"></script>

	<script>

var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 700 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

var svg = d3.select("body").append("svg")
			.attr("width", width + margin.left + margin.right)
			.attr("height", height + margin.top + margin.bottom)
			.append("g")
			.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var gdp = [
			{年: 2007, gdp: 524, 増減: "up"},
			{年: 2008, gdp: 518, 増減: "down"},
			{年: 2009, gdp: 490, 増減: "down"},
			{年: 2010, gdp: 512, 増減: "up"},
			{年: 2011, gdp: 510, 増減: "down"},
			{年: 2012, gdp: 517, 増減: "up"},
			{年: 2013, gdp: 525, 増減: "up"}
			];

var xScale = d3.scale.linear()
				.domain([2007,2014])
				.range([0,width]);

var yScale = d3.scale.linear()
				.domain([480,530])
				.range([height,0]);

var colorCategoryScale = d3.scale.category10();

var xAxis = d3.svg.axis()
			    .scale(xScale)
			    .orient("bottom")
			    .tickSize(6, -height)
				.tickFormat(function(d){ return d+"年"; });

var yAxis = d3.svg.axis()
				.ticks(5)
			    .scale(yScale)
			    .orient("left")
			    .tickSize(6, -width);

// lineの設定。
var line = d3.svg.line()
    .x(function(d) { return xScale(d["年"]); })
    .y(function(d) { return height; }) //最初にheight=一番下に直線を作る。
	.interpolate("cardinal");

svg.selectAll("circle")
	.data(gdp)
	.enter()
	 .append("circle")
	 .attr("r",5)
	 .attr("fill", function(d){ return colorCategoryScale(d["増減"]); })
	 .attr("cx", function(d){ return xScale(d["年"]); })
	 .attr("cy", function(d){ return yScale(d["gdp"]); });

// line表示。
var linePath = svg.append("path")
				 .datum(gdp)
				 .attr("class", "line")
				 .attr("d", line); // 上で作ったlineを入れて、ラインpathを作る。

svg.append("g")
	.attr("class", "y axis")
	.call(yAxis)
    .append("text")
      .attr("y", -10)
	  .attr("x",10)
      .style("text-anchor", "end")
      .text("GDP(兆円)");

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

linePath.transition().delay(1000).duration(1000).ease("elastic-in")
		.call(moveLine) // callでlineを更新する。
		.attr("d", line);	

function moveLine(){
	line.x(function(d) { return xScale(d["年"]); })
	    .y(function(d) { return yScale(d["gdp"]); });
}	 

	</script>

</body>
</html>

コメントを残す