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; }
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
.xAxisText, .yAxisText{font-size: 30}
.popObj {}
.stem1990 {}
.stem1991 {}
.stem1992 {}
.stem1993 {}
.stem1994 {}
.stem1995 {}
.stem1996 {}
.stem1997 {}
.stem1998 {}
.stem1999 {}
.stem2001 {}
.stem2002 {}
.stem2003 {}
.stem2004 {}
.stem2005 {}
.stem2006 {}
.stem2007 {}
.stem2008 {}
.stem2009 {}
.stem2010 {}
.stem2011 {}
.stem2012 {}
.stem2013 {}
.textMarker{}
.tooltip{
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
</head>
<body>
<script>
var height = 500;
var width = 960;
var margin = {top: 40, bottom: 40, left:20, right:20};
var innerHeight = height - margin['top'] - margin['bottom'];
var innerWidth = height - margin['left'] - margin['right'];
function generalUpdate(obj, elt, data)
{
var className = ((elt.hasOwnProperty('cl'))? elt.class: elt.obj);
var output = obj.selectAll(className)
.data(data);
return(output)
};
function generalEnter(obj, elt)
{
var output = obj.enter().append(elt.obj);
if(elt.hasOwnProperty('cl'))
output = output.attr('class', elt.cl);
return(output)
};
function attributes(obj, attributes)
{
var output = obj;
for(var name in attributes)
{
if( attributes.hasOwnProperty(name))
{
output = output.attr(name, attributes[name]);
};
};
return(output);
}
function exitObjects(arr)
{
for(name in arr)
{
if(arr.hasOwnProperty(name))
{
arr[name].exit().remove();
}
}
}
function render(data, year, countryNum)
{
data = data.filter(function(d){return(d.Year <= Math.ceil(year));});
data = data.filter(function(d){return(d.Final_Rank <= countryNum)});
data = data.sort(function(a,b){return(a.Final_Rank - b.Final_Rank);})
var xValue = d => d.Country;//function(d){return d.Country;}
var xScale = d3.scaleBand().padding(.80);
xScale.domain(data.map(xValue))
.range([0,innerWidth]);
var yScale = d3.scaleSqrt().domain([0,d3.max(data, d => d.GHG_Cum) + 1000])
.range([innerHeight,0]);
var yValueBottom = d => d.GHG_Cum - d.GHG;
var yValueTop = d => d.GHG_Cum
var body = d3.select('body');
var svg = generalUpdate(body, {obj:'svg'}, [null]);
svg = attributes(svg,{height:height,width:width} );
svg = generalEnter(svg, {obj: 'svg'} ); //Why do I need this here and not after svg declaration?
svg = attributes(svg,{height:innerHeight,width:innerWidth} );
var outerGroup = generalUpdate(svg, {obj: 'g'}, [null]);
outerGroup = generalEnter(outerGroup, {obj: 'g'});
outerGroup = attributes(outerGroup, {height: innerHeight
, width: innerWidth
, transform: `translate(${margin['left']}, ${margin['top']})`});
outerGroup = outerGroup.merge(outerGroup);
var floatingLabel = generalUpdate(outerGroup, {obj:'g', cl:'.floatingLabel'}, [null]);
floatingLabel = generalEnter(floatingLabel, {obj:'g', cl:'.floatingLabel'});
floatingLabel = floatingLabel.style("display", "none");
floatingLabel.append('rect')
.attr("width",60)
.attr("height", 20)
.attr("fill", "white")
.attr("opacity", .5);
var floatingText = floatingLabel.append("text")
.attr("x", 30)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
var popMarker = floatingText.append('tspan');
var cumGHGMarker = floatingText.append('tspan');
var bandwidthFactor = 1.08
var stemObjBottom = {}
for(var yr = 1990; yr < year; yr++)
{
yearData = data.filter(function(d){return(d.Year == yr);})
stemObjBottom[yr] = generalUpdate(outerGroup,{obj:"rect", cl:".stem" + yr}, yearData);
stemObjBottom[yr] = generalEnter(stemObjBottom[yr],{obj:"rect", cl:".stem" + yr});
stemObjBottom[yr].merge(stemObjBottom[yr]);
stemObjBottom[yr] = attributes(stemObjBottom[yr], {height:function(d){return(yScale(d.GHG));}
, width: xScale.bandwidth() * bandwidthFactor
, stroke:"black"
, x: d => xScale(xValue(d))
, y: function(d){return yScale(d.GHG_Cum - d.GHG);}
, fill:"none"});
};
var fYearData = data.filter(function(d){return(d.Year == Math.ceil(year));})
console.log(fYearData)
var factor = 1 - (Math.ceil(year) - year);
console.log(factor)
var stemObjTop = generalUpdate(outerGroup,{obj:"rect", cl:".stem" + Math.ceil(year)}, fYearData);
stemObjTop = generalEnter(stemObjTop, {obj:"rect", cl:".stem" + Math.ceil(year)});
stemObjTop = stemObjTop.merge(stemObjTop);
stemObjTop = attributes(stemObjTop, {width: xScale.bandwidth() * bandwidthFactor
, height:function(d){return(yScale( (1-factor) * d.GHG));}
, x: d=>xScale(xValue(d))
, y: function(d){return(yScale((d.GHG_Cum - d.GHG) + factor * d.GHG ));}
, stroke: "black"
, fill: "none"})
var popObj = generalUpdate(outerGroup, {obj:"circle", cl:".popObj"}, fYearData);
popObj = generalEnter(popObj, {obj:"circle", cl:".popObj"})
popObj = popObj.merge(popObj);
popObj =attributes(popObj, {r:d => Math.sqrt(3*d.Population/(1000000))
, fill: "rgba(10,10,10,.1)"
, cx: d=> xScale(d.Country)+xScale.bandwidth()/2
, cy: d => yScale(d.GHG_Cum - d.GHG + factor * d.GHG)
, stroke: "black"
, 'stroke-dasharray': '5,5'}
)
popObj.on('mouseover', function(d){
d3.select(this).attr('fill', 'rgba(0,0,255,.2)');
})
.on('mouseout', function(d){
d3.select(this).attr('fill', 'rgba(10, 10, 10, .1)')
})
;
}
var rows = function(d){
d.Country = d.Country;
d.Year = +d.Year;
d.GHG = +d.GHG;
d.GHG_Cum = +d.GHG_Cum;
d.Population = +d.Population;
d.Final_Rank = +d.Final_Rank;
return(d);};
d3.csv("Data3.csv", rows , function(data){return(render(data, 1993, 10))})
</script>
</body>
https://d3js.org/d3.v4.min.js