こんにちは。きんくまです。
引き続きd3.jsです。
今回はデータと同期するためのupdate, enter, exitについてです。
参考リンク
>> Binding data
>> Let’s Make a Bar Chart
>> Three Little Circles
例えば[1,2,3]というデータがあったとして、それをもとにしたグラフを作るとします。
htmlのbodyの中身は空だとします。
まず、どこにそのデータをいれるかを選択します。
d3.select('body').selectAll('div');
htmlのbodyが空なので、selectAllでdivを選択しても空なのですが、d3に対象を始めに教えてあげる必要があるためにまずselectします。
次にデータの同期を開始します。
var bardata = [1,2,3]; d3.select('body').selectAll('div') .data(bardata);
これでデータの同期ができました。ただ、同期するべきdivの個数が0なのでまだ何もすることができません。
この対象となるhtmlやsvgの要素数とデータの個数に差がでてきたときに必要なメソッドがenterとexitです。
enterは対象がデータの個数より少ないときに
exitは対象がデータの個数より多いときに
使います。差分が出た時という感じ。
var bardata = [1,2,3]; d3.select('body').selectAll('div') .data(bardata) .enter('div') .text('hello');
とやると3つのhelloが表示されます。同期したデータを使いたいときには関数を引数に入れればOKです。
var bardata = [1,2,3]; d3.select('body').selectAll('div') .data(bardata) .enter('div') .text(function(d){ return 'data = ' + d; });
同じようにexitもできます。
これをふまえて作ってみたデモ
今回作ったもの。最初のデータが[1, 3, 5, 7]で、棒グラフで表します。
+-ボタンを押すとその配列にデータを追加したり、削除したりします。
それをグラフで同期します。
html
<!doctype html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>D3 Sample</title> <style> html, body { margin: 0; } body{ background: white; } #container{ padding: 15px; position: relative; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; } .bar{ position: absolute; width:20px; background-color: steelblue; font-size: 10px; text-align: center; color:white; } .push_button{ border:1px solid #ccc; background-color: #eaeaea; text-align: center; width:60px; height: 30px; box-sizing: border-box; padding-top: 3px; font-size: 16px; cursor: pointer; display:inline-block; } .push_button:first-child{ margin-right: 10px; } .button_area{ padding: 10px; } </style> </head> <body> <div class="button_area"> <div id="minus_button" class="push_button">-</div> <div id="add_button" class="push_button">+</div> </div> <div id="container"></div> <script src="js/d3.js"></script> <script src="js/linechart.js"></script> </body> </html>
TypeScript
/// <reference path="definitions/d3.d.ts" /> module sample { var dataset = [1, 3, 5, 7]; export class LineChart{ count = 0; stepNum = 2; barWidth = 20; barHeightRatio = 10; constructor(){ this.count = dataset[dataset.length - 1]; this.appendDiv(); d3.select('#add_button').on('click', ()=>{ this.count = this.count + this.stepNum; dataset.push(this.count); this.appendDiv(); this.updateDiv(); //ここ! }); d3.selectAll('#minus_button').on('click', ()=>{ this.count = this.count - this.stepNum; dataset.pop(); this.removeDiv(); this.updateDiv(); //ここ! }); } getBarStyle():any{ var maxVal = dataset[dataset.length - 1]; return { height:(d:any)=>{ return d * this.barHeightRatio + 'px';}, left:(d:any, i:number)=>{ return i * (this.barWidth + 2) + 'px';}, top:(d:any)=>{ return (maxVal - d) * this.barHeightRatio + 'px';} }; } updateDiv(){ d3.select('#container') .selectAll('div') .data(dataset) .style(this.getBarStyle()); } appendDiv(){ d3.select('#container') .selectAll('div') .data(dataset) .enter() .append('div') .attr('class', 'bar') .text((d)=>{ return d; }) .style(this.getBarStyle()); } removeDiv(){ d3.select('#container') .selectAll('div') .data(dataset) .exit() .remove(); } } } var linechartMain = new sample.LineChart();
ボタンを押したあとにupdateDivを最後に呼んでいます。もしこれを呼ばないと、個数に差がでいない部分は更新されずそのままです。なので、こんな感じに表示されてしまって、うまくいきませんでした。
d3の基本が少しずつわかってまいりました!
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ