記事のタイトルの通り、円グラフをアニメーションさせながら表示させてみます。円グラフを0度から360度まで1周して表示されるアニメーションを作成してみます。基本てなことは棒グラフのアニメーションと一緒です。attr()メソッドで初期値を設定したら、transition()メソッドを呼びだします。その後に、変化後の数値を指定すればアニメーションができます。
ただ、、円グラフは棒グラフとは違い、単純に処理ができません。難しい点は扇形の座標の計算です。。ただD3.jsにはattrTween()メソッドとinterpolate()メソッドというものをりようすればこの問題はクリアできます。
サンプルコードの実行結果はこちら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!DOCTYPE html> <head> <meta charset="utf-8"> <title>D3.js 円グラフのアニメーション</title> <script src="../js/d3.js"></script> <style> svg{ width:320px; height:320px; border:2px solid red;} .pie{ fill:yellow; stroke:green} </style> </head> <body> <h2>円グラフにアニメーションを付けてみる</h2> <svg id="graph"></svg> <script src="test.js"></script> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
var svgWidth = 320; // SVG要素の幅を設定 var svgHeight = 320; // SVG要素の高さを設定 var arrData =[50,25,12,6,3,2]; var color = d3.scale.category20(); var pie = d3.layout.pie(); // 円グラフレイアウト var arc = d3.svg.arc() .innerRadius(0) // 円グラフの内径 .outerRadius(100); // 円グラフの外径 var pieElements = d3.select("#graph") .selectAll("path") // path要素を指定 .data( pie(arrData) ); // データを要素に連結 pieElements.enter() // データの数だけ繰り返し .append("path") // データの数だけpath要素を追加 .attr("class","pie") // CSSクラスを指定 .attr("transform","translate(" + svgWidth / 2 + ", " + svgHeight / 2 + ")") //円グラフを中心に配置 .style("fill",function(d,i){ //配列内の色を返却 return color(i); //標準10色の中から色を返す }) .transition() .duration(600) .delay(function(d,i){ // 描画して表示する円グラフをずらす return i * 600; }) .ease("linear") // 直線的な動きにする .attrTween("d", function(d,i){ var interpolate = d3.interpolate( // 各部分の開始角度 { startAngle: d.startAngle, endAngle: d.startAngle }, // 各部分の終了角度 { startAngle: d.startAngle, endAngle: d.endAngle } ); return function(t){ return arc(interpolate(t)); } }); |
サンプルコードを実行すると、円グラフが0度から360度まで1周して表示されます。
実行結果のようにするには時間差で表示するのがポイントです。下記のようにdelay()メソッドを使い待ち時間を指定します。後から表示される扇ほど、待機時間がながくなります。
.delay(function(d,i){
return i * 600
})
次が、表示する扇形の座標計算です。時間の経過に応じて図形を変形させる必要があります。属性値を時間の経過に合わせて変化させるときに使うのが、attrTween()メソッドです。1番目のパラメーターに変化させたい属性名、2番目のパラメータに関数を指定します。この関数からの戻り値が設定される座標です。
大事なのは、この関数からの戻り値である座標の情報です。どうやって取得すればいいのかという問題があります。円を1周させながら表示するので、0度から360度までの変化させればいいと思いますが、1つしか扇形がない、データが1つしかない場合のみ有効です。扇形複数ある場合は、各扇の角度に応じて処理する必要があります。
この問題を保管して解決するのが d3.interpolate()で、パラメーターには下記のように
各扇の部分の開始・終了の角度を指定します。
最初の{・・・}がアニメーション開始時の扇形の開始角度と終了角度を指定します。
次の{・・・}がアニメーション終了時の扇形の開始角度と終了角度を指定します。
var interpolate = d3.interpolate(
// 各部分の開始角度
{ startAngle: d.startAngle, endAngle: d.startAngle },
// 各部分の終了角度
{ startAngle: d.startAngle, endAngle: d.endAngle }
);
表示する円グラフの座標値は、下記のようにして、返します。
アニメーションする前はattr("d",arc)として計算しましたが、interpolate()メソッドを利用する場合は、下記のように書きます、tは時間を表しています。
return function(t){
return arc(interpolate(t));
}
上記を踏まえて実行すると、0度から360度まで1周しながら円が表示されますが、動きが各扇の表示でカクカクしてます。これは、アニメーションの開始時と終了時にゆっくりなるからです。なので、扇を1つずつ表示するたびにアニメーションが加速・減速を繰り返すので、動きがカクカクします。円を1つ表示するので動きを直線的なものにしたほうが滑らかに見えます。
D3.jsでアニメーションの動きを指定するにはease()メソッドを使います。直線的な動きをするならease("linear")をtransition()の後に書きます。動きを指定する文字に続けて「-」で区切り「in」とか「out-in」といった文字を追記すると、動きの加速具合を変更することができます。たとえばease("sin-out")と書きます。
*動きを示す文字に付加できる文字列
「in」「out」「in-out」「out-in」