Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@tag1216
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tag1216/76e6bba3fd1784eba83c to your computer and use it in GitHub Desktop.
Save tag1216/76e6bba3fd1784eba83c to your computer and use it in GitHub Desktop.
Qiita新着投稿100件のタグをd3.jsのForceレイアウトで表示2
<!DOCTYPE html>
<meta charset="utf-8">
<title>Qiita新着投稿100件のタグをd3.jsのForceレイアウトで表示2</title>
<style>
svg {
border: solid 1px;
}
.item image {
opacity: .7;
}
.item circle {
fill: #fff;
fill-opacity: .7;
stroke-width: .5px;
stroke: #60c90d;
stroke-opacity: .7;
}
.tag image {
opacity: .9;
}
.tag rect {
fill-opacity: 0;
stroke-width: 1px;
stroke: #0f6faf;
stroke-opacity: .9;
}
.tag text {
pointer-events: none;
font-size: 8px;
}
.tag .shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .7;
}
.link {
stroke: #aaa;
stroke-width: 2px;
opacity: .3;
}
</style>
<body>
<div class="message"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="qiita-tag-force2.js"></script>
</body>
var WIDTH = 800,
HEIGHT = 800,
TAG_IMAGE_SIZE = 16,
ITEM_IMAGE_SIZE = 8,
APPEND_INTERVAL = 250;
var tags = [];
var items = [];
var nodes = [];
var links = [];
var svg = d3.select("body").append("svg")
.attr("width", WIDTH)
.attr("height", HEIGHT);
var force = d3.layout.force()
.size([WIDTH, HEIGHT])
.nodes(nodes)
.links(links)
.charge(0)
.linkDistance(20)
.linkStrength(1)
.gravity(0.3)
.start();
var itemNode = svg.selectAll(".item-node");
var tagNode = svg.selectAll(".tag-node");
var link = svg.selectAll(".link")
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
itemNode.attr("transform", function(d) {return "translate(" + d.x + "," + d.y + ")"; });
tagNode.attr("transform", function(d) {return "translate(" + d.x + "," + d.y + ")"; });
});
//データの読み込み
showMessage("データ読み込み中...");
//d3.json("items.json", function(error, items) {
d3.json("https://qiita.com/api/v1/items?per_page=100", function(error, items) {
var index = 0;
var timer = setInterval(function() {
try {
if (items.length <= index) {
clearInterval(timer);
showMessage("");
return;
}
showMessage("データ追加中(" + (index+1) + "/" + items.length + ")...");
appendItem(items[index++])
}
catch (e) {
showMessage(e);
clearInterval(timer);
}
}, APPEND_INTERVAL);
});
//メッセージ表示
function showMessage(text) {
d3.select(".message").text(text);
}
//投稿をノードとして追加する
function appendItem(item) {
items.push(item);
nodes.push(item);
item.tags.forEach(function(tag) {
var name = "___" + tag.name;
if (!(name in tags)) {
tags[name] = tag;
tags[name].count = 0;
nodes.push(tags[name]);
}
tags[name].count++;
links.push({
source: nodes.indexOf(item),
target: nodes.indexOf(tags[name])
});
});
restart();
}
//forceレイアウトの再描画
function restart() {
itemNode = itemNode.data(items);
tagNode = tagNode.data(d3.values(tags));
drawItemNode();
drawTagNode();
drawLink();
force
.nodes(nodes)
.links(links)
.charge(function(d) {
//反発力を 投稿数の多いタグ > 投稿数の少ないタグ > 投稿ノード にする
return d.count ? -(d.count * 200) : -100;
});
force.start();
}
// 投稿ノードの描画
function drawItemNode() {
var g = itemNode.enter().append("g")
.attr("class", "node item")
.call(force.drag);
var a = g.append("a")
.attr("xlink:href", function(d) { return d.url; })
.attr("target", "_blank");
a.append("circle")
.attr("r", ITEM_IMAGE_SIZE);
a.append("image")
.attr("xlink:href", function(d) { return d.user.profile_image_url; })
.attr({
x: -ITEM_IMAGE_SIZE/2,
y: -ITEM_IMAGE_SIZE/2,
width: ITEM_IMAGE_SIZE,
height: ITEM_IMAGE_SIZE
});
g.append("title")
.text(function(d) {
return d.title + "(" + d.user.url_name + "が" + d.created_at_in_words + "前に投稿)";
});
}
//タグノードの描画
function drawTagNode() {
var g = tagNode.enter().insert("g", ".item")
.attr("class", "node tag")
.call(force.drag);
var a = g.append("a")
.attr("xlink:href", function(d) { return "http://qiita.com/tags/" + d.url_name; })
.attr("target", "_blank");
a.append("image")
.attr("xlink:href", function(d) {
return d.icon_url == "/icons/medium/missing.png"
? "http://qiita.com/icons/medium/missing.png"
: d.icon_url;
});
a.append("rect");
a.append("text")
.attr("class", "shadow");
a.append("text")
.attr("class", "text");
tagNode.selectAll("text")
.attr("text-anchor", "middle")
.text(function(d) {return d.name;});
tagNode.each(function(d) {
var size = ~~(TAG_IMAGE_SIZE * Math.sqrt(d.count));
d3.select(this).select("image")
.attr({
x: -size/2,
y: -size/2,
width: size,
height: size
});
d3.select(this).select("rect")
.attr({
x: -size/2,
y: -size/2,
width: size,
height: size
});
d3.select(this).selectAll("text")
.attr("dy", size / 2 + 10);
});
}
//リンクの描画
function drawLink() {
link = link.data(links);
link.enter().insert("line", ".tag")
.attr("class", "link");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment