Built with blockbuilder.org
Forked from D3byEx.
There are more interactive with data. If there are more elements than the data, the extra elements(circles) will move up to top and dispared with zero radius.
The origin example uses linear scale to size circles, while I set it to pow scale. All the fancy is come from the timer function.
forked from 1Cr18Ni9's block: Chart Controls III
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0;font-family: Futura, Arial, sans-serif; }
div#container{margin: 10px 20px; position: relative;}
svg{border: 1px solid #ccc; background-color: #fff;}
.tick line, path.domain{stroke: #555;stroke-width: 1;fill: none;}
.xGroup path{stroke:none;}
.tick text, .label{fill: #555;}
select{
position: absolute;
left: 15px;
top: 15px;
height: 2em;
border-radius: 5px;
display: block;
padding: 2px;
}
text.bigText{
text-anchor: middle;
font-size: 15em;
opacity: 0.5;
fill: none;
stroke: #111;
stroke-width: 1;
}
</style>
</head>
<body>
<div id="container">
<select name="region"></select>
</div>
<script>
var margin = {top: 85, bottom: 85, left: 85, right: 45},
svgWidth = 650,
svgHeight = 450,
graphWidth = svgWidth - margin.left - margin.right,
graphHeight = svgHeight - margin.top - margin.bottom,
circleSize = [5, 50], // circle size span
axisPadding = circleSize[1] / 2;
// X-axis is for life expectation: LifeExp
// Y-axis is for birth rate: FertRate
// The 3rd dimension is population represented with circleSize
// The 4th dimension is time line: Year
var xScale = d3.scale.linear().range([0, graphWidth]).nice(),
yScale = d3.scale.linear().range([graphHeight, 0]).nice(),
colors = d3.scale.category10(),
rScale = d3.scale.pow().exponent(2).range(circleSize);
var xAxis = d3.svg.axis()
.orient('bottom')
.scale(xScale)
.tickSize(6,0),
yAxis = d3.svg.axis()
.orient('left')
.scale(yScale)
.tickSize(6,0);
var svg = d3.select('#container')
.append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
var graphBody = svg.append('g')
.attr('class', 'graph')
.attr('transform', 'translate(' +
[margin.left, margin.top] + ')'),
xGroup = svg.append('g')
.attr('class', 'xGroup')
.attr('transform', 'translate(' +
[margin.left,
margin.top + graphHeight + axisPadding] +
')'),
yGroup = svg.append('g')
.attr('class', 'yGroup')
.attr('transform', 'translate(' +
[margin.left - axisPadding,
margin.top] +
')');
var bigText = graphBody.append('text')
.attr('transform', 'translate(' +
[graphWidth / 2,graphHeight / 2] + ')')
.attr('class', 'bigText')
.attr('dy', 70);
var url = 'lfp_all.csv';
// global decleared variables
var newData, minYear, maxYear,
currentYear, currentData, interval = 200;
d3.csv(url, function(error, data){
data.map(function(d){
d.Year = +d.Year;
d.LifeExp = +d.LifeExp;
d.FertRate = +d.FertRate;
d.Population = +d.Population;
});
// Find all the values spans for axis domains
var LifeExtent = d3.extent(data, function(d){ return d.LifeExp; }),
maxFertRate = d3.max(data, function(d){ return d.FertRate; }),
PopulationExtent = d3.extent(data, function(d){ return d.Population; }),
yearExtent = d3.extent(data, function(d){ return d.Year; }),
regions = d3.set(data.map(function(d){ return d.Region; }))
.values()
.sort();
minYear = yearExtent[0];
maxYear = yearExtent[1];
newData = d3.nest()
.key(function(d){return d.Year;})
.map(data);
// add 'All' as the 1st option
var optItems = regions.slice();
optItems.unshift('All')
var opts = d3.select('select[name=region]');
opts
.selectAll('option')
.data(optItems)
.enter()
.append('option')
.property('value', function(d,i){ return d; })
.html(function(d,i){ return d; });
opts.on('change', optChange)
// add axis domain
xScale.domain([LifeExtent[0]* 0.9, LifeExtent[1]* 1.1]);
yScale.domain([0, maxFertRate]);
rScale.domain(PopulationExtent);
colors.domain(regions);
// Drawing of the axises
xGroup.call(xAxis);
yGroup.call(yAxis);
// Drawing of labels
yGroup.append('text')
.attr('transform',
'translate(' +
[-30, graphHeight / 2] +
')rotate(' + -90 + ')')
.attr('class', 'label yLabel')
.attr('text-anchor', 'middle')
.text('[ FertRate ]');
xGroup.append('text')
.attr('transform',
'translate(' +
[graphWidth / 2, 40] +
')')
.attr('class', 'label xLabel')
.attr('text-anchor', 'middle')
.text('[ Life Expectation ]');
// graph drawing area, initial setting
opts.property('value', 'All');
currentYear = minYear;
d3.timer(callback(), interval);
})
function redraw(year){
var data;
var val = d3.select('select[name=region]').property('value');
if(val === 'All'){
data = newData[year];
}else{
data = newData[year]
.map(function(d){if(d.Region === val){return d;}})
.filter(function(d){return d;});
}
// year update
bigText.html(year);
var circles = graphBody
.selectAll('circle')
.attr('class', 'bubble')
.data(data, function(d){return d.CountryName});
// update circles
circles
.transition()
.each(function(d,i){
d3.select(this).attr({
cx: xScale(d.LifeExp),
cy: yScale(d.FertRate),
r: rScale(d.Population),
});
});
// append circles if there is More data
circles
.enter()
.append('circle')
.each(function(d,i){
d3.select(this).attr({
cx : xScale(d.LifeExp),
cy : yScale(d.FertRate),
r : rScale(d.Population),
fill : colors(d.Region),
'fill-opacity': 0.5,
stroke : colors(d.Region),
'stroke-width': 1
});
});
// delet circles if there is Less data
circles
.exit()
.transition()
.duration(500)
.attr('cy', 0)
.attr('r', 0)
.remove();
}
// timer callback
var callback = function(){
return function(){
currentYear++;
if(currentYear <= maxYear){
redraw(currentYear);
d3.timer(callback(), interval);
};
return true;
};
};
// option input change event
function optChange(){
graphBody.selectAll('circle').remove();
currentYear = minYear;
d3.timer(callback(), interval);
}
</script>
</body>
https://d3js.org/d3.v3.min.js