huruyosi’s blog

プログラミングとかインフラとかのメモです。

General Update Pattern, IIIを読む

アニメーションを行うことで、 .enter()、.update()、.exit()を可視化する

最後の General Update Pattern, III では .data()メソッドに与えられたデータに追加、更新、削除が生じた時に、それぞれに異なるアニメーションを行います。

アニメーションの指定

動きは下の3つのパラメータで指定します。

  • transition(): アニメーションを開始
  • duration(ms): アニメーションを開始してから終了するまでの時間をミリ秒で指定
  • ease('linear'): 値の変化量

transition()jQueryanimateと思うとなんとなく意味が分かってきます。ease()の引数の意味は D3.js Easing Checker が参考になります。

データが追加された

 text.enter().append("text")
      .attr("class", "enter")
      .attr("dy", ".35em")
      .attr("y", -60)
      .attr("x", function(d, i) { return i * 32; })
      .style("fill-opacity", 1e-6)
      .text(function(d) { return d; })
    .transition()
      .duration(750)
      .attr("y", 0)
      .style("fill-opacity", 1);

.transition()の後にアニメーション後のy座標(attr("y",0"))と透明度(.style("fill-opacity", 1))を指定しています。.transition()の前を見るとy座標に-60、透明度に1e-6を指定しているので、アニメーションは.append("text")で追加された後にアルファベットが透明な状態から不透明になりながら上から降りてきます。

データが更新された(今回の場合では値は変わらない)

text.attr("class", "update")
    .transition()
      .duration(750)
      .attr("x", function(d, i) { return i * 32; });

duration(750)の後に.attr("x", function(d, i) { return i * 32; })とあるので、アルファベットのx座標を変えて新しい位置へ移動します。

データが削除された

text.exit()
      .attr("class", "exit")
    .transition()
      .duration(750)
      .attr("y", 60)
      .style("fill-opacity", 1e-6)
      .remove();

追加の場合と同様に x座標と透明度を変えることで、不透明の状態から下に降りながら透明なっていき、removwe()で削除されます。

処理

// 表示するアルファベットの配列を作成します。
var alphabet = "abcdefghijklmnopqrstuvwxyz".split("");

var width = 960,
    height = 500;

// svgタグを作成し、gタグを縦方向の中央に移動します。
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(32," + (height / 2) + ")");

function update(data) {

  // DATA JOIN
  // Join new data with old elements, if any.
  // データとデータのキーを取得する無名関数を与えます。
  var text = svg.selectAll("text")
      .data(data, function(d) { return d; });

  // UPDATE
  // Update old elements as needed.
  // 更新されたデータ
  // 更新後の位置に移動します。
  text.attr("class", "update")
    .transition()
      .duration(750)
      .attr("x", function(d, i) { return i * 32; });

  // ENTER
  // Create new elements as needed.
  // 追加されたデータ
  // 表示されている文字の上に追加され、透明な状態から下に降りながら不透明になります。
  text.enter().append("text")
      .attr("class", "enter")
      .attr("dy", ".35em")
      .attr("y", -60)
      .attr("x", function(d, i) { return i * 32; })
      .style("fill-opacity", 1e-6)
      .text(function(d) { return d; })
    .transition()
      .duration(750)
      .attr("y", 0)
      .style("fill-opacity", 1);

  // EXIT
  // Remove old elements as needed.
  // 削除されたデータ
  // 下に移動しながら透明になり、消えます。
  text.exit()
      .attr("class", "exit")
    .transition()
      .duration(750)
      .attr("y", 60)
      .style("fill-opacity", 1e-6)
      .remove();
}

// The initial display.
// 最初の表示を行います。a~zまでの文字が描画されます。
update(alphabet);

// Grab a random sample of letters from the alphabet, in alphabetical order.
// 1.5秒ごとにアルファベットをランダムに決め、アルファベット順に表示します。
setInterval(function() {
  update(d3.shuffle(alphabet)
      .slice(0, Math.floor(Math.random() * 26))
      .sort());
}, 1500);

General Update PatternのI~IIIを読んでみて

見えるぞ!私にもd3.jsが見える!

データの増減が分かったでの、やりたかったグラフのデータ更新を行えそうな気がしてきました。これまでは動きがついているサンプルを見ていても、さっぱり理解できなかったのが相当改善されています。

参考ページ

lisia.hatenadiary.jp