D3 メモ[API]

API Reference
https://github.com/mbostock/d3/wiki/API-Reference

Event

<div id="container">
  <button class="clickme">click me</button>
  <button class="clickme">click me</button>
  <button class="clickme">click me</button>
  <button class="clickme">click me</button>
</div>
  var data = [
    { name: 'button1' },
    { name: 'button2' },
    { name: 'button3' },
    { name: 'button4' }
  ];

  d3.selectAll('.clickme')
    .data(data)
    .on('click', function(d, idx) {
      var posX = d3.event.pageX + 'px';
      d3.select('#out')
        .style('left', posX)
        .text(function() { return d.name; });
    }, false);


選択した要素にはonでイベントハンドラを登録できる。
イベントオブジェクトはグローバルなd3.eventを参照することで、対象の要素のイベントを取得できる。


イベントの発生時のマウス位置を、特定の要素内の相対位置で取得したい場合には
d3.mouse(document.getElementById('container'))のようにすると[x, y]の配列で取得できる。d3.touch()もある。

  d3.selectAll('.clickme')
    .data(data)
    .on('click', function(d, idx) {
      var pos = d3.mouse(document.getElementById('container'));

      d3.select('#out')
        .text(function() {
          return d + ' at (' + pos[0] + ',' + pos[1] + ')';
        });
    }, false);

データ取得

  • d3.xhr(url, callback)
  • d3.text(url, callback)
  • d3.json(url, callback)
  • d3.xml(url, callback)
  • d3.html(url, callback)
  • d3.csv(url, callback)

サンプルなので、予め取得しておいたデータをjsonファイルとしてローカルに置いておく
http://gdata.youtube.com/feeds/api/videos?v=2&alt=jsonc&max-results=20&category=Music&format=5&orderby=rating&q=sonicyouth

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Demo</title>
  <!--[if lt IE 9]>
  <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
  <![endif]-->
  <style>
  .item { margin: 10px 0; }
  h5 { margin: 0; }
  ul {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .info {
    font-size: 85%;
  }
  </style>
  <script src="js/libs/d3/d3.v2.js" type="text/javascript"></script>
  <script src="js/libs/underscore-min.js" type="text/javascript"></script>
  <script src="js/app.js" type="text/javascript"></script>
</head>
<body onload="init();">
  <div id="container">
    <ul></ul>
  </div>
</body>
</html>
function init() {
  d3.json('data/videos.json', draw);
}

function draw(json) {
  d3.select('#container ul')
    .selectAll('li')
    .data(json.data.items)
    .enter()
    .append('li')
    .attr('class', 'item')
    .html(function(d, idx) {
      return buildHTML(d);
    });
}

function buildHTML(d) {
  var tmpl = _.template(
    '<h5><%- title %></h5>' +
    '<img src="<%- thumbnail %>" />' +
    '<div class="info">' +
    '<span class="like"><%- like %></span> | ' +
    '<span class="view"><%- view %></span>' +
    '</div>'
  );

  return tmpl({
    title: d.title,
    thumbnail: d.thumbnail.sqDefault,
    like: d.likeCount,
    view: d.viewCount,
  });
}

配列操作

d3で扱うデータは配列が基本なので、配列操作のメソッドが色々用意されている。

function init() {
  d3.json('data/videos.json', draw);
}

// 欲しいデータだけ取り出す
function initData(json) {
  return _.map(json.data.items, function(item) {
    return {
      title: item.title,
      fav: item.favoriteCount,
      view: item.viewCount,
      thumbnail: item.thumbnail.sqDefault
    };
  });
}

function draw(json) {
  var data = initData(json),
      fMax, fMin, split;

  // fav数の最小・最大値
  fMax = d3.max(data, function(d) { return d.fav; });
  fMin = d3.min(data, function(d) { return d.fav; });

  // min/maxは一度に取得できる [min, max]
  fExtent = d3.extent(data, function(d) { return d.fav; });

  // fav数の昇順ソート
  favAsc = data.sort(function(a, b) {
    return d3.ascending(a.fav, b.fav);
  });

  // view数が10,0000以上のアイテムだけ取り出して降順にソート
  split = d3.merge(d3.split(data, function(d) {
              return d.view < 100000;
            }))
            .sort(function(a, b) {
              return d3.descending(a.view, b.view);
            });

}

d3.scale

fav数に対応した大きさの図形を描きたい時など
実際のデータの値のまま使うと

function init() {
  d3.json('data/videos.json', draw);
}

function initData(json) {
  return _.map(json.data.items, function(item) {
    return {
      title: item.title,
      fav: item.favoriteCount
    };
  });
}

function draw(json) {
  var data = initData(json);

  d3.select('#container')
    .selectAll('div')
    .data(data)
    .enter()
    .append('div')
    .attr('class', 'bar')
    .style('background', '#0088ff')
    .style('font-size', '12px')
    .style('height', '16px')
    .style('width', function(d) {
      return d.fav + 'px';
    })
    .text(function(d) {
      return d.title;
    });

}

fav数によっては、windowサイズを大きくはみ出してしまうので
例えば、最大でもwindow幅以内にして全データをスケールしたい場合にはScales APIを使う。

d3.scale.linear()

デフォルトで変域・範囲が0~1のスケールを作るので、必要な変域と、範囲を指定する

max = d3.max(data, function(d) { return d.fav; });

// 「0~fav数の最大値」を「0~windowサイズ」に収める
w = d3.scale.linear()
                    .domain([0, max])
                    .range([0, document.body.clientWidth]);

d3.select('#container')
  .selectAll('div')
  .data(data)
  .enter()
  .append('div')
  .attr('class', 'bar')
  .style('background-color', '#0088ff')
  .style('font-size', '12px')
  .style('height', '16px')
  .style('width', function(d) {
    return w(d.fav) + 'px';
  })
  .text(function(d) {
    return d.title + ':' + d.fav + '(' + w(d.fav) +  'px)';
  });

グラフの軸を描くときにも使える。