前回の記事で紹介したQiitaのタグの情報を使い、ドラッグして範囲を指定し、ドリルダウンできる散布図を作ってみました。
今回の完成がこちらです。
http://bl.ocks.org/ganezasan/9098135dae6ce1552194
最初にこのコードは汎用化はできていません。
まず動くというのを目指しました。
そのため、NVD3のライブラリを直接いじっています。
なので、試す際にはこのリポジトリにおいてあるnv.d3.jsを使用しないと動作しません。
今後もう少し綺麗に書いてNVD3にPull Requestを送りたいと思います。
修正したソースコード部分
.extent {
stroke: #cfd7e5;
fill: #cfd7e5;
fill-opacity: 0.4;
shape-rendering: crispEdges;
}
// brushオブジェクト
var callback = function(){
console.log("bashend");
var brushElem = d3.select('.extent');
var _x = new Number(brushElem.attr('x'));
var _y = new Number(brushElem.attr('y'));
var _width = new Number(brushElem.attr('width'));
var _height = new Number(brushElem.attr('height'));
// xMin,xMax等設定&選択範囲内のデータ抽出。
var xMin = 0;
var xMax = 0;
var yMin = 0;
var yMax = 0;
var newState = {"disabled":[]};
//選択範囲が0じゃない場合
if (_width != 0 && _height != 0){
xMin = x.invert(_x);
xMax = xMin + x.invert(_width);
yMin = y.invert(_y + _height);
yMax = y.invert(_y);
data = data.filter(function(row,i){
var rowX = row["values"][0]["x"];
var rowY = row["values"][0]["y"];
if(xMin <= rowX && rowX <= xMax && yMin <= rowY && rowY <= yMax){
newState.disabled[i] = false;
row.disabled = false;
return true;
}else{
newState.disabled[i] = true;
row.disabled = true;
return false;
}
});
}else{
//単純なクリックの場合、スケールを戻す
data = data.filter(function(row,i) {
row.disabled = false;
newState.disabled[i] = false;
});
}
state.disabled = newState.disabled;
//グラフ再描画
dispatch.stateChange(state);
chart.update();
//選択範囲を非表示に
d3.select('.extent').attr({width: 0, height: 0, x: 0, y: 0});
};
var _brush = d3.svg.brush()
.x(x) // x軸を選択可能範囲に指定
.y(y).on('brushend',callback);
var wrapEnter = d3.select(".nv-groups");
wrapEnter.call(_brush).selectAll("rect");
ちょっとだけ解説
まず範囲指定するためにd3.svg.brush()を使用しています。
d3.svg.brush()を使用すると「rect」タグが自動で作られクラス名が「extent」になっています。
<rect class="extent" x="0" width="0" y="0" height="0" style="cursor: move;"></rect>
範囲指定後の「bashend」のイベントを拾って「extent」のx,y,width,heightを取得し、範囲内のデータをfilterで絞り込み表示するようにしています。
次にドットを表示する、しないについて、NVD3の散布図「nv.models.scatterChart」にはlegend(凡例)を表示する機能があり、凡例をクリックした際に、凡例と同じグループのドットを表示する、しないを指定できる機能があり、今回はそちらを利用しました。
具体的に言うと、
もともとの散布図のデータはこうなっています。
[{key: グループ名 ※legend(凡例)として表示される,
values:[{
x: x軸の位置
, y: y軸の位置
, size: 円の大きさ
, shapes: '円の形'
}]}]
再描画時にドットを表示しない場合は「disabled:true」を追加します。
[{disabled: true,
key: グループ名 ※legend(凡例)として表示される,
values:[{
x: x軸の位置
, y: y軸の位置
, size: 円の大きさ
, shapes: '円の形'
}]}]
さらにstate.disabledというオブジェクトにgroupの数true,falseの配列が入っているので、表示したくないgroupと同じ配列番号にtrueを入れて上げ、
以下のメソッドを実行すると再描画されます。
dispatch.stateChange(state);
chart.update();
まとめ
d3.js単体で作った方が処理速度は早い気がしますが、
nvd3は便利な関数が多いので好きです。
散布図にドラッグでドリルダウン機能はすごく欲しかったので、
できてよかったです。
ソースはアップしているので、
よかったら使ってみてください。