d3.jsな日々

d3.jsでデータ可視化する際の覚書です

インタラクティブの実装

SVG要素にインタラクティブ機能を実装するには、.on() を使う。

svg.selectAll("rect")
	.data(dataset)
	.enter()
	.append("rect")
.................
        .on("mouseover", function() {
		d3.select(this)
		.attr("fill", "orange");
	 })
	.on("mouseout", function(d) {
		d3.select(this)
		.transition()
		.duration(250)
		.attr("fill", "rgb(0, 0, " + (d * 10) + ")");
	});

.on()の第一引数は動作の種類。
click
mouseover
mouseout
submit
などがある。

第二引数は匿名関数で、引数は、d, dおよびi, 引数なし、のいずれかになる(上の例では、引数なしとdの場合)


特定の要素でマウスEventを発生したくない場合は、CSS

pointer-events: none;

とする。

d3内でCSSを直接表記するには、

svg.append("text")
   .....
   .style("pointer-events", "none");

とする。

マウスクリックの発信元で処理を変える

テキストクリックで処理を行うには、

d3.select("p")
    .on("click", function(){....

のようになる。このケースでは、pタグをつけたテキストをクリックすると、function(){}で定義された処理が行われる。


では、複数のpタグテキストがある場合はどうするか。次のようになる。

d3.selectAll("p")
    .on("click", funciton(){
    var paragraphID = d3.select(this).attr("id");
    ...

これは、paragraphIDに、クリックされたpタグのid属性が代入される。

<p id="add">Add Items</p>
<p id="remove">Remove Items</p>

後は、このparagraphIDの内容で処理を変えれば良い。

dataとkey

通常、.data()の中身は単純な配列を入れる。1次元でも2次元でも、配列であることには変わらない。配列の要素はインデックスで指定するが、これは、0,1,2,....,nの数値である。
一方、任意の名前でデータの要素を指定したいことがある。これをd3.jsで実現するのがkeyである。

var dataset = [{key:0, value:10},
        {key:1, value:5},
        {key;2, value;18],
        .................
];

dataset自体は配列([]で指定)、中身の各要素はオブジェクト({}で指定)となる。オブジェクトの中の、key, valueと言った名前は任意に指定できる。

注意するのは、keyを使う場合、データは'd'のように直接取り出せない。'd.value'のように指定する必要がある。

var key = function(d) {
        return d.key;
}
var yScale = d3.scale.linear()
        .domain([0, d3.max(dataset, function(d) { 
        return d.value;
})]);
....
.data(dataset, key)  //上で定義したkey関数でdatasetをバインド
......

key関数を定義せずに

.data(dataset, function(d){
        return d.key;
})

としてもよい

Transitionの基本

アニメーションを実現するのが、.transition()。
基本構文としては、

.transition()
.duration(####)
.ease($$$$)
.attr(...) //変更したい属性
.......

となる。ここで、
####は、トランジションの時間(mSec)
$$$$は、トランジションの種類で、次のように基本種類+オプションの文字列で指定する。

基本種類
linear - リニア
poly(k) - k次関数
quad - 2次 = poly(2)
cubic - 3次 = poly(3).
sin - Sin関数
exp - 指数関数
circle - 1/4円
elastic(a, p) - オーバーシュート付きの弾性変形
back(s) - 駐車スペースへのバックをシミュレート
bounce - 跳ね返りをシミュレート

オプショ
in -正方向
out - 逆方向
in-out - 正→逆
out-in - 逆→正


さらに、.transition()と組み合わせてよく使うオプションには次がある。
.delay(####) トランジションの開始を####mSec遅らせる
.each("start", function(){};)
.each("end", function(){};)
.remove() トランジション終了後に削除する

Updateセレクション

d3.jsは、チェイン構文によってメソッドを次々とつないでいく。これは、上から下(あるいは左から右)へバトンを渡すようなイメージだ。
やりたい事を全て一連のチェインにすることも可能だが(その場合、受け渡される「バトン」は見えない)、データの変更がある場合やインタラクティブな描画を行う場合は、途中でいったんバトンを「保留」する方が効率が良い。

要素とデータの関係と、update, enter, exitは下図の関係にある。
f:id:yasuda0404:20130429223645p:plain

Updateセレクションは対応するデータが存在する要素である。

var bars = svg.selectAll("rect")	 //Select all bars
        .data(dataset);	

このUpdateセレクション('bar')について、必要な操作を行う。

bars.enter()
.append("rect")
.......
.......
})

bars.transition()
.duration(500)
.......
.......

bar.enter()
........

こうすることで効率的で、理解しやすいスクリプトになる

データの追加・削除

データの追加・削除は、

dataset.push(newNumber); //データセットの最後にnewNumberを追加
dataset.pop(); //データセットの最後の要素を削除
dataset.shift(); //データセットの最初の要素を削除、全要素をひとつずつ前へ

を用いる。

要素を追加・削除したデータセットを、再度バインドする。

var bars = svg.selectAll("rect")	
             .data(dataset);

要素を追加した場合は.enter().append()で新しいSVG要素を追加、要素を削除した場合は.exit()で余ったエレメントを削除する

bars.enter()	//References the enter selection (a subset of the update selection)
.append("rect")	//Creates a new rect
.attr("x", w)
.attr("y", function(d) { //Sets the y value, based on the updated yScale
    return h - yScale(d);
})
.attr("width", xScale.rangeBand())	//Sets the width value, based on the updated xScale
.attr("height", function(d) {	//Sets the height value, based on the updated yScale
    return yScale(d);
})
.attr("fill", function(d) {	//Sets the fill value
    return "rgb(0, 0, " + (d * 10) + ")";
});

bars.exit()	;

必要に応じて、スケーリングも再設定する