function tooltipper(){
var config = {
left: 0,
top: 0,
text: '',
isVisible: false
};
var tooltip = d3.select('body')
.append('div')
.attr({
'class': 'tooltip'
})
.style({
position: 'absolute',
'pointer-events': 'none'
});
var render = function(){
tooltip.style({
left: config.left + 'px',
top: (config.top - 15) + 'px',
display: config.isVisible ? 'block' : 'none'
})
.html(config.text);
return this;
};
var exports = {};
exports.show = function(){
config.isVisible = true;
render();
return this;
};
exports.hide = function(){
config.isVisible = false;
render();
return this;
};
exports.text = function(text){
config.text = text;
return this;
};
exports.position = function(position){
config.left = position[0];
config.top = position[1];
return this;
};
return exports
}
function scatterPlot() {
var margin = {top: 40, right: 60, bottom: 60, left: 40},
width = 600,
height = 400,
emphasizedCountries = [],
xScale = d3.scale.log(),
yScale = d3.scale.linear(),
sizeScale = d3.scale.sqrt(),
colorScale = d3.scale.category10(),
xAxis = d3.svg.axis().scale(xScale).orient('bottom').tickSize(6,1).ticks(12, d3.format('s')),
yAxis = d3.svg.axis().scale(yScale).orient('left').tickSize(6, 1),
labelY = '',
valueName = '',
dataMinX = null,
dataMaxX = null,
dataMinY = null,
dataMaxY = null,
year = null,
dataMaxSize = null,
tooltip = tooltipper(),
chartTitle = '',
dispatch = d3.dispatch('info'),
showBackgroundLines = false;
function chart(selection) {
selection.each(function(data) {
var line = d3.svg.line()
.x(function(d) { return xScale(d[0]); })
.y(function(d) { return yScale(d[1]); });
var chartHeight = height - margin.top - margin.bottom,
chartWidth = width - margin.left - margin.right;
xScale
.domain([dataMinX, dataMaxX])
.range([0, chartWidth]);
yScale
.domain([dataMinY, dataMaxY])
.range([chartHeight, 0]);
var svg = d3.select(this).selectAll('svg').data([data.map(function(d, i){ return d[year - 1990]; })]);
var svgEnter = svg.enter().append('svg');
var gEnter = svgEnter.append('g');
gEnter.append('g').attr({'class': 'lines'});
gEnter.append('g').attr({'class': 'bg-lines'});
gEnter.append('g').attr({'class': 'points'});
gEnter.append('g').attr({'class': 'x axis'});
gEnter.append('g').attr({'class': 'y axis'});
gEnter.append('g').attr({'class': 'point-labels'});
gEnter.append('text').attr({'class': 'title'});
gEnter.append('g').attr({'class': 'axis-labels'});
svg.attr({
width: width,
height: height
});
var g = svg.select('g')
.attr({transform: 'translate(' + margin.left + ',' + margin.top + ')'});
var points = g.select('g.points')
.selectAll('circle.point')
.data(function(d){
return d;
});
points.enter().append('circle')
.attr({
'class': 'point'
})
.style({
display: 'none'
})
.on('mousemove', function(d, i){
var mouse = d3.event;
tooltip.position([mouse.x, mouse.y])
.text(
'Name: ' + d[2] + '
' +
'Region: ' + d[3] + '
' +
'GDP: ' + d[0] + '
' +
valueName + ': ' + d[1] + '
')
.show();
dispatch.info(d);
})
.on('mouseout', function(d){
tooltip.hide();
})
.on('click', function(d){
var line = g.select('path.' + formatName(d[3]));
line.classed('highlighted', !line.classed('highlighted'));
var point = d3.select(this);
point.classed('highlighted', !point.classed('highlighted'));
var label = g.select('text.' + formatName(d[3]));
label.classed('highlighted', !label.classed('highlighted'));
});
points.transition().duration(100)
//.attr({r: function(d) { return sizeScale(d[2]); }})
.attr({r: function(d) { return 2; }})
.style({
display: 'none'
})
.filter(function(d){
return d && d[0] !== null && d[1] !== null;
})
.attr({transform: function(d) {
return 'translate(' + xScale(d[0]) + ',' + yScale(d[1]) + ')';
}})
.style({
display: 'block'
});
var lines = g.select('g.lines')
.selectAll('path.line')
.data(data);
lines.enter().append('path')
.attr({
'class': function(d){
var highlightClass = emphasizedCountries.indexOf(d[0][3]) > -1 ? ' highlighted' : '';
return formatName(d[0][3]) + ' line' + highlightClass;
},
d: line,
stroke: function(d, i){
return colorScale(d[0][2], i);
},
fill: 'none'
});
if(showBackgroundLines){
var lines = g.select('g.bg-lines')
.selectAll('path.bg-line')
.data(data);
lines.enter().append('path')
.attr({
'class': function(d){
var highlightClass = emphasizedCountries.indexOf(d[0][3]) > -1 ? ' highlighted' : '';
return formatName(d[0][3]) + ' bg-line' + highlightClass;
},
d: line,
stroke: function(d, i){
return colorScale(d[0][2], i);
},
fill: 'none'
});
}
var labels = g.select('g.point-labels')
.selectAll('text.point-label')
.data(data);
labels.enter().append('text')
.attr({
'class': function(d){
var highlightClass = emphasizedCountries.indexOf(d[0][3]) > -1 ? ' highlighted' : '';
return formatName(d[0][3]) + ' point-label' + highlightClass;
},
dx: 8,
transform: function(d) {
var lastPos = d[d.length-1];
return 'translate(' + xScale(lastPos[0]||1) + ',' + yScale(lastPos[1]||1) + ')';
}
})
.html(function(d){
return d[0][3];
});
g.select('.x.axis')
.attr({transform: 'translate(0,' + chartHeight + ')'})
.call(xAxis);
g.select('.y.axis')
.call(yAxis);
g.select('text.title')
.html(chartTitle)
.attr({
x: function(){
return (chartWidth - this.getBBox().width) / 2;
},
y: function(){
return -this.getBBox().height;
}
});
var axisLabels = gEnter.select('g.axis-labels');
axisLabels.append('text')
.html(labelY)
.attr({
'class': 'y-axis-title',
x: -30,
y: -5
});
axisLabels.append('text')
.html('$ per capita')
.attr({
'class': 'x-axis-title',
x: chartWidth - margin.right + 35,
y: chartHeight + 18
});
});
}
function X(d) {
return xScale(d[0]);
}
function Y(d) {
return yScale(d[1]);
}
function formatName(name){
return name.replace(/[^a-zA-Z]/g, '_');
}
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.labelY = function(_) {
if (!arguments.length) return labelY;
labelY = _;
return chart;
};
chart.valueName = function(_) {
if (!arguments.length) return valueName;
valueName = _;
return chart;
};
chart.dataMinX = function(_) {
if (!arguments.length) return dataMinX;
dataMinX = _;
return chart;
};
chart.dataMaxX = function(_) {
if (!arguments.length) return dataMaxX;
dataMaxX = _;
return chart;
};
chart.dataMinY = function(_) {
if (!arguments.length) return dataMinY;
dataMinY = _;
return chart;
};
chart.dataMaxY = function(_) {
if (!arguments.length) return dataMaxY;
dataMaxY = _;
return chart;
};
chart.dataMaxSize = function(_) {
if (!arguments.length) return dataMaxSize;
dataMaxSize = _;
return chart;
};
chart.year = function(_) {
if (!arguments.length) return year;
year = _;
return chart;
};
chart.chartTitle = function(_) {
if (!arguments.length) return chartTitle;
chartTitle = _;
return chart;
};
chart.highlights = function(_){
if (!arguments.length) return emphasizedCountries;
emphasizedCountries = _;
return chart;
};
chart.showBackgroundLines = function(_){
showBackgroundLines = _;
return chart;
};
d3.rebind(chart, dispatch, 'on');
return chart;
}