D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
35degrees
Full window
Github gist
gatesbubbletest
Built with
blockbuilder.org
<!DOCTYPE html> <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