Built with blockbuilder.org
forked from sxywu's block: visfest block visualization
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width: 100%; height: 100%; }
</style>
</head>
<body>
<script>
var margin = {top: 20, right: 10, bottom: 20, left: 10};
var width = 1024 - margin.left - margin.right;
var height = 968 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var nodes = [],
links = [];
var ignoreApi = ['d3.select', 'd3.selectAll'];
var force = d3.layout.force()
.size([width, height])
.charge(function(d) {return d.type === 'api' ? 5 : -Math.pow(d.size, 2)})
.linkStrength(function(d) {return d.strength})
.on('tick', update);
var circle, path, text;
function enter() {
path = svg.selectAll('line')
.data(links).enter().append('line')
.attr('stroke', '#ccc')
.attr('stroke-linecap', 'round');
circle = svg.selectAll('circle')
.data(nodes).enter().append('circle')
.attr('stroke-width', 2)
.call(force.drag);
text = svg.selectAll('text')
.data(_.filter(nodes, function(node) {return node.type === 'api';}))
.enter().append('text')
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.attr('fill', '#555')
.style({
'font-size': '12px',
'font-family': 'Helvetica',
'font-weight': 600,
'pointer-events': 'none'
});
};
function update() {
circle.attr('r', function(d) {return d.size})
.attr('fill', function(d) {return d.fill || '#fff'})
.attr('fill-opacity', function(d) {return d.type === 'api' ? .25 : 1})
.attr('stroke', function(d) {return d.stroke || 'none'})
.attr('cx', function(d) {return d.x})
.attr('cy', function(d) {return d.y});
text.attr('x', function(d) {return d.x})
.attr('y', function(d) {return d.y + 10})
.text(function(d) {return d.name});
path.attr('stroke-width', function(d) {return d.size})
.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});
};
d3.json('data.json', function(data) {
var linkStrengths = [];
var api = _.chain(data)
.pluck('api')
.map(function(api) {return _.pairs(api)})
.flatten().compact()
.filter(function(api) {return !_.contains(ignoreApi, api[0])})
.reduce(function(memo, api) {
linkStrengths.push(api[1]);
if (!memo[api[0]]) {
memo[api[0]] = 0;
}
memo[api[0]] += api[1];
return memo;
}, {})
.value();
var colors = d3.scale.category20();
var sizeScale = d3.scale.linear()
.domain([_.min(api), _.max(api)])
.range([5, 40]);
console.log(linkStrengths)
var strengthScale = d3.scale.linear()
.domain([_.min(linkStrengths), _.max(linkStrengths)])
.range([0, 1]);
var radius = 400;
var apiNodes = _.chain(api)
.map(function(count, name) {
api[name] = {
name,
size: sizeScale(count),
fill: colors(name),
fixed: true,
type: 'api'
};
return api[name];
}).sortBy(function(node) {
return -node.size;
}).map(function(node, i) {
var radian = (2 * Math.PI) / _.size(api) * i - (Math.PI / 2);
node.x = radius * Math.cos(radian) + (width / 2);
node.y = radius * Math.sin(radian) + (height / 2);
return node;
}).value();
var blockNodes = _.map(data, function(block) {
var node = {
id: block.id,
title: block.description,
user: block.userId,
image: block.thumbnail,
size: 15,
stroke: '#999'
};
_.each(block.api, function(count, apiName) {
if (_.contains(ignoreApi, apiName)) return;
links.push({
source: node,
target: api[apiName],
size: count,
strength: strengthScale(count)
});
});
return node;
});
nodes = _.union(apiNodes, blockNodes);
force.nodes(nodes).links(links)
.start();
enter();
});
</script>
</body>
https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js