D3.js の面白い点の一つが、transition によるアニメーションです。DOMツリーの中の任意のノードを選択し、位置、色、大きさなどを変更できます。色々なtransition を試しているうちに、少しコツがあることに気づいたので、今回はそれを紹介します。
transition によるSVG オブジェクトの移動 二つの方法
SVGをHTML 内につくり、それをキャンバスに色々な形のオブジェクトを書き出せます。一度書き出したオブジェクトを別の位置に移動させる場合にtransition を利用できます。その際、二つの方法があります。
translate を利用する方法
translate はオブジェクトの位置を相対値で変更します。例えば、オブジェクトを上に50px、左に100px 移動させるときは、translate(-50,-100)となります。D3 でこれを実行するときは、次のように書きます*1。
d3.select("circle").transition().attr("transform","translate(-50,-100)");
直接xy座標を書き換える方法
transition はDOM オブジェクトの属性を上書きすることもできます。この場合は移動先の座標を書きます。D3 では次のようにします。
d3.select("circle").transition().attr("cx","50px").attr("cy","100px");
この例だと、SVG オブジェクトの左上を原点として、右に50px 、下に100pxの位置に円の中心が移動します。
二つの方法の違い
上の二つの方法は一見同じ効果をもたらします。でも、細かく見ると異なる結果になります。その違いを示すために簡単なデモを作ってみました。下のデモでは二つのSVG オブジェクト(長方形)のそれぞれの上に円がかかれています。また、円の中心座標が示されています。では二つの方法を使って、円を移動させてみましょう。長方形の上にあるtransition というボタンを押すと、上の円はtranslate を利用して、下の円は座標を上書きして移動します。移動が終わったあとで、それぞれの円の中心座標が赤字で示されます。中心座標を取得するためのfunctionを二つの円で共通にしてあります。
二つの円の動きは同じですが、上の円は、移動後もスタート位置にあると表示されます。一方、下の円は、移動後の座標が示されます。
詳しく見ると何が違うのか?
二つの移動の結果の違いは、DOM を見てみると分かります*2。
translate を利用して移動したあとのcircle
<circle r="30" cx="150" cy="150" transform="translate(-50,-50)" style="fill: rgb(255, 0, 0); stroke: none;"></circle>
座標を上書きして移動した後のcircle
<circle r="30" cx="100" cy="100" style="fill: rgb(255, 0, 0); stroke: none;"></circle>
ご覧のように、translate を利用して移動するとDOM の属性値が変更されずに、transfer ノードが追加されます。座標を上書きして移動した場合は、属性値が上書きされています*3。
まとめ 二つの移動方法を使い分けよう
今回紹介した二つの移動方法は、どちらも利用価値があるように思えます。translate を利用する方法は、最初にどこに書いたかという情報を残しているので、移動させた最後にもとの位置に戻すことができます。また、座標を上書きする方法は、移動した先のオブジェクトの座標を基準に新しいイベントを生成する場合に便利です。二つの方法を上手く使い分けることが大事です。