Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
a, a:visited, a:active {
color: #444;
}
.container {
max-width: 900px;
margin: auto;
}
.button {
min-width: 130px;
padding: 4px 5px;
cursor: pointer;
text-align: center;
font-size: 13px;
border: 1px solid #e0e0e0;
text-decoration: none;
}
.button.active {
background: #000;
color: #fff;
}
#vis {
width: 940px;
height: 600px;
clear: both;
margin-bottom: 10px;
}
#toolbar {
margin-top: 10px;
}
.year {
font-size: 21px;
fill: #aaa;
cursor: default;
}
.tooltip {
position: absolute;
top: 100px;
left: 100px;
-moz-border-radius:5px;
border-radius: 5px;
border: 2px solid #000;
background: #fff;
opacity: .9;
color: black;
padding: 10px;
width: 300px;
font-size: 12px;
z-index: 10;
}
.tooltip .title {
font-size: 13px;
}
.tooltip .name {
font-weight:bold;
}
.footer {
text-align: center;
}
</style>
</head>
<body>
<script>
function bubbleChart() {
var width = 960;
var height = 600;
var tooltip = floatingTooltip('gates_tooltip', 240);
var center = { x: width / 2, y: height / 2 };
var yearsTitleX = {
2008: 160,
2009: width / 2,
2010: width - 160
};
var yearCenters = {
2008: { x: width / 3, y: height / 2 },
2009: { x: width / 2, y: height / 2 },
2010: { x: 2 * width / 3, y: height / 2 }
};
/* var studioCenters = {
Disney: { x: width * (1/8), y: height / 2 },
Fox: { x: width * (1/4), y: height / 2 },
Lionsgate: { x: width * (3/8), y: height / 2 },
Paramount: { x: width * (1/2), y: height / 2 },
Sony: { x: width * (5/8), y: height / 2 },
WB: { x: width * (3/4), y: height / 2 },
Universal: { x: width * (7/8), y: height / 2 },
Other: { x: width, y: height / 2 },
};
var studiosTitleX = {
Disney: width * (1/16),
Fox: width * (3/16),
Lionsgate: width * (5/16),
Paramount: width * (7/16),
Sony: width * (9/16),
WB: width * (11/16),
Universal: width * (13/16),
Other: width * (15/16),
}; */
var forceStrength = 0.03;
var svg = null;
var bubbles = null;
var nodes = [];
function charge(d) {
return -Math.pow(d.radius, 2.0) * forceStrength;
}
var simulation = d3.forceSimulation()
.velocityDecay(0.2)
.force('x', d3.forceX().strength(forceStrength).x(center.x))
.force('y', d3.forceY().strength(forceStrength).y(center.y))
.force('charge', d3.forceManyBody().strength(charge))
.on('tick', ticked);
simulation.stop();
var fillColor = d3.scaleOrdinal()
.domain(['low', 'medium', 'high'])
.range(['#d84b2a', '#beccae', '#7aa25c']);
function createNodes(rawData) {
var maxAmount = d3.max(rawData, function (d) { return +d.total_amount; });
var radiusScale = d3.scalePow()
.exponent(0.5)
.range([2, 85])
.domain([0, maxAmount]);
var myNodes = rawData.map(function (d) {
return {
id: d.id,
radius: radiusScale(+d.total_amount),
value: +d.total_amount,
name: d.grant_title,
org: d.organization,
group: d.group,
year: d.start_year,
x: Math.random() * 900,
y: Math.random() * 800
};
});
myNodes.sort(function (a, b) { return b.value - a.value; });
return myNodes;
}
var chart = function chart(selector, rawData) {
nodes = createNodes(rawData);
svg = d3.select(selector)
.append('svg')
.attr('width', width)
.attr('height', height);
bubbles = svg.selectAll('.bubble')
.data(nodes, function (d) { return d.id; });
var bubblesE = bubbles.enter().append('circle')
.classed('bubble', true)
.attr('r', 0)
.attr('fill', function (d) { return fillColor(d.group); })
.attr('stroke', function (d) { return d3.rgb(fillColor(d.group)).darker(); })
.attr('stroke-width', 2)
.on('mouseover', showDetail)
.on('mouseout', hideDetail);
bubbles = bubbles.merge(bubblesE);
bubbles.transition()
.duration(2000)
.attr('r', function (d) { return d.radius; });
simulation.nodes(nodes);
groupBubbles();
};
function ticked() {
bubbles
.attr('cx', function (d) { return d.x; })
.attr('cy', function (d) { return d.y; });
}
function nodeYearPos(d) {
return yearCenters[d.year].x;
}
function groupBubbles() {
hideYearTitles();
simulation.force('x', d3.forceX().strength(forceStrength).x(center.x));
simulation.alpha(1).restart();
}
function splitBubbles() {
showYearTitles();
simulation.force('x', d3.forceX().strength(forceStrength).x(nodeYearPos));
simulation.alpha(1).restart();
}
function hideYearTitles() {
svg.selectAll('.year').remove();
}
function showYearTitles() {
var yearsData = d3.keys(yearsTitleX);
var years = svg.selectAll('.year')
.data(yearsData);
years.enter().append('text')
.attr('class', 'year')
.attr('x', function (d) { return yearsTitleX[d]; })
.attr('y', 40)
.attr('text-anchor', 'middle')
.text(function (d) { return d; });
}
function showDetail(d) {
d3.select(this).attr('stroke', 'black');
var content = '<span class="name">Title: </span><span class="value">' +
d.name +
'</span><br/>' +
'<span class="name">Amount: </span><span class="value">$' +
addCommas(d.value) +
'</span><br/>' +
'<span class="name">Year: </span><span class="value">' +
d.year +
'</span>';
tooltip.showTooltip(content, d3.event);
}
function hideDetail(d) {
d3.select(this)
.attr('stroke', d3.rgb(fillColor(d.group)).darker());
tooltip.hideTooltip();
}
chart.toggleDisplay = function (displayName) {
if (displayName === 'year') {
splitBubbles();
} else {
groupBubbles();
}
};
return chart;
}
var myBubbleChart = bubbleChart();
function display(error, data) {
if (error) {
console.log(error);
}
myBubbleChart('#vis', data);
}
function setupButtons() {
d3.select('#toolbar')
.selectAll('.button')
.on('click', function () {
d3.selectAll('.button').classed('active', false);
var button = d3.select(this);
button.classed('active', true);
var buttonId = button.attr('id');
myBubbleChart.toggleDisplay(buttonId);
});
}
function addCommas(nStr) {
nStr += '';
var x = nStr.split('.');
var x1 = x[0];
var x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
d3.csv('data/gates_money.csv', display);
setupButtons();
</script>
</body>
https://d3js.org/d3.v4.min.js