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/4817fdf092634270bbbf to your computer and use it in GitHub Desktop.
Save tag1216/4817fdf092634270bbbf to your computer and use it in GitHub Desktop.
Qiita新着投稿100件のタグをd3.jsのForceレイアウトで表示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Qiita新着投稿100件のタグをd3.jsのForceレイアウトで表示</title>
<style>
svg {
border: solid 1px;
}
.node circle {
stroke: #000;
stroke-width: .5px;
opacity: .7;
}
.node text {
pointer-events: none;
font-size: 8px;
}
.node .shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .7;
}
.node .text {
}
.link {
stroke: #888;
opacity: .3;
}
</style>
</head>
<body>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="qiita-tag-force.js"></script>
</body>
</html>
var NAME_PREFIX = "__";
d3.json('https://qiita.com/api/v1/items?per_page=100', function(error, items) {
//タグ投稿数のカウント
var tags = items.reduce(function(tags, item) {
item.tags.forEach(function(tag) {
var name = NAME_PREFIX + tag.name;
if (!(name in tags)) {
tags[name] = {
name: tag.name,
urlName: tag.url_name,
count: 0
};
}
tags[name].count++;
});
return tags;
}, []);
//ノードデータの作成
var nodes = d3.values(tags)
.sort(function(tag1, tag2) {
return tag1.count - tag2.count;
});
//タグ組み合わせ数のカウント
var tagLinks = items.reduce(function(links, item) {
item.tags.forEach(function(tag1) {
item.tags.forEach(function(tag2) {
var key = tag1.name + NAME_PREFIX + tag2.name;
if (!(key in links)) {
links[key] = {
source: nodes.indexOf(tags[NAME_PREFIX + tag1.name]),
target: nodes.indexOf(tags[NAME_PREFIX + tag2.name]),
count: 0
};
}
links[key].count++;
})
})
return links;
}, []);
//リンクデータの作成
var links = d3.values(tagLinks);
var width = 1024,
height = 800;
var color = d3.scale.category20();
var force = d3.layout.force()
// .charge(-200)
.charge(function(d) {
return -(d.count * 150);
})
.linkDistance(30)
.linkStrength(1.0)
.gravity(0.2)
.size([width, height]);
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height);
force
.nodes(nodes)
.links(links)
.start();
var link = svg.selectAll('.link')
.data(links)
.enter().append('line')
.attr('class', 'link')
.style('stroke-width', function(d) { return d.count * d.count; });
var node = svg.selectAll('.node')
.data(nodes)
.enter().append('g')
.attr('class', 'node')
.call(force.drag);
var a = node.append('a')
.attr('xlink:href', function(d) { return 'http://qiita.com/tags/' + d.urlName + '/items'; })
.attr('target', '_blank');
a.append('circle')
.attr('r', function(d) { return 8 * Math.sqrt(d.count) })
.style('fill', function(d) { return color(d.index); })
.on('mouseover', function(d) { d3.select(this.parentNode.parentNode).style('z-index', 999); })
.on('mouseout', function(d) { d3.select(this.parentNode.parentNode).style('z-index', null); })
node.append('text')
.attr('class', 'shadow')
.attr('dx', 0)
.attr('dy', '.5em')
.style('font-size', function(d) { return (6 * Math.sqrt(d.count)) + 'px' })
.text(function(d) { return d.name + '(' + d.count + ')'; })
node.append('text')
.attr('class', 'text')
.attr('dx', 0)
.attr('dy', '.5em')
.style('font-size', function(d) { return (6 * Math.sqrt(d.count)) + 'px' })
.text(function(d) { return d.name + '(' + d.count + ')'; })
node.append('title')
.text(function(d) { return d.name + ':' + d.count; });
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; });
node.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment