Created
January 16, 2020 09:34
-
-
Save AbnormalDistribution-2020/d565ad5f4d8415bab411a2aed42d17b2 to your computer and use it in GitHub Desktop.
World Data Visualization Prize - Interactive Submission
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style type="text/css"> | |
</style> | |
<body> | |
</body> | |
<div id="map"></div> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script src="https://unpkg.com/topojson@3.0.2/dist/topojson.js"></script> | |
<script> | |
var margins = {top:20, bottom:300, left:30, right:600}; | |
var height = 600; | |
var width = 900; | |
var totalWidth = width+margins.left+margins.right; | |
var totalHeight = height+margins.top+margins.bottom; | |
var projection = d3.geoMercator(); | |
var path = d3.geoPath().projection(projection); | |
var svg = d3.select("body") | |
.append('svg') | |
.attr('width', totalWidth) | |
.attr('height', totalHeight); | |
var topoData = d3.json("wdvp-countries.json"); | |
topoData.then(function(data){ | |
//var country = topojson.feature(data, data.features); | |
/* | |
var b, s, t; | |
projection.scale(1).translate([0, 0]); | |
var b = path.bounds(country); | |
console.log(d3.geoBounds(country)) | |
var s = .9 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height); | |
var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]; | |
projection.scale(s).translate(t); | |
*/ | |
var map = svg.append('g').attr('class', 'boundary'); | |
var world = map.selectAll('path').data(data.features.filter(d => d.id !== "ATA")); | |
var color = d3.scaleLinear() | |
.range(["#0ba4d4","#0b77a8"]) | |
.domain([50,80]); | |
world.enter() | |
.append('path') | |
.attr('d', path) | |
.attr('fill', function(d) {return color(d.properties.gov)}) | |
.on('click.second', function(d) {return progressText(d); }) | |
.on('click.third', function(d) {return lineUpdate(d); }) | |
.on('click', function(d) {return progressDonut(d); }) | |
.on('click.fourth', function(d) {return progressDonut3(d); }) | |
.on('click.fifth', function(d) {return circUpdate(d); }); | |
var gradient = svg.append('defs') | |
.append('linearGradient') | |
.attr('id', 'gradient') | |
.attr('x1', '0%') | |
.attr('y1', '0%') | |
.attr('x2', '0%') | |
.attr('y2', '100%') | |
.attr('spreadMethod', 'pad'); | |
gradient.append('stop') | |
.attr('offset', '0%') | |
.attr('stop-color', '#0ba4d4') | |
.attr('stop-opacity', 1); | |
gradient.append('stop') | |
.attr('offset', '100%') | |
.attr('stop-color', '#0b77a8') | |
.attr('stop-opacity', 1); | |
svg.append('rect') | |
.attr('width', 30) | |
.attr('height', (452)) | |
.attr('transform', 'translate(' + (margins.left+975) + ',' + (3+0) + ')') | |
.style('fill','url(#gradient)'); | |
var legendScale = d3.scaleLinear() | |
.domain([0,100]).nice() | |
.range([451, 0]); | |
var legendAxis = d3.axisRight(legendScale).tickValues([10,20,30,40,50,60,70,80,90,100]); | |
var graphGroup = svg.append('g') | |
.attr('transform', "translate("+ margins.left+","+3+")"); | |
graphGroup.append('g') | |
.attr('class', 'axis') | |
.attr('transform', "translate(1010,"+00+")") | |
.call(legendAxis); | |
var marker = graphGroup.append('line') | |
.attr('y1',legendScale(51)) | |
.attr('y2',legendScale(51)) | |
.attr('x1',975) | |
.attr('x2',1005) | |
.style('stroke','#fff') | |
.style('stroke-width','4px'); | |
var triangle = graphGroup.append('path') | |
.attr("transform", function(d) { return "translate(" + 965 + "," + legendScale(51) + ")rotate(90)"; }) | |
.attr("d", d3.symbol().type(d3.symbolTriangle)) | |
.style('fill',"#0b77a8"); | |
function lineUpdate(datum) { | |
marker.transition() | |
.attr('y1', legendScale(datum.properties.gov)) | |
.attr('y2', legendScale(datum.properties.gov)) | |
.duration(1000); | |
triangle.transition() | |
.attr("transform", function(d) { return "translate(" + 965 + "," + legendScale(datum.properties.gov) + ")rotate(90)"; }) | |
.duration(1000); | |
} | |
//donut start | |
var percentage = 51; | |
var pData = d3.range(16).map(function(d) { | |
return { value: d*6.25, interval: 6.25 }; | |
}) | |
var pWidth = 200, | |
pHeight = 200, | |
radius = Math.min(pWidth, pHeight) / 2; | |
var color = d3.scaleLinear() | |
.range(["#0b77a8","#0ba4d4"]).domain([0,75]); | |
var explode = function(x,index) { | |
var offset = (index==5) ? 80:0; | |
var angle = (x.startAngle + x.endAngle)/2; | |
var xOff = Math.sin(angle)*offset; | |
var yOff = -Math.cos(angle)*offset; | |
return "translate(" +xOff+","+yOff+ ")"; | |
} | |
var arc = d3.arc() | |
.outerRadius(radius - 50) | |
.innerRadius(radius - 70); | |
var pie = d3.pie() | |
.padAngle(.05) | |
.sort(null) | |
.value(function(d) { return d.interval; }); | |
var g = graphGroup.selectAll(".arc") | |
.data(pie(pData)) | |
.enter().append("g") | |
.attr('transform', "translate("+200+","+(height+100)+")") | |
.attr("class", "arc"); | |
g.append("path") | |
.attr("d", arc) | |
//.attr('transform', explode) | |
.style('stroke','none') | |
.style("fill", function(d) {return color(d.data.value); }); | |
g.append("text") | |
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) | |
.attr("dy", ".35em") | |
.text(function(d) { return d.data.age; }); | |
var coverArc = g.append("path") | |
.attr("fill","white") | |
.attr("d", d3.arc() | |
.endAngle(Math.PI*2) | |
.startAngle(percentage * Math.PI*2) | |
.outerRadius(radius - 50) | |
.innerRadius(radius - 70)); | |
var label = g.append('text') | |
.text(percentage) // magic number | |
.style('font-family','TW Cen MT') | |
.attr('text-anchor','middle') | |
.attr('x',0) | |
.attr('y',5); | |
var province = g.append('text') | |
.attr('x',100) | |
.attr('y',-200) | |
.text('Afghanistan') | |
.style('font-size', '52px'); | |
var h2G = g.append('g'); | |
h2G.append('rect') | |
.attr('x',-100) | |
.attr('y',-150) | |
.attr('width',200) | |
.attr('height',100) | |
.style('fill',"#fff"); | |
h2G.append('text') | |
.text("Government Index") // magic number | |
.style('font-family','TW Cen MT') | |
.style("font-size", "18px") | |
.attr('text-anchor','middle') | |
.attr('x',0) | |
.attr('y',-70); | |
function progressDonut(datum) { | |
// progress one chart | |
var percentage = datum.properties.gov; | |
console.log(percentage) | |
label.text(percentage); | |
function transition() { | |
coverArc | |
.transition() | |
.tween("d", function(d) { | |
var that = d3.select(this), | |
i = d3.interpolateNumber(0, percentage); | |
return function(t) { | |
that.attr("d", d3.arc() | |
.endAngle(Math.PI*2) | |
.startAngle(i(t)/100 * Math.PI*2) | |
.outerRadius(radius - 10) | |
.innerRadius(radius - 70) | |
) | |
label.text(Math.round(i(t))); | |
}; | |
}) | |
.duration(1000); | |
} | |
transition(); | |
province | |
.transition() | |
.duration(750) | |
.tween("text", function() { | |
var self = this; | |
var newText = datum.properties.name; | |
var textLength = newText.length; | |
return function(t) { | |
self.textContent = newText.slice(0, Math.round(t * textLength)); | |
}; | |
}); | |
} | |
//donut2 start | |
var percentage2 = 1919; | |
var arc2 = d3.arc() | |
.outerRadius(radius - 50) | |
.innerRadius(radius - 70); | |
var pie2 = d3.pie() | |
.padAngle(.05) | |
.sort(null) | |
.value(function(d) { return d.interval; }); | |
var g2 = graphGroup.selectAll(".arc2") | |
.data(pie2(pData)) | |
.enter().append("g") | |
.attr('transform', "translate("+400+","+(height+100)+")") | |
.attr("class", "arc2"); | |
g2.append("path") | |
.attr("d", arc2) | |
//.attr('transform', explode) | |
.style('stroke','none') | |
.style("fill", function(d) {return color(d.data.value); }); | |
g2.append("text") | |
.attr("transform", function(d) { return "translate(" + arc2.centroid(d) + ")"; }) | |
.attr("dy", ".35em") | |
.text(function(d) { return d.data.age; }); | |
var coverArc2 = g2.append("path") | |
.attr("fill","white") | |
.attr("d", d3.arc() | |
.endAngle(Math.PI*2) | |
.startAngle(percentage2 * Math.PI*2) | |
.outerRadius(radius - 50) | |
.innerRadius(radius - 70)); | |
var label2 = g2.append('text') | |
.text(percentage2) // magic number | |
.style('font-family','TW Cen MT') | |
.attr('text-anchor','middle') | |
.attr('font-size',48) | |
.attr('x',0) | |
.attr('y',5); | |
var h2G2 = g2.append('g'); | |
h2G2.append('rect') | |
.attr('x',-100) | |
.attr('y',-150) | |
.attr('width',200) | |
.attr('height',100) | |
.style('fill',"#fff"); | |
h2G2.append('text') | |
.text("GDP per Capita") // magic number | |
.style('font-family','TW Cen MT') | |
.style("font-size", "18px") | |
.attr('text-anchor','middle') | |
.attr('x',0) | |
.attr('y',-70); | |
function progressText(datum) { | |
// progress one chart | |
var percentage2 = datum.properties.gdp; | |
console.log(percentage2) | |
label2.text(percentage2); | |
function transition() { | |
coverArc2 | |
.transition() | |
.tween("d", function(d) { | |
var that = d3.select(this), | |
i = d3.interpolateNumber(0, percentage2); | |
return function(t) { | |
label2.text(Math.round(i(t))); | |
}; | |
}) | |
.duration(1000); | |
} | |
transition(); | |
} | |
//donut3 start | |
var percentage3 = 20; | |
var pData3 = d3.range(16).map(function(d) { | |
return { value: d*3.125, interval: 3.125 }; | |
}) | |
var arc3 = d3.arc() | |
.outerRadius(radius - 50) | |
.innerRadius(radius - 70); | |
var pie3 = d3.pie() | |
.padAngle(.05) | |
.sort(null) | |
.value(function(d) { return d.interval; }); | |
var g3 = graphGroup.selectAll(".arc3") | |
.data(pie3(pData3)) | |
.enter().append("g") | |
.attr('transform', "translate("+600+","+(height+100)+")") | |
.attr("class", "arc3"); | |
g3.append("path") | |
.attr("d", arc3) | |
//.attr('transform', explode) | |
.style('stroke','none') | |
.style("fill", function(d) {return color(d.data.value); }); | |
g3.append("text") | |
.attr("transform", function(d) { return "translate(" + arc3.centroid(d) + ")"; }) | |
.attr("dy", ".35em") | |
.text(function(d) { return d.data.age; }); | |
var coverArc3 = g3.append("path") | |
.attr("fill","white") | |
.attr("d", d3.arc() | |
.endAngle(Math.PI*2) | |
.startAngle(percentage3 * Math.PI*2) | |
.outerRadius(radius - 50) | |
.innerRadius(radius - 70)); | |
var label3 = g3.append('text') | |
.text(percentage3) // magic number | |
.style('font-family','TW Cen MT') | |
.attr('text-anchor','middle') | |
.attr('x',0) | |
.attr('y',5); | |
var h2G3 = g3.append('g'); | |
h2G3.append('rect') | |
.attr('x',-100) | |
.attr('y',-150) | |
.attr('width',200) | |
.attr('height',100) | |
.style('fill',"#fff"); | |
h2G3.append('text') | |
.text("Happiness Index") // magic number | |
.style('font-family','TW Cen MT') | |
.style("font-size", "18px") | |
.attr('text-anchor','middle') | |
.attr('x',0) | |
.attr('y',-70); | |
function progressDonut3(datum) { | |
// progress one chart | |
var percentage = datum.properties.happy; | |
console.log(percentage) | |
label3.text(percentage); | |
function transition() { | |
coverArc3 | |
.transition() | |
.tween("d", function(d) { | |
var that = d3.select(this), | |
i = d3.interpolateNumber(0, percentage); | |
return function(t) { | |
that.attr("d", d3.arc() | |
.endAngle(Math.PI*2) | |
.startAngle(i(t)/50 * Math.PI*2) | |
.outerRadius(radius - 10) | |
.innerRadius(radius - 70) | |
) | |
label3.text(Math.round(i(t))); | |
}; | |
}) | |
.duration(1000); | |
} | |
transition(); | |
} | |
//scatterplot start | |
var xScale = d3.scaleLinear() | |
.range([1010,1450]) | |
.domain([0, 50]); | |
graphGroup.append("g") | |
.attr("class", "axis axis--x") | |
.attr("transform", "translate("+0+","+ 451 + ")") | |
.call(d3.axisBottom(xScale)); | |
graphGroup.selectAll('circle') | |
.data(data.features.filter(function(d) {return d.properties.happy!==""})) | |
.enter() | |
.append('circle') | |
.style('fill', function(d) { return color(d.properties.gov)}) | |
.attr('cx', function(d) {return xScale(d.properties.happy)}) | |
.attr('cy', function(d) {return legendScale(d.properties.gov)}) | |
.attr('r', 4); | |
function circUpdate(datum) { | |
var allCircles = graphGroup.selectAll('circle'); | |
var thisCircle = graphGroup.selectAll('circle').filter(function(d) {return d==datum}); | |
allCircles | |
.transition() | |
.attr('r', 4) | |
.duration(1000); | |
thisCircle | |
.transition() | |
.attr('r',20) | |
.duration(1000); | |
} | |
}) | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment