Skip to content

Instantly share code, notes, and snippets.

@djbarnwal
Last active July 11, 2018 19:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djbarnwal/da9cc47ec78e213d2cd9a5cc0f380305 to your computer and use it in GitHub Desktop.
Save djbarnwal/da9cc47ec78e213d2cd9a5cc0f380305 to your computer and use it in GitHub Desktop.
Fifa Visualization
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Fifa Visualization - iodide</title>
<link rel="stylesheet" type="text/css" href="iodide.dev.css">
</head>
<body>
<script id="jsmd" type="text/jsmd">
%% meta
{
"title": "Fifa Visualization",
"lastSaved": "2018-07-11T19:44:50.532Z",
"lastExport": "2018-07-11T19:49:25.155Z"
}
%% md
# Country wise performance in Fifa World Cup
## by their wins, loses and draws
%% css
h1, h2 {
margin: 0 !important;
max-width: 1000px !important;
}
%% resource
https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.js
%% js
var countryGrid = { columns: 5, rows: 8 };
var cellSize = { width: 190, height: 120 };
var maxRadius = (Math.floor(cellSize.height / 2) - 30);
var scaleRadius = d3.scaleLinear()
.domain([0, 100])
.range([10, maxRadius]);
var matchResults = ["Won", "Lost", "Draw"]
var scaleColor = d3.scaleOrdinal()
.domain(matchResults)
.range(["#F13C05", "#FF7747", "#35D4DA"]);
%% md
<div class="content">
<div class="legend">
<div class="column">
<div class="title">Match<br/>Results</div>
<div class="legend-statuses"></div>
</div>
<div class="column">
<div class="title">Total<br/>Matches</div>
<div class="legend-duration"></div>
</div>
</div>
<div class="container"></div>
</div>
%% js
d3.csv("https://gist.githubusercontent.com/djbarnwal/05b931c63251eb21b5b352349a94b6c2/raw/e4fd6ef546b283eda8715423a5464f7018a04a31/fifadata.csv", function(error, source) {
if (error) throw error;
var data = prepareData(source.slice(0,40));
var svg = createContainer();
appendGooeyFilter(svg);
generateChart(svg, data);
});
function createContainer() {
var width = cellSize. width * countryGrid.columns;
var height = cellSize. height * countryGrid.rows;
var svg = d3.select(".container")
.append("svg")
.attr("width", width)
.attr("height", height);
return svg;
};
function prepareData(source) {
return source.map(function (item) {
var aggregated = {
team: item['Team'],
bestFinish: item['Best finish'],
results: []
};
aggregated.results = [
{ status: "Won", duration: item['W'] },
{ status: "Lost", duration: item['D'] },
{ status: "Draw", duration: item['L'] }
];
return aggregated;
});
};
function generateChart(svg, data) {
var countries = svg
.append("g")
.selectAll("g")
.data(data).enter()
.append("g")
.attr("class", "state")
.attr("transform", (d, i) => {
var x = (i % countryGrid.columns) * cellSize.width;
var y = Math.floor(i / countryGrid.columns) * (cellSize.height + 40);
return "translate(" + x + "," + y + ")";
});
var titleOffset = cellSize.width / 2;
countries
.append("text")
.attr("transform", "translate(" + titleOffset + ",15)")
.style("text-anchor", "middle")
.text(d => d.team);
countries
.append("text")
.attr("transform", "translate(" + titleOffset + ",100)")
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text('Best Performance');
countries
.append("text")
.attr("transform", "translate(" + titleOffset + ",120)")
.style("text-anchor", "middle")
.text(d => d.bestFinish);
var charts = countries
.append("g")
.style("filter", "url(#gooeyFilter)");
charts
.selectAll("circle")
.data((d) => prepareSingleChart(d.results)).enter()
.append("circle")
.attr("r", (d) => d.radius )
.attr("cx", (d) => d.offset )
.style("fill", (d) => d.color)
.style("fill-opacity", "0.7")
charts
.attr("transform", function() {
var realSize = d3.select(this).node().getBoundingClientRect();
var xOffset = (cellSize.width - realSize.width) / 2 ;
var yOffset = maxRadius + 15;
return "translate(" + xOffset + "," + yOffset +")"
});
};
function prepareSingleChart(data) {
var result = [];
var offset = 0;
for (var i = 0; i < data.length; i++) {
var item = data[i];
if (item.duration == 0) {
continue;
}
var radius = scaleRadius(item.duration);
offset = offset + radius;
result.push({
radius: radius,
offset: offset,
color: scaleColor(item.status)
});
offset = offset + radius;
}
return result;
}
function appendGooeyFilter(svg) {
var filter = svg.append("defs").append("filter").attr("id","gooeyFilter");
filter.append("feGaussianBlur")
.attr("in","SourceGraphic")
.attr("stdDeviation", 5)
.attr("color-interpolation-filters","sRGB")
.attr("result","blur");
filter.append("feColorMatrix")
.attr("in","blur")
.attr("mode","matrix")
.attr("values","1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9")
.attr("result","gooey");
}
%% css
.user-markdown {
max-width: 1000px;
margin: 0 auto;
text-align: center;
}
.content {
max-width: 1000px !important;
}
.container {
max-width: 1000px !important;
margin-top: 40px !important;
}
.legend {
display: flex;
flex-wrap: wrap;
margin: 10px 70px 50px 70px;
padding: 10px 50px;
border: 1px #dadada;
border-style: solid none;
}
.legend text {
text-anchor: left;
font-size: 12px;
fill: #333;
}
.legend .column {
display: flex;
flex-wrap: wrap;
flex: 1 1 auto;
align-items: center;
}
.legend .title {
padding-right: 30px;
color: #777;
font-size: 0.9em;
}
%% js
appendStatusLegend();
appendDurationLegend();
function appendStatusLegend() {
var svg = d3.select(".legend-statuses")
.append("svg")
.attr("width", 200)
.attr("height", 80);
var resultsLegend = svg.append("g").attr("class", "results");
var results = resultsLegend.selectAll("g")
.data(matchResults).enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + (30 * i)+ ")"});
results
.append("circle")
.attr("cx", 10)
.attr("cy", 10)
.attr("r", 7)
.style("fill", function(d) { return scaleColor(d) });
results
.append("text")
.attr("transform", "translate(25,14)")
.text(function(d) { return d;});
}
function appendDurationLegend() {
var svg = d3.select(".legend-duration")
.append("svg")
.attr("width", 300)
.attr("height", 80);
var matchesLegend = svg
.append("g")
.attr("class", "duration")
.attr("transform", "translate(30, 35)");
var matches = matchesLegend
.selectAll("g")
.data([5, 40, 75]).enter()
.append("g")
.attr("transform", function(d, i) { return "translate(" + (i * 85) + ", 0)"});
matches
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", function(d) { return scaleRadius(d) - 5; })
.style("fill", "#dadada");
matches
.append("text")
.attr("transform","translate(0, 40)")
.text(function(d) { return d + " matches"; })
.style("text-anchor", "middle")
}
%% js
</script>
<div id='page'></div>
<script src='iodide.dev.js'></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment