JavaScriptでTreemap

著名なサイト『百式』さんで検索結果をマップ形式で表示する検索サイトの紹介(リストからマップへ)がされていて、
なんか新しいなーって思った。TagCloudと同じで視覚で結果をうったえるってわかりやすくていいよね。

PHP でtreemapの実装をされている方(Treemap PHP Source Code - neurofuzzy)がいて、コードも公開されていたのでアルゴリズムはそのままに(真似してます)JavaScriptで実装してみた。

//■JavaScript
//require Prototype.js
function render_treemap(nodes) {
    var divTmp = new Template('<div class="node" style="width:#{width}px;height:#{height}">#{tag}</div>');
    return (function(nodes, width, height, depth) {
      if (nodes.length == 1) {
        var textsize = Math.floor(width / nodes[0].label.length);
        textsize = Math.min(textsize, height);
        return '<a class="textnode" href="#" style=" font-size:'+textsize+'px">'+nodes[0].label+'</a>';

      }
      var tag = '';
      if (depth == 0) 
        tag += '<div class="treemap" style="width:'+width+'px; height:'+height+'px;">';

      var m = Math.ceil(nodes.length / 2);
      var a = nodes.slice(0, m);
      var b = nodes.slice(m, nodes.length);

      var aper = a.inject(0, function(ret, v) { return ret + v.size }) /
                   nodes.inject(0, function(ret, v) { return ret + v.size });
      var bper = 1 - aper;
      if (depth % 2 == 0) {
        var awidth = Math.ceil(width * aper);
        var bwidth = width - awidth;
        var aheight = height;
        var bheight = height;
      } else {
        var awidth = width;
        var bwidth = width;
        var aheight = Math.ceil(height * aper);
        var bheight = height - aheight;
      }
      tag += divTmp.evaluate({tag: arguments.callee.call(null, a, awidth, aheight, depth+1), width: awidth, height: aheight});
      tag += divTmp.evaluate({tag: arguments.callee.call(null, b, bwidth, bheight, depth+1), width: bwidth, height: bheight});
      
      if (depth == 0) tag += '</div>';
      return tag;
    }).call(null, nodes, 300, 200, 0);
}

//■CSS
div.treemap {
  margin-bottom: 4px;
  font-family: Lucida Grande, Lucida Sans Unicode, Tahoma, Arial, sans serif;
}
div.treemap div.node {
  float: left;
  clear: none;
  background-color: #CCCC00;
}
	
div.treemap a.textnode {
  display: block;
  font-size: 10px;
  text-align: center;
  width: 100%;
  height: 100%;
  display: block;
  float: left;
  color: #fff;
  overflow: hidden;
  background-color: #A4C088;
  text-decoration: none;
}
a.textnode {
  border: 1px solid black;
}

使い方はこんな感じ

var n = [{label:'りんご', size: 20}, {label:'オレンジ', size: 30}, 
         {label:'グレープ', size: 80}, {label:'いちご', size: 15}, 
         {label:'キューイ', size: 40}, {label:'バナナ', size: 5}];
$('panel').innerHTML = render_treemap(n);

見た目はこんな感じ

まだ、重要度によって色を変えたりだとかが実装されてないんだよね。
TagCloudみたいな感じでclassNameを振っていこうかなと思ってる。




Tags: ,