まとめ
D3.jsでData-Driven Documentsするとかよくわからなかったので、基礎っぽいところのメモとサンプル。
まずは、d3.selectAll(), selection.data(), selection.enter(). d3.scale()を理解することが重要。
svgのcircle, rectあたりは調べておきましょう。
同じくJavaScriptのArrayあたりはよく使うので復習しておく。
にこ先輩はちっちゃい。
Documentの読み方
公式のIntroductionと、Tutrialsは参考になる。
とりあえずIntroductionからThree Little Circles、Thinking with Joinsまで読むのがおすすめ。
すごく単純に要約すると、d3.selectAll()で選択して、selection.data()でデータをバインディングして、selection.enter()などにデータから要素をappendしていくのがD3.jsの大まかな流れ。
selectAllで選択した要素よりも多い(例えば要素0個の)場合でも、dataの数だけ要素をappendできる。
あとこちらが参考になる。d3.js API Advent Calendar 2012 by id:muddydixon
今回のサンプル!
AxisとScaleは、また別の機会に。
実際に動くサンプル
あぁ、にこ先輩ちっちゃいなぁ。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>d3 sample</title>
<style type="text/css">
circle {
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 12px sans-serif;
}
text.shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .8;
}
</style>
</head>
<body>
<div id="chart">
<button>Run</button>
</div>
<script type="text/javascript" src="d3.v3.min.js"></script>
<script type="text/javascript" src="lovelive.js"></script>
</body>
</html>
var member = [
{ name : "高坂 穂乃果", cv : "新田恵海", grade : 2, age : 16, birthday : "8/3", bloodType : "O", height : 157, B : 78, W : 58, H : 82, like : "いちご", dislike : "ピーマン", color : "246,168,0", img : "01s_off.png" },
{ name : "絢瀬 絵里", cv : "南條愛乃", grade : 3, age : 17, birthday : "10/21", bloodType : "B", height : 162, B : 88, W : 60, H : 84, like : "チョコレート", dislike : "梅干し・のり", color : "0,186,255", img : "02s_off.png" },
{ name : "南 ことり", cv : "内田 彩", grade : 2, age : 16, birthday : "9/12", bloodType : "O", height : 159, B : 80, W : 58, H : 80, like : "チーズケーキ", dislike : "にんにく", color : "160,160,160", img : "03s_off.png" },
{ name : "園田 海未", cv : "三森すずこ", grade : 2, age : 16, birthday : "3/15", bloodType : "A", height : 159, B : 76, W : 58, H : 80, like : "穂乃果の家のまんじゅう", dislike : "炭酸飲料", color : "108,84,253", img : "04s_off.png" },
{ name : "星空 凛", cv : "飯田里穂", grade : 1, age : 15, birthday : "11/1", bloodType : "A", height : 155, B : 75, W : 59, H : 80, like : "ラーメン!", dislike : "お魚", color : "85,251,214", img : "05s_off.png" },
{ name : "西木野 真姫", cv : "Pile", grade : 1, age : 15, birthday : "4/19", bloodType : "AB", height : 161, B : 78, W : 58, H : 83, like : "トマト", dislike : "みかん", color : "255,97,54", img : "06s_off.png" },
{ name : "東條 希", cv : "楠田亜衣奈", grade : 3, age : 17, birthday : "6/9", bloodType : "O", height : 159, B : 90, W : 60, H : 82, like : "焼き肉", dislike : "キャラメル", color : "227,79,253", img : "07s_off.png" },
{ name : "小泉 花陽", cv : "久保ユリカ", grade : 1, age : 15, birthday : "1/17", bloodType : "B", height : 156, B : 82, W : 60, H : 83, like : "白いごはん", dislike : "なし", color : "66,206,112", img : "08s_off.png" },
{ name : "矢澤 にこ", cv : "徳井青空", grade : 3, age : 17, birthday : "7/22", bloodType : "A", height : 154, B : 74, W : 57, H : 79, like : "お菓子", dislike : "辛いもの", color : "255,95,219", img : "09s_off.png" }
];
var w = 800;
var h = 600;
var svg = d3.select("#chart").append("svg")
.attr("height", h)
.attr("width", w);
member.sort(function(a, b){
return b.height - a.height;
});
var r = 40;
var offset = 40;
var widths = d3.scale.linear()
.domain([0, 8])
.range([r * 2, w - r*2]);
var heights = d3.scale.linear()
.domain([member[0].height, member[member.length-1].height])
.range([r + offset, h - r - offset]);
var yAxis = d3.svg.axis()
.scale(heights)
.orient("left");
svg.append("g")
.attr("transform", "translate(" + offset + ",0)")
.attr("class", "select")
.call(yAxis);
svg.selectAll("circle")
.data(member)
.enter().append("circle")
.attr("class", "member select")
.attr("cx", function(d, i){
return widths(i);
})
.attr("cy", function(d){
return heights(d.height);
})
.attr("r", r)
.attr("fill", function(d){
return "rgb(" + d.color + ")";
});
var text = svg.append("g").selectAll("g")
.data(member)
.enter().append("g");
text.append("text")
.text(function(d) { return d.name; })
.attr("class", "shadow select")
.attr("dx", function(d, i){
return widths(i);
})
.attr("dy", function(d){
return heights(d.height);
})
.attr("text-anchor", "middle");
text.append("text")
.text(function(d) { return d.name; })
.attr("class", "select")
.attr("dx", function(d, i){
return widths(i);
})
.attr("dy", function(d){
return heights(d.height);
})
.attr("text-anchor", "middle");
d3.select("button").on("click", function() {
svg.selectAll(".select").remove();
var minB = d3.min(member, function(d) { return d.B; });
var maxB = d3.max(member, function(d) { return d.B; });
var rate = 2;
var widths = d3.scale.linear()
.domain([maxB, minB])
.range([maxB/rate + offset, w-maxB/rate - offset]);
var heights = d3.scale.linear()
.domain([member[0].height, member[member.length-1].height])
.range([maxB/rate + offset, h - maxB/rate - offset]);
var xAxis = d3.svg.axis()
.scale(widths)
.orient("bottom");
svg.append("g")
.attr("class", "select")
.call(xAxis);
var yAxis = d3.svg.axis()
.scale(heights)
.orient("left");
svg.append("g")
.attr("transform", "translate(" + offset + ",0)")
.attr("class", "select")
.call(yAxis);
svg.selectAll("circle")
.data(member)
.enter().append("circle")
.attr("class", "select")
.attr("cx", function(d, i){
return widths(d.B);
})
.attr("cy", function(d){
return heights(d.height);
})
.attr("r", function(d) {
return 5 + d.B / rate;
})
.attr("fill", function(d){
return "rgb(" + d.color + ")";
});
var text = svg.append("g").selectAll("g")
.data(member)
.enter().append("g");
text.append("text")
.text(function(d) { return d.name; })
.attr("class", "shadow select")
.attr("dx", function(d, i){
return widths(d.B);
})
.attr("dy", function(d){
return heights(d.height);
})
.attr("text-anchor", "middle");
text.append("text")
.text(function(d) { return d.name; })
.attr("class", "select")
.attr("dx", function(d, i){
return widths(d.B);
})
.attr("dy", function(d){
return heights(d.height);
})
.attr("text-anchor", "middle");
});