Skip to content

Instantly share code, notes, and snippets.

@jamiecollinson
Last active August 29, 2015 14:28
Show Gist options
  • Save jamiecollinson/a4ac045b23a094df96b0 to your computer and use it in GitHub Desktop.
Save jamiecollinson/a4ac045b23a094df96b0 to your computer and use it in GitHub Desktop.
d3 bubblechart
{"description":"d3 bubblechart","endpoint":"","display":"svg","public":true,"require":[{"name":"lodash","url":"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"},{"name":"faker","url":"https://cdnjs.cloudflare.com/ajax/libs/Faker/3.0.1/faker.min.js"},{"name":"bootstrap","url":"https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"},{"name":"bootstrap","url":"https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"},{"name":"bootstrap-tooltip","url":"https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/umd/tooltip.js"},{"name":"d3-tip","url":"https://raw.githubusercontent.com/Caged/d3-tip/master/index.js"},{"name":"d3-tip","url":"https://raw.githubusercontent.com/Caged/d3-tip/master/index.js"}],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"tab":"edit","display_percent":0.7,"thumbnail":"http://i.imgur.com/Z4ghHZY.png","fullscreen":false,"ajax-caching":true}
var BubbleChart = function(data) {
this.data = data;
this.width = 800;
this.height = 1000;
this.center = { x: this.width/2, y: this.height/2 };
this.stages = [
{ name: 'stage one', x: this.width / 2, y: this.height / 4 },
{ name: 'stage two', x: this.width / 2, y: this.height / 2 },
{ name: 'stage three', x: this.width / 2, y: this.height * 3 / 4 }
];
this.vis = null;
this.nodes = [];
this.force = null;
this.circles = null;
this.fillColors = d3.scale.ordinal()
.range(["#d84b2a", "#beccae", "#7aa25c"]);
this.displayMode = 'displayAll';
var max_value = d3.max(this.data, function(d) {
return parseInt(d.value);
});
this.radius_scale = d3.scale.pow()
.domain([0, max_value])
.range([2, 40]);
this.create_nodes();
this.create_vis();
};
BubbleChart.prototype.addNode = function(d) {
var node = {
name: d.name,
radius: this.radius_scale(parseInt(d.value)),
x: Math.random() * this.width,
y: Math.random() * this.height,
stage: d.stage,
value: d.value
}
this.nodes.push(node);
};
BubbleChart.prototype.create_nodes = function() {
var self = this;
this.data.forEach(function(d) {
self.addNode(d)
});
};
BubbleChart.prototype.create_vis = function() {
var self = this;
this.vis = d3.select('svg')
.attr('width', this.width)
.attr('height', this.height)
.attr('id', 'bubblechart_vis')
.on('click', function() {
self.switchMode();
});
this.vis.append('text')
.attr('id', 'title')
.attr('y', 30)
.attr('x', this.width/2)
.attr('text-anchor', 'middle')
.attr('font-size', 24)
.text('Opportunities');
this.circles = this.vis.selectAll('circle')
.data(this.nodes);
this.circles.enter().append('circle')
.attr('r', 0)
.attr('fill', function(d) { return self.fillColors(d.stage); })
.attr('stroke-width', 2)
.on("mouseover", function (d) {
self.vis.select('text#title').text(d.name + ' - £' + d.value);
})
.on("mouseout", function(d) {
self.vis.select('text#title').text('Opportunities');
});
this.circles.transition().duration(2000)
.attr('r', function(d) {
return d.radius;
});
};
BubbleChart.prototype.switchMode = function() {
if (this.displayMode == 'displayAll') {
this.displayByStage();
} else {
this.displayAll();
}
};
BubbleChart.prototype.charge = function(d) {
return -Math.pow(d.radius, 2.0)*2;
};
BubbleChart.prototype.start = function() {
this.force = d3.layout.force()
.nodes(this.nodes)
.size([this.width, this.height]);
};
BubbleChart.prototype.displayAll = function() {
var self = this;
this.displayMode = 'displayAll';
this.removeStageNames();
this.force
.gravity(0)
.charge(this.charge)
.friction(0.9)
.on('tick', function(e) {
self.circles
.each(function(d) {
d.x = d.x + (self.center.x - d.x) * e.alpha;
d.y = d.y + (self.center.y - d.y) * e.alpha;
})
.attr('cx', function(d) { return d.x })
.attr('cy', function(d) { return d.y });
});
this.force.start();
};
BubbleChart.prototype.displayByStage = function() {
var self = this;
this.displayMode = 'displayByStage';
this.displayStageNames();
this.force
.gravity(0)
.charge(this.charge)
.friction(0.9)
.on('tick', function(e) {
self.circles
.each(function(d) {
var target = self.stages[d.stage];
d.x = d.x + (target.x - d.x) * e.alpha;
d.y = d.y + (target.y - d.y) * e.alpha;
})
.attr('cx', function(d) { return d.x })
.attr('cy', function(d) { return d.y });
});
this.force.start();
};
BubbleChart.prototype.displayStageNames = function() {
this.vis.selectAll('.stage')
.data(this.stages)
.enter().append('text')
.attr('class', 'stage')
.attr('x', 50)
.attr('y', function(d) { return d.y })
.attr('font-size', '24px')
.text(function(d) { return d.name });
};
BubbleChart.prototype.removeStageNames = function() {
this.vis.selectAll('.stage').remove();
};
var testItem = function() {
return {
name: faker.commerce.productName(),
value: faker.finance.amount(),
stage: faker.random.number(2)
};
};
var testData = _.range(60).map(testItem);
//console.log(testData);
var chart = new BubbleChart(testData);
chart.start();
chart.displayAll();
console.log(chart);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment