Compare commits

..

No commits in common. '31ff20dbf3adaac1b4bb61954f8515cf40e05364' and '27cac531130b803ec27b2df86d6c9a716d3c9abf' have entirely different histories.

  1. 80
      index.html
  2. 430
      js/bundle.js
  3. 196
      js/diagram.js
  4. 66
      js/hotfixes.js
  5. 139
      js/index.js
  6. 4
      js/matrices.js

@ -21,7 +21,7 @@
<blockquote>
Explore D3's chord diagrams using World Cup match data. Use Haskell to build JSON parsers.
<br><br>
The visualization should invite interaction to create and answer questions such as:
Visualization should invite interaction to create and answer questions such as:
<ul>
<li>How many times has Iran competed in a World Cup?</li>
<li>Which teams played the in final in 1986?</li>
@ -36,7 +36,7 @@
</p>
<p>
This visualization is created using D3.js. Note that null-null relationships are not displayed on chord diagrams. As a result, matches with a score of 0-0 are not shown.
This visualization is created using D3 and Three.js libraries.
</p>
<hr>
@ -53,77 +53,40 @@
</div>
</div>
<!-- <div class="notes">
<div class="notes">
<h5>TODO</h5>
1930: OK
1934: Patched.
OK Italy Spain replay 1-0!
Italy Spain replay 1-0!
1938:
OK Switzerland Germany 1-1 replay 4-2
OK Cuba Romania 3-3 replay 3-2
OK Brazil Czech 1-1 replay 2-1
Switzerland Germany replay 4-2
Cuba Romania replay 3-2
Brazil Czech replay 2-1
1950: OK
1954:
OK Germany Turkey 4-1 playoff 7-2
OK Switzerland Italy 2-1 playoff 4-1
OK Germany Hungary 3-8 final 3-2
Germany Turkey playoff 7-2
Switzerland Italy playoff 4-1
Germany Hungary final 3-2
1958:
Northern Ireland Czech playoff 2-1
Wales Hungary replay 2-1
Sweden Wales 0-0
Brazil England 0-0
OK Northern Ireland Czech 1-0 playoff 2-1
OK Wales Hungary 1-1 replay 2-1
OK Russia England 1-0 replay 2-2
Russia England replay 1-0
1962:
Germany Italy 0-0
Brazil Czech Republic 0-0
Hungary Argentina 0-0
England Bulgaria 0-0
1966:
England Uruguay 0-0
Mexico Uruguay 0-0
Argentina Germany 0-0
1970:
Mexico Russia 0-0
Uruguay Italy 0-0
Israel Italy 0-0
1974:
Australia Chile 0-0
Brazil Yugoslavia 0-0
Scotland Brazil 0-0
Sweden Bulgaria 0-0
1978:
Germany Poland 0-0
Germany Tunisia 0-0
Brazil Spain 0-0
Netherlands Peru 0-0
Italy Germany 0-0
Argentina Brazil 0-0
1982:
Italy Poland 0-0
Peru Cameroon 0-0
Poland Cameroon 0-0
Serbia Northern Ireland 0-0
Russia Poland 0-0
Germany England 0-0
Spain England 0-0
1986:
Scotland Uruguay 0-0
Morocco Poland 0-0
1990:
Uruguay Spain 0-0
England Netherlands 0-0
Ireland Egypt 0-0
1994:
South Korea Bolivia 0-0
Ireland Norway 0-0
Brazil Sweden replay
1998:
Paraguay Bulgaria 0-0
Spain Paraguay 0-0
Netherlands Belgium 0-0
2002:
France Uruguay 0-0
Nigeria England 0-0
OK Brazil Turkey replay 1-0
Brazil Turkey replay 1-0
2006:
Trinidad Tobago Sweden 0-0
Netherlands Argentina 0-0
@ -143,7 +106,18 @@
Costa Rica England 0-0
Ecuador France 0-0
Iran-Nigeria 0-0
</div> -->
Brazil Chile replay
Costa Rica Greece replay
Netherlands Costa Rica replay
Argentina Netherlands replay
gremlins?
african dictator visualization
update gogs
update drone
tweet it!
</div>
</body>
</html>
`

@ -58,12 +58,13 @@
var _ui2 = _interopRequireDefault(_ui);
var _hotfixes = __webpack_require__(5);
var _hotfixes = __webpack_require__(13);
var _hotfixes2 = _interopRequireDefault(_hotfixes);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
__webpack_require__(5);
__webpack_require__(6);
__webpack_require__(7);
__webpack_require__(8);
@ -71,7 +72,6 @@
__webpack_require__(10);
__webpack_require__(11);
__webpack_require__(12);
__webpack_require__(13);
var main = {
changeEvent: function changeEvent(e) {
@ -105,46 +105,22 @@
main.updateUI();
},
// DEPRECATED? 161120
// getRounds: (eventKey) => {
// const rounds = {};
//
// main.json.tourneys[eventKey].games.forEach(game => {
// const name = UI.getRoundName(main.json.rounds[game.rId]);
// if (rounds[name] === undefined) {
// rounds[name] = [];
// }
//
// rounds[name].push({
// id: game.rId,
// name: name,
// });
// });
//
// return rounds;
// },
getDuplicates: function getDuplicates(eventKey) {
var games = {};
getRounds: function getRounds(eventKey) {
var rounds = {};
main.json.tourneys[eventKey].games.forEach(function (game) {
var teams = [game.t1, game.t2].sort();
var addr = teams[0] + '-' + teams[1];
if (games[addr] === undefined) {
games[addr] = [];
var name = _ui2.default.getRoundName(main.json.rounds[game.rId]);
if (rounds[name] === undefined) {
rounds[name] = [];
}
games[addr].push(game);
rounds[name].push({
id: game.rId,
name: name
});
});
return Object.keys(games).reduce(function (acc, k) {
if (games[k].length > 1) {
acc.push(games[k]);
}
return acc;
}, []);
return rounds;
},
generateUI: function generateUI() {
@ -159,103 +135,10 @@
updateUI: function updateUI() {
var state = main.getState();
var eventKey = state.eventKey;
var matrix = _matrices2.default.buildMatrix(main.json, eventKey);
var duplicates = main.getDuplicates(eventKey);
var tmp = _diagram2.default.buildChords({
data: main.json,
sort: state.sort,
eventKey: eventKey,
matrix: matrix,
SORT_TYPES: _ui2.default.SORT_TYPES
});
var getScore = function getScore(game) {
var s1 = game.s1;
var s2 = game.s2;
if (game.sp1 !== null) {
s1 = game.sp1;
} else if (game.se1 !== null) {
s1 = game.se1;
}
if (game.sp2 !== null) {
s2 = game.sp2;
} else if (game.se2 !== null) {
s2 = game.se2;
}
return { s1: s1, s2: s2 };
};
var chords = tmp.reduce(function (acc, d) {
var tSrc = main.json.tourneys[eventKey].teams[d.source.index].tId;
var tTgt = main.json.tourneys[eventKey].teams[d.target.index].tId;
d.game = main.json.tourneys[eventKey].games.find(function (g) {
return g.t1 === tSrc && g.t2 === tTgt || g.t1 === tTgt && g.t2 === tSrc;
});
duplicates.forEach(function (games) {
if (games[0] === d.game || games[1] === d.game) {
var gameNew = games[0] === d.game ? games[1] : games[0];
var sourceNew = Object.assign({}, d.source);
var targetNew = Object.assign({}, d.target);
var sourceAngle = d.source.endAngle - d.source.startAngle;
var targetAngle = d.target.endAngle - d.target.startAngle;
var _getScore = getScore(games[0]),
s1g0 = _getScore.s1,
s2g0 = _getScore.s2;
var _getScore2 = getScore(games[1]),
s1g1 = _getScore2.s1,
s2g1 = _getScore2.s2;
var totals = { src: 0, tgt: 0 };
var offset = { src: 0, tgt: 0 };
totals.src += games[0].t1 === tSrc ? s1g0 : s2g0;
totals.tgt += games[0].t1 === tTgt ? s1g0 : s2g0;
totals.src += games[1].t1 === tSrc ? s1g1 : s2g1;
totals.tgt += games[1].t1 === tTgt ? s1g1 : s2g1;
offset.src = games[0].t1 === tSrc ? s1g0 : s2g0;
offset.tgt = games[0].t1 === tTgt ? totals.tgt - s1g0 : totals.tgt - s2g0;
sourceNew.startAngle = d.source.startAngle + sourceAngle * (offset.src / totals.src);
d.source.endAngle = d.source.startAngle + sourceAngle * (offset.src / totals.src);
targetNew.endAngle = d.target.startAngle + targetAngle * (offset.tgt / totals.tgt);
d.target.startAngle = d.target.startAngle + targetAngle * (offset.tgt / totals.tgt);
acc.push({ source: sourceNew, target: targetNew, game: gameNew });
}
});
acc.push(d);
return acc;
}, []);
chords.groups = tmp.groups;
var matrix = _matrices2.default.buildMatrix(main.json, state.eventKey);
_diagram2.default.clear();
var color = _diagram2.default.buildColorScheme({
scheme: parseInt(state.scheme),
len: main.json.tourneys[state.eventKey].teams.length
});
var container = _diagram2.default.buildContainer(chords);
_diagram2.default.buildArcs({ container: container, color: color, eventKey: eventKey, data: main.json });
_diagram2.default.buildRibbons({ container: container, color: color, chords: chords, eventKey: eventKey, data: main.json });
_diagram2.default.build(main.json, state.eventKey, state.sort, state.scheme, _ui2.default.SORT_TYPES, matrix);
_ui2.default.updateTourneyPane(state.eventKey);
_ui2.default.updateEventsPane(state.eventKey);
@ -267,7 +150,7 @@
fetch: function fetch(url) {
return new Promise(function (resolve, reject) {
var listener = function listener(_ref) {
var req = _ref.target;
var req = _ref.srcElement;
req.status === 200 ? resolve(req.responseText) : reject("busted");
};
@ -384,8 +267,8 @@
s2 += g.s2;
}
matrix[i1][i2] = s1;
matrix[i2][i1] = s2;
matrix[i1][i2] = g.s1 + g.se1 + g.sp1;
matrix[i2][i1] = g.s2 + g.se2 + g.sp2;
}, []);
return matrix;
@ -412,8 +295,6 @@
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _sorter = __webpack_require__(3);
var _sorter2 = _interopRequireDefault(_sorter);
@ -541,81 +422,82 @@
return team.ga;
},
buildChords: function buildChords(_ref) {
var matrix = _ref.matrix,
data = _ref.data,
eventKey = _ref.eventKey,
sort = _ref.sort,
SORT_TYPES = _ref.SORT_TYPES;
build: function build(data, eventKey, sort, scheme, SORT_TYPES, matrix) {
var svg = d3.select("svg"),
width = svg.attr("width"),
height = svg.attr("height"),
outerArcThickness = 5,
outerRadius = Math.min(width, height) * 0.5 - 130,
innerRadius = outerRadius - outerArcThickness;
var chords = d3.chord().padAngle(0.05).call(null, matrix);
var sortedChords = chords;
switch (sort) {
case SORT_TYPES.COUNTRY:
return _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getCountryName.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
sortedChords = _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getCountryName.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
break;
case SORT_TYPES.GOALS:
return _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getGoalsFor.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
sortedChords = _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getGoalsFor.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
break;
case SORT_TYPES.POPULATION:
return _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getPopulation.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
sortedChords = _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getPopulation.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
break;
}
return chords;
},
buildDimensions: function buildDimensions() {
var svgW = d3.select("svg").attr("width");
var svgH = d3.select("svg").attr("height");
var arcT = 5;
var outerR = Math.min(svgW, svgH) * 0.5 - 130;
var innerR = outerR - arcT;
var arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
return { svgW: svgW, svgH: svgH, arcT: arcT, outerR: outerR, innerR: innerR };
},
var ribbon = d3.ribbon().radius(innerRadius);
buildColorScheme: function buildColorScheme(_ref2) {
var scheme = _ref2.scheme,
len = _ref2.len;
var len = data.tourneys[eventKey].teams.length;
var color = d3.scaleOrdinal(d3.schemeCategory20);
if (scheme === 1) {
return d3.scaleLinear().domain([0, len]).range(["#fff", "green"]).interpolate(d3.interpolateRgb);
} else if (scheme === 2) {
var _ret = function () {
(function () {
switch (parseInt(scheme)) {
case 1:
color = d3.scaleLinear().domain([0, len]).range(["#fff", "green"]).interpolate(d3.interpolateRgb);
break;
case 2:
var colors = ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"];
return {
v: function v(i) {
color = function color(i) {
return colors[i % colors.length];
}
};
}();
if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
} else if (scheme === 3) {
return d3.scaleLinear().domain([0, len]).range(["red", "blue"]).interpolate(d3.interpolateRgb);
} else if (scheme === 4) {
return d3.scaleOrdinal(d3.schemeCategory10);
break;
case 3:
color = d3.scaleLinear().domain([0, len]).range(["red", "blue"]).interpolate(d3.interpolateRgb);
break;
case 4:
color = d3.scaleOrdinal(d3.schemeCategory10);
break;
}
})();
return d3.scaleOrdinal(d3.schemeCategory20);
},
var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")").datum(sortedChords);
buildRibbons: function buildRibbons(_ref3) {
var container = _ref3.container,
color = _ref3.color,
chords = _ref3.chords,
data = _ref3.data,
eventKey = _ref3.eventKey;
var group = g.append("g").attr("class", "groups").selectAll("g").data(function (chords) {
return chords.groups;
}).enter().append("g");
var dimensions = Diagram.buildDimensions();
var ribbon = d3.ribbon().radius(dimensions.innerR);
group.append("path").style("fill", function (d) {
return color(d.index);
}).style("stroke", function (d) {
return d3.rgb(color(d.index)).darker();
}).attr("d", arc);
container.append("g").attr("class", "ribbons").selectAll("path").data(function (chords) {
g.append("g").attr("class", "ribbons").selectAll("path").data(function (chords) {
return chords;
}).enter().append("path").attr("d", ribbon).attr('data-round-id', function (d) {
return d.game.rId;
}).style('fill', function (d) {
}).enter().append("path").attr("d", ribbon).attr("data-round-id", function (d) {
var t1 = data.tourneys[eventKey].teams[d.source.index];
var t2 = data.tourneys[eventKey].teams[d.target.index];
var game = data.tourneys[eventKey].games.find(function (v) {
return (v.t1 === t1.tId || v.t1 === t2.tId) && (v.t2 === t1.tId || v.t2 === t2.tId);
});
return game.rId;
}).style("fill", function (d) {
return color(d.target.index);
}).style('stroke', function (d) {
}).style("stroke", function (d) {
return d3.rgb(color(d.target.index)).darker();
}).classed("ribbon", true).append("title").text(function (d) {
var t1 = data.tourneys[eventKey].teams[d.source.index];
@ -624,74 +506,60 @@
var c1 = data.countries[t1.cId];
var c2 = data.countries[t2.cId];
var s1 = d.game.t1 === t1.tId ? d.game.s1 : d.game.s2;
var s2 = d.game.t2 === t2.tId ? d.game.s2 : d.game.s1;
var game = data.tourneys[eventKey].games.find(function (v) {
return (v.t1 === t1.tId || v.t1 === t2.tId) && (v.t2 === t1.tId || v.t2 === t2.tId);
});
var s1 = game.t1 === t1.tId ? game.s1 : game.s2;
var s2 = game.t2 === t2.tId ? game.s2 : game.s1;
if (d.game.sp1 !== null && d.game.sp2 !== null) {
s1 = d.game.t1 === t1.tId ? d.game.sp1 : d.game.sp2;
s2 = d.game.t2 === t2.tId ? d.game.sp2 : d.game.sp1;
if (game.sp1 !== null && game.sp2 !== null) {
s1 = game.t1 === t1.tId ? game.sp1 : game.sp2;
s2 = game.t2 === t2.tId ? game.sp2 : game.sp1;
s1 += " (Penalties)";
s2 += " (Penalties)";
} else if (d.game.se1 !== null && d.game.se2 !== null) {
s1 = d.game.t1 === t1.tId ? d.game.se1 : d.game.se2;
s2 = d.game.t2 === t2.tId ? d.game.se2 : d.game.se1;
} else if (game.se1 !== null && game.se2 !== null) {
s1 = game.t1 === t1.tId ? game.se1 : game.se2;
s2 = game.t2 === t2.tId ? game.se2 : game.se1;
s1 += " (Extended time)";
s2 += " (Extended time)";
}
return c1 + ': ' + s1 + '\n' + c2 + ': ' + s2 + '\n' + data.rounds[d.game.rId];
});
},
buildArcs: function buildArcs(_ref4) {
var container = _ref4.container,
color = _ref4.color,
eventKey = _ref4.eventKey,
data = _ref4.data;
var dimensions = Diagram.buildDimensions();
var arc = d3.arc().innerRadius(dimensions.innerR).outerRadius(dimensions.outerR);
var group = container.append("g").attr("class", "groups").selectAll("g").data(function (chords) {
return chords.groups;
}).enter().append("g");
// const s1 = game.t1 === t1.tId ? game.s1 : game.s2;
// const s2 = game.t2 === t2.tId ? game.s2 : game.s1;
//
// const e1 = game.se1 ? `(+${game.se1} in extended time)` : '';
// const e2 = game.se2 ? `(+${game.se2} in extended time)` : '';
//
// const p1 = game.sp1 ? `(+${game.sp1} in penalties)` : '';
// const p2 = game.sp2 ? `(+${game.sp2} in penalties)` : '';
group.append("path").style("fill", function (d) {
return color(d.index);
}).style("stroke", function (d) {
return d3.rgb(color(d.index)).darker();
}).attr("d", arc);
return c1 + ': ' + s1 + '\n' + c2 + ': ' + s2 + '\n' + data.rounds[game.rId];
});
group.append("text").each(function (d) {
d.angle = (d.startAngle + d.endAngle) / 2;
}).attr("dy", ".35em").attr("transform", function (d) {
return "rotate(" + (d.angle * 180 / Math.PI - 91) + ")" + "translate(" + (dimensions.innerR + 26) + ")" + (d.angle > Math.PI ? "rotate(180)" : "");
return "rotate(" + (d.angle * 180 / Math.PI - 91) + ")" + "translate(" + (innerRadius + 26) + ")" + (d.angle > Math.PI ? "rotate(180)" : "");
}).style("text-anchor", function (d) {
return d.angle > Math.PI ? "end" : null;
}).text(function (d) {
var team = data.tourneys[eventKey].teams[d.index];
var metric = '';
// switch (sort) {
// case SORT_TYPES.GOALS:
// metric = `(${team.gf})`;
switch (sort) {
case SORT_TYPES.GOALS:
metric = '(' + team.gf + ')';
break;
// case SORT_TYPES.POPULATION:
// metric = `(${Number(team.p).toLocaleString()})`;
// break;
// // case SORT_TYPES.POPULATION:
// // metric = `(${Number(team.p).toLocaleString()})`;
// // break;
// }
}
return data.countries[team.cId] + ' ' + metric;
});
},
buildContainer: function buildContainer(chords) {
var svg = d3.select("svg");
var dimensions = Diagram.buildDimensions();
return svg.append("g").attr("transform", 'translate(' + dimensions.svgW / 2 + ',' + dimensions.svgH / 2 + ')').datum(chords);
}
};
@ -1132,6 +1000,54 @@
/***/ },
/* 5 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 6 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 7 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 8 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 9 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 10 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 11 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 12 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 13 */
/***/ function(module, exports) {
"use strict";
@ -1206,53 +1122,5 @@
exports.default = hotfixes;
/***/ },
/* 6 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 7 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 8 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 9 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 10 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 11 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 12 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ },
/* 13 */
/***/ function(module, exports) {
// removed by extract-text-webpack-plugin
/***/ }
/******/ ]);

@ -120,86 +120,96 @@ const Diagram = {
return team.ga;
},
buildChords: ({ matrix, data, eventKey, sort, SORT_TYPES }) => {
build: (data, eventKey, sort, scheme, SORT_TYPES, matrix) => {
const svg = d3.select("svg"),
width = (svg.attr("width")),
height = (svg.attr("height")),
outerArcThickness = 5,
outerRadius = Math.min(width, height) * 0.5 - 130,
innerRadius = outerRadius - outerArcThickness;
const chords = d3.chord()
.padAngle(0.05)
.call(null, matrix);
let sortedChords = chords;
switch (sort) {
case SORT_TYPES.COUNTRY:
return Sorter.sort(chords, 0, chords.groups.length - 1,
sortedChords = Sorter.sort(chords, 0, chords.groups.length - 1,
Diagram.getCountryName.bind(null, data, eventKey),
Diagram.swapGroups.bind(null, data, eventKey));
break;
case SORT_TYPES.GOALS:
return Sorter.sort(chords, 0, chords.groups.length - 1,
sortedChords = Sorter.sort(chords, 0, chords.groups.length - 1,
Diagram.getGoalsFor.bind(null, data, eventKey),
Diagram.swapGroups.bind(null, data, eventKey));
break;
case SORT_TYPES.POPULATION:
return Sorter.sort(chords, 0, chords.groups.length - 1,
sortedChords = Sorter.sort(chords, 0, chords.groups.length - 1,
Diagram.getPopulation.bind(null, data, eventKey),
Diagram.swapGroups.bind(null, data, eventKey));
break;
}
return chords;
},
buildDimensions: () => {
const svgW = d3.select("svg").attr("width");
const svgH = (d3.select("svg").attr("height"));
const arcT = 5;
const outerR = Math.min(svgW, svgH) * 0.5 - 130;
const innerR = outerR - arcT;
return { svgW, svgH, arcT, outerR, innerR};
},
buildColorScheme: ({ scheme, len }) => {
if (scheme === 1) {
return d3.scaleLinear()
.domain([0, len])
.range(["#fff", "green"])
.interpolate(d3.interpolateRgb);
} else if (scheme === 2) {
const colors = [
"#ffffd9",
"#edf8b1",
"#c7e9b4",
"#7fcdbb",
"#41b6c4",
"#1d91c0",
"#225ea8",
"#253494",
"#081d58"
];
return (i => colors[i % colors.length]);
} else if (scheme === 3) {
return d3.scaleLinear()
.domain([0, len])
.range(["red", "blue"])
.interpolate(d3.interpolateRgb);
} else if (scheme === 4) {
return d3.scaleOrdinal(d3.schemeCategory10);
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
const ribbon = d3.ribbon()
.radius(innerRadius);
const len = data.tourneys[eventKey].teams.length;
let color = d3.scaleOrdinal(d3.schemeCategory20);
switch (parseInt(scheme)) {
case 1:
color = d3.scaleLinear().domain([0, len]).range(["#fff", "green"]).interpolate(d3.interpolateRgb);
break;
case 2:
const colors = ["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"];
color = i => colors[i % colors.length];
break;
case 3:
color = d3.scaleLinear().domain([0, len]).range(["red", "blue"]).interpolate(d3.interpolateRgb);
break;
case 4:
color = d3.scaleOrdinal(d3.schemeCategory10);
break;
}
return d3.scaleOrdinal(d3.schemeCategory20);
},
const g = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.datum(sortedChords);
const group = g.append("g")
.attr("class", "groups")
.selectAll("g")
.data(chords => chords.groups)
.enter().append("g");
buildRibbons: ({ container, color, chords, data, eventKey }) => {
const dimensions = Diagram.buildDimensions();
const ribbon = d3.ribbon().radius(dimensions.innerR);
group.append("path")
.style("fill", d => color(d.index))
.style("stroke", d => d3.rgb(color(d.index)).darker())
.attr("d", arc);
container.append("g")
g.append("g")
.attr("class", "ribbons")
.selectAll("path")
.data(chords => chords)
.data(function(chords) { return chords; })
.enter().append("path")
.attr("d", ribbon)
.attr('data-round-id', d => d.game.rId)
.style('fill', d => color(d.target.index))
.style('stroke', d => d3.rgb(color(d.target.index)).darker())
.attr("data-round-id", (d) => {
const t1 = data.tourneys[eventKey].teams[d.source.index];
const t2 = data.tourneys[eventKey].teams[d.target.index];
const game = data.tourneys[eventKey].games.find(v => {
return (v.t1 === t1.tId || v.t1 === t2.tId) && (v.t2 === t1.tId || v.t2 === t2.tId);
});
return game.rId;
})
.style("fill", (d) => color(d.target.index))
.style("stroke", (d) => d3.rgb(color(d.target.index)).darker())
.classed("ribbon", true)
.append("title")
.text(function(d) {
@ -209,49 +219,46 @@ const Diagram = {
const c1 = data.countries[t1.cId];
const c2 = data.countries[t2.cId];
let s1 = d.game.t1 === t1.tId ? d.game.s1 : d.game.s2;
let s2 = d.game.t2 === t2.tId ? d.game.s2 : d.game.s1;
const game = data.tourneys[eventKey].games.find(v => {
return (v.t1 === t1.tId || v.t1 === t2.tId) && (v.t2 === t1.tId || v.t2 === t2.tId);
});
let s1 = game.t1 === t1.tId ? game.s1 : game.s2;
let s2 = game.t2 === t2.tId ? game.s2 : game.s1;
if (d.game.sp1 !== null && d.game.sp2 !== null) {
s1 = d.game.t1 === t1.tId ? d.game.sp1 : d.game.sp2;
s2 = d.game.t2 === t2.tId ? d.game.sp2 : d.game.sp1;
if (game.sp1 !== null && game.sp2 !== null) {
s1 = game.t1 === t1.tId ? game.sp1 : game.sp2;
s2 = game.t2 === t2.tId ? game.sp2 : game.sp1;
s1 += " (Penalties)";
s2 += " (Penalties)";
}
else if (d.game.se1 !== null && d.game.se2 !== null) {
s1 = d.game.t1 === t1.tId ? d.game.se1 : d.game.se2;
s2 = d.game.t2 === t2.tId ? d.game.se2 : d.game.se1;
else if (game.se1 !== null && game.se2 !== null) {
s1 = game.t1 === t1.tId ? game.se1 : game.se2;
s2 = game.t2 === t2.tId ? game.se2 : game.se1;
s1 += " (Extended time)";
s2 += " (Extended time)";
}
return `${c1}: ${s1}\n${c2}: ${s2}\n${data.rounds[d.game.rId]}`;
});
},
buildArcs: ({ container, color, eventKey, data }) => {
const dimensions = Diagram.buildDimensions();
const arc = d3.arc().innerRadius(dimensions.innerR).outerRadius(dimensions.outerR)
// const s1 = game.t1 === t1.tId ? game.s1 : game.s2;
// const s2 = game.t2 === t2.tId ? game.s2 : game.s1;
//
// const e1 = game.se1 ? `(+${game.se1} in extended time)` : '';
// const e2 = game.se2 ? `(+${game.se2} in extended time)` : '';
//
// const p1 = game.sp1 ? `(+${game.sp1} in penalties)` : '';
// const p2 = game.sp2 ? `(+${game.sp2} in penalties)` : '';
const group = container.append("g")
.attr("class", "groups")
.selectAll("g")
.data(chords => chords.groups)
.enter().append("g");
group.append("path")
.style("fill", d => color(d.index))
.style("stroke", d => d3.rgb(color(d.index)).darker())
.attr("d", arc);
return `${c1}: ${s1}\n${c2}: ${s2}\n${data.rounds[game.rId]}`;
});
group.append("text")
.each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("dy", ".35em")
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 91) + ")"
+ "translate(" + (dimensions.innerR + 26) + ")"
+ "translate(" + (innerRadius + 26) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
@ -259,29 +266,18 @@ const Diagram = {
const team = data.tourneys[eventKey].teams[d.index];
let metric = '';
// switch (sort) {
// case SORT_TYPES.GOALS:
// metric = `(${team.gf})`;
switch (sort) {
case SORT_TYPES.GOALS:
metric = `(${team.gf})`;
break;
// case SORT_TYPES.POPULATION:
// metric = `(${Number(team.p).toLocaleString()})`;
// break;
// // case SORT_TYPES.POPULATION:
// // metric = `(${Number(team.p).toLocaleString()})`;
// // break;
// }
}
return `${data.countries[team.cId]} ${metric}`;
});
},
buildContainer: (chords) => {
const svg = d3.select("svg");
const dimensions = Diagram.buildDimensions();
return svg.append("g")
.attr("transform", `translate(${ dimensions.svgW / 2 },${ dimensions.svgH / 2 })`)
.datum(chords);
},
};
export default Diagram;

@ -1,66 +0,0 @@
const hotfixes = {
patch1934: (data) => {
data.games.forEach(g => {
if (g.t1 === 149 && g.t2 === 2 && g.rId === 13) {
g.s1 = 4;
g.s2 = 2;
}
if (g.t1 === 223 && g.t2 === 146 && g.rId === 13) {
g.s1 = 2;
g.s2 = 1;
}
if (g.t1 === 134 && g.t2 === 223 && g.rId === 18) {
g.s1 = 2;
g.s2 = 1;
}
if (g.t1 === 223 && g.t2 === 153 && g.rId === 14) {
g.s1 = 3;
g.s2 = 2;
}
if (g.t1 === 223 && g.t2 === 127 && g.rId === 16) {
g.s1 = 3;
g.s2 = 1;
}
if (g.t1 === 134 && g.t2 === 129 && g.rId === 14) {
g.s1 = 1;
g.s2 = 1;
}
if (g.t1 === 134 && g.t2 === 191 && g.rId === 13) {
g.s1 = 7;
g.s2 = 1;
}
if (g.t1 === 153 && g.t2 === 137 && g.rId === 13) {
g.s1 = 3;
g.s2 = 2;
}
if (g.t1 === 129 && g.t2 === 211 && g.rId === 13) {
g.s1 = 3;
g.s2 = 1;
}
if (g.t1 === 127 && g.t2 === 125 && g.rId === 13) {
g.s1 = 5;
g.s2 = 2;
}
if (g.t1 === 124 && g.t2 === 131 && g.rId === 13) {
g.s1 = 3;
g.s2 = 2;
}
if (g.t1 === 147 && g.t2 === 210 && g.rId === 13) {
g.s1 = 3;
g.s2 = 2;
}
if (g.t1 === 127 && g.t2 === 124 && g.rId === 17) {
g.s1 = 3;
g.s2 = 2;
}
if (g.t1 === 124 && g.t2 === 149 && g.rId === 14) {
g.s1 = 2;
g.s2 = 1;
}
});
return data;
},
};
export default hotfixes;

@ -44,46 +44,22 @@ const main = {
main.updateUI();
},
// DEPRECATED? 161120
// getRounds: (eventKey) => {
// const rounds = {};
//
// main.json.tourneys[eventKey].games.forEach(game => {
// const name = UI.getRoundName(main.json.rounds[game.rId]);
// if (rounds[name] === undefined) {
// rounds[name] = [];
// }
//
// rounds[name].push({
// id: game.rId,
// name: name,
// });
// });
//
// return rounds;
// },
getDuplicates: (eventKey) => {
const games = {};
getRounds: (eventKey) => {
const rounds = {};
main.json.tourneys[eventKey].games.forEach(game => {
const teams = [game.t1, game.t2].sort();
const addr = `${teams[0]}-${teams[1]}`;
if (games[addr] === undefined) {
games[addr] = [];
const name = UI.getRoundName(main.json.rounds[game.rId]);
if (rounds[name] === undefined) {
rounds[name] = [];
}
games[addr].push(game);
rounds[name].push({
id: game.rId,
name: name,
});
});
return Object.keys(games).reduce((acc, k) => {
if (games[k].length > 1) {
acc.push(games[k]);
}
return acc;
}, []);
return rounds;
},
generateUI: () => {
@ -98,99 +74,10 @@ const main = {
updateUI: () => {
const state = main.getState();
const eventKey = state.eventKey;
const matrix = Matrices.buildMatrix(main.json, eventKey);
const duplicates = main.getDuplicates(eventKey);
const tmp = Diagram.buildChords({
data: main.json,
sort: state.sort,
eventKey,
matrix,
SORT_TYPES: UI.SORT_TYPES,
});
const getScore = (game) => {
let s1 = game.s1;
let s2 = game.s2;
if (game.sp1 !== null) {
s1 = game.sp1;
} else if (game.se1 !== null) {
s1 = game.se1;
}
if (game.sp2 !== null) {
s2 = game.sp2;
} else if (game.se2 !== null) {
s2 = game.se2;
}
return { s1, s2 }
};
const chords = tmp.reduce((acc, d) => {
const tSrc = main.json.tourneys[eventKey].teams[d.source.index].tId;
const tTgt = main.json.tourneys[eventKey].teams[d.target.index].tId;
d.game = main.json.tourneys[eventKey].games
.find(g => {
return (g.t1 === tSrc && g.t2 === tTgt) ||
(g.t1 === tTgt && g.t2 === tSrc)
});
duplicates.forEach(games => {
if (games[0] === d.game || games[1] === d.game) {
const gameNew = (games[0] === d.game ? games[1] : games[0]);
const sourceNew = Object.assign({}, d.source);
const targetNew = Object.assign({}, d.target);
const sourceAngle = d.source.endAngle - d.source.startAngle;
const targetAngle = d.target.endAngle - d.target.startAngle;
const { s1: s1g0, s2: s2g0 } = getScore(games[0]);
const { s1: s1g1, s2: s2g1 } = getScore(games[1]);
const totals = { src: 0, tgt: 0 };
const offset = { src: 0, tgt: 0 }
totals.src += (games[0].t1 === tSrc ? s1g0 : s2g0);
totals.tgt += (games[0].t1 === tTgt ? s1g0 : s2g0);
totals.src += (games[1].t1 === tSrc ? s1g1 : s2g1);
totals.tgt += (games[1].t1 === tTgt ? s1g1 : s2g1);
offset.src = (games[0].t1 === tSrc ? s1g0 : s2g0);
offset.tgt = (games[0].t1 === tTgt ? (totals.tgt - s1g0) : (totals.tgt - s2g0));
sourceNew.startAngle = d.source.startAngle + sourceAngle * (offset.src / totals.src);
d.source.endAngle = d.source.startAngle + sourceAngle * (offset.src / totals.src);
targetNew.endAngle = d.target.startAngle + targetAngle * (offset.tgt / totals.tgt);
d.target.startAngle = d.target.startAngle + targetAngle * (offset.tgt / totals.tgt);
acc.push({ source: sourceNew, target: targetNew, game: gameNew });
}
});
acc.push(d);
return acc;
}, []);
chords.groups = tmp.groups;
const matrix = Matrices.buildMatrix(main.json, state.eventKey);
Diagram.clear();
const color = Diagram.buildColorScheme({
scheme: parseInt(state.scheme),
len: main.json.tourneys[state.eventKey].teams.length,
});
const container = Diagram.buildContainer(chords);
Diagram.buildArcs({ container, color, eventKey, data: main.json });
Diagram.buildRibbons({ container, color, chords, eventKey, data: main.json });
Diagram.build(main.json, state.eventKey, state.sort, state.scheme, UI.SORT_TYPES, matrix);
UI.updateTourneyPane(state.eventKey);
UI.updateEventsPane(state.eventKey);
@ -200,7 +87,7 @@ const main = {
},
fetch: (url) => new Promise((resolve, reject) => {
const listener = ({ target: req }) => {
const listener = ({ srcElement: req }) => {
req.status === 200 ? resolve(req.responseText) : reject("busted");
};

@ -37,8 +37,8 @@ const Matrices = {
s2 += g.s2;
}
matrix[i1][i2] = s1;
matrix[i2][i1] = s2;
matrix[i1][i2] = g.s1 + g.se1 + g.sp1;
matrix[i2][i1] = g.s2 + g.se2 + g.sp2;
}, []);
return matrix;

Loading…
Cancel
Save