diff --git a/index.html b/index.html
index 3244155..c0c8d51 100644
--- a/index.html
+++ b/index.html
@@ -59,9 +59,9 @@
1934: Patched.
Italy Spain replay 1-0!
1938:
- Switzerland Germany replay 4-2
- Cuba Romania replay 3-2
- Brazil Czech replay 2-1
+ Switzerland Germany 1-1 replay 4-2
+ Cuba Romania 3-3 replay 3-2
+ Brazil Czech 1-1 replay 2-1
1950: OK
1954:
Germany Turkey playoff 7-2
@@ -82,7 +82,13 @@
1986:
1990:
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
diff --git a/js/bundle.js b/js/bundle.js
index 4d11526..0282a68 100644
--- a/js/bundle.js
+++ b/js/bundle.js
@@ -58,13 +58,12 @@
var _ui2 = _interopRequireDefault(_ui);
- var _hotfixes = __webpack_require__(13);
+ var _hotfixes = __webpack_require__(5);
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);
@@ -72,6 +71,7 @@
__webpack_require__(10);
__webpack_require__(11);
__webpack_require__(12);
+ __webpack_require__(13);
var main = {
changeEvent: function changeEvent(e) {
@@ -105,22 +105,46 @@
main.updateUI();
},
- getRounds: function getRounds(eventKey) {
- var rounds = {};
+ // 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 = {};
main.json.tourneys[eventKey].games.forEach(function (game) {
- var name = _ui2.default.getRoundName(main.json.rounds[game.rId]);
- if (rounds[name] === undefined) {
- rounds[name] = [];
+ var teams = [game.t1, game.t2].sort();
+ var addr = teams[0] + '-' + teams[1];
+
+ if (games[addr] === undefined) {
+ games[addr] = [];
}
- rounds[name].push({
- id: game.rId,
- name: name
- });
+ games[addr].push(game);
});
- return rounds;
+ return Object.keys(games).reduce(function (acc, k) {
+ if (games[k].length > 1) {
+ acc.push(games[k]);
+ }
+
+ return acc;
+ }, []);
},
generateUI: function generateUI() {
@@ -135,10 +159,124 @@
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;
+
+ // 127/110 Germany 153/137 Switzerland
+ // if (`${d.source.index},${d.source.subindex}` === "14,10" &&
+ // `${d.target.index},${d.target.subindex}` === "5,2") {
+ // // source has to split into 1/5, 4/5
+ //
+ // const sourceAngle = d.source.endAngle - d.source.startAngle;
+ // const targetAngle = d.target.endAngle - d.target.startAngle;
+ //
+ // const sourceNew = Object.assign({}, d.source);
+ // sourceNew.startAngle = d.source.startAngle + sourceAngle * (1/5);
+ // d.source.endAngle = d.source.startAngle + sourceAngle * (1/5);
+ //
+ // const targetNew = Object.assign({}, d.target);
+ // targetNew.endAngle = d.target.startAngle + targetAngle * (2/3);
+ // d.target.startAngle = d.target.startAngle + targetAngle * (2/3);
+ //
+ // chords.push({ source: sourceNew, target: targetNew });
+ // }
+ }, []);
+
+ chords.groups = tmp.groups;
+ //
+ // console.warn(test)
- var matrix = _matrices2.default.buildMatrix(main.json, state.eventKey);
_diagram2.default.clear();
- _diagram2.default.build(main.json, state.eventKey, state.sort, state.scheme, _ui2.default.SORT_TYPES, matrix);
+
+ 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 });
_ui2.default.updateTourneyPane(state.eventKey);
_ui2.default.updateEventsPane(state.eventKey);
@@ -267,8 +405,8 @@
s2 += g.s2;
}
- matrix[i1][i2] = g.s1 + g.se1 + g.sp1;
- matrix[i2][i1] = g.s2 + g.se2 + g.sp2;
+ matrix[i1][i2] = s1;
+ matrix[i2][i1] = s2;
}, []);
return matrix;
@@ -295,6 +433,8 @@
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);
@@ -422,82 +562,81 @@
return team.ga;
},
- 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;
+ buildChords: function buildChords(_ref) {
+ var matrix = _ref.matrix,
+ data = _ref.data,
+ eventKey = _ref.eventKey,
+ sort = _ref.sort,
+ SORT_TYPES = _ref.SORT_TYPES;
var chords = d3.chord().padAngle(0.05).call(null, matrix);
- var sortedChords = chords;
switch (sort) {
case SORT_TYPES.COUNTRY:
- sortedChords = _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getCountryName.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
- break;
+ return _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getCountryName.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
case SORT_TYPES.GOALS:
- sortedChords = _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getGoalsFor.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
- break;
+ return _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getGoalsFor.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
case SORT_TYPES.POPULATION:
- sortedChords = _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getPopulation.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
- break;
+ return _sorter2.default.sort(chords, 0, chords.groups.length - 1, Diagram.getPopulation.bind(null, data, eventKey), Diagram.swapGroups.bind(null, data, eventKey));
}
- var arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
+ return chords;
+ },
- var ribbon = d3.ribbon().radius(innerRadius);
+ 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 len = data.tourneys[eventKey].teams.length;
- var color = d3.scaleOrdinal(d3.schemeCategory20);
+ return { svgW: svgW, svgH: svgH, arcT: arcT, outerR: outerR, innerR: innerR };
+ },
- (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"];
- color = function color(i) {
- return 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;
- }
- })();
+ buildColorScheme: function buildColorScheme(_ref2) {
+ var scheme = _ref2.scheme,
+ len = _ref2.len;
- var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")").datum(sortedChords);
+ if (scheme === 1) {
+ return d3.scaleLinear().domain([0, len]).range(["#fff", "green"]).interpolate(d3.interpolateRgb);
+ } else if (scheme === 2) {
+ var _ret = function () {
+ var colors = ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"];
- var group = g.append("g").attr("class", "groups").selectAll("g").data(function (chords) {
- return chords.groups;
- }).enter().append("g");
+ return {
+ v: function v(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);
+ }
- 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 d3.scaleOrdinal(d3.schemeCategory20);
+ },
- 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) {
- var t1 = data.tourneys[eventKey].teams[d.source.index];
- var t2 = data.tourneys[eventKey].teams[d.target.index];
+ buildRibbons: function buildRibbons(_ref3) {
+ var container = _ref3.container,
+ color = _ref3.color,
+ chords = _ref3.chords,
+ data = _ref3.data,
+ eventKey = _ref3.eventKey;
- 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 dimensions = Diagram.buildDimensions();
+ var ribbon = d3.ribbon().radius(dimensions.innerR);
- return game.rId;
- }).style("fill", function (d) {
+ container.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) {
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];
@@ -506,60 +645,76 @@
var c1 = data.countries[t1.cId];
var c2 = data.countries[t2.cId];
- 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;
+ 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;
- 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;
+ 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;
s1 += " (Penalties)";
s2 += " (Penalties)";
- } 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;
+ } 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;
s1 += " (Extended time)";
s2 += " (Extended time)";
}
- // 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)` : '';
+ // console.warn(t1.tId, c1, t2.tId, c2, s1, s2)
- return c1 + ': ' + s1 + '\n' + c2 + ': ' + s2 + '\n' + data.rounds[game.rId];
+ return c1 + ': ' + s1 + '\n' + c2 + ': ' + s2 + '\n' + data.rounds[d.game.rId] + '\n \nsource (i,j) val: (' + d.source.index + ', ' + d.source.subindex + ') ' + d.source.value + '\n \ntarget (i,j) val: (' + d.target.index + ', ' + d.target.subindex + ') ' + d.target.value;
});
+ },
+
+ 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");
+
+ 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);
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(" + (innerRadius + 26) + ")" + (d.angle > Math.PI ? "rotate(180)" : "");
+ return "rotate(" + (d.angle * 180 / Math.PI - 91) + ")" + "translate(" + (dimensions.innerR + 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 + ')';
- break;
- // case SORT_TYPES.POPULATION:
- // metric = `(${Number(team.p).toLocaleString()})`;
- // break;
- }
+ // switch (sort) {
+ // case SORT_TYPES.GOALS:
+ // metric = `(${team.gf})`;
+ // 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);
}
};
@@ -1000,54 +1155,6 @@
/***/ },
/* 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";
@@ -1122,5 +1229,53 @@
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
+
/***/ }
/******/ ]);
\ No newline at end of file
diff --git a/js/diagram.js b/js/diagram.js
index 2e73963..0925343 100644
--- a/js/diagram.js
+++ b/js/diagram.js
@@ -120,68 +120,126 @@ const Diagram = {
return team.ga;
},
- 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;
-
+ buildChords: ({ matrix, data, eventKey, sort, SORT_TYPES }) => {
const chords = d3.chord()
.padAngle(0.05)
.call(null, matrix);
- let sortedChords = chords;
switch (sort) {
case SORT_TYPES.COUNTRY:
- sortedChords = Sorter.sort(chords, 0, chords.groups.length - 1,
- Diagram.getCountryName.bind(null, data, eventKey),
- Diagram.swapGroups.bind(null, data, eventKey));
- break;
+ return Sorter.sort(chords, 0, chords.groups.length - 1,
+ Diagram.getCountryName.bind(null, data, eventKey),
+ Diagram.swapGroups.bind(null, data, eventKey));
case SORT_TYPES.GOALS:
- sortedChords = Sorter.sort(chords, 0, chords.groups.length - 1,
- Diagram.getGoalsFor.bind(null, data, eventKey),
- Diagram.swapGroups.bind(null, data, eventKey));
- break;
+ return Sorter.sort(chords, 0, chords.groups.length - 1,
+ Diagram.getGoalsFor.bind(null, data, eventKey),
+ Diagram.swapGroups.bind(null, data, eventKey));
case SORT_TYPES.POPULATION:
- sortedChords = Sorter.sort(chords, 0, chords.groups.length - 1,
- Diagram.getPopulation.bind(null, data, eventKey),
- Diagram.swapGroups.bind(null, data, eventKey));
- break;
+ return Sorter.sort(chords, 0, chords.groups.length - 1,
+ Diagram.getPopulation.bind(null, data, eventKey),
+ Diagram.swapGroups.bind(null, data, eventKey));
}
- 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 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 g = svg.append("g")
- .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
- .datum(sortedChords);
+ return d3.scaleOrdinal(d3.schemeCategory20);
+ },
- const group = g.append("g")
+ buildRibbons: ({ container, color, chords, data, eventKey }) => {
+ const dimensions = Diagram.buildDimensions();
+ const ribbon = d3.ribbon().radius(dimensions.innerR);
+
+ container.append("g")
+ .attr("class", "ribbons")
+ .selectAll("path")
+ .data(chords => 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())
+ .classed("ribbon", true)
+ .append("title")
+ .text(function(d) {
+ const t1 = data.tourneys[eventKey].teams[d.source.index];
+ const t2 = data.tourneys[eventKey].teams[d.target.index];
+
+ 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;
+
+ 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;
+
+ 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;
+
+ s1 += " (Extended time)";
+ s2 += " (Extended time)";
+ }
+
+ // console.warn(t1.tId, c1, t2.tId, c2, s1, s2)
+
+ return `${c1}: ${s1}\n${c2}: ${s2}\n${data.rounds[d.game.rId]}
+ \nsource (i,j) val: (${d.source.index}, ${d.source.subindex}) ${d.source.value}
+ \ntarget (i,j) val: (${d.target.index}, ${d.target.subindex}) ${d.target.value}`;
+ });
+ },
+
+ buildArcs: ({ container, color, eventKey, data }) => {
+ const dimensions = Diagram.buildDimensions();
+ const arc = d3.arc().innerRadius(dimensions.innerR).outerRadius(dimensions.outerR)
+
+ const group = container.append("g")
.attr("class", "groups")
.selectAll("g")
.data(chords => chords.groups)
@@ -192,73 +250,12 @@ const Diagram = {
.style("stroke", d => d3.rgb(color(d.index)).darker())
.attr("d", arc);
- g.append("g")
- .attr("class", "ribbons")
- .selectAll("path")
- .data(function(chords) { return chords; })
- .enter().append("path")
- .attr("d", ribbon)
- .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) {
- const t1 = data.tourneys[eventKey].teams[d.source.index];
- const t2 = data.tourneys[eventKey].teams[d.target.index];
-
- const c1 = data.countries[t1.cId];
- const c2 = data.countries[t2.cId];
-
- 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 (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 (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)";
- }
-
- // 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)` : '';
-
- 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(" + (innerRadius + 26) + ")"
+ + "translate(" + (dimensions.innerR + 26) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
@@ -266,18 +263,29 @@ const Diagram = {
const team = data.tourneys[eventKey].teams[d.index];
let metric = '';
- switch (sort) {
- case SORT_TYPES.GOALS:
- metric = `(${team.gf})`;
- break;
- // case SORT_TYPES.POPULATION:
- // metric = `(${Number(team.p).toLocaleString()})`;
- // break;
- }
+ // switch (sort) {
+ // case SORT_TYPES.GOALS:
+ // metric = `(${team.gf})`;
+ // 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;
diff --git a/js/index.js b/js/index.js
index 7c547d5..ea8898b 100644
--- a/js/index.js
+++ b/js/index.js
@@ -44,22 +44,46 @@ const main = {
main.updateUI();
},
- getRounds: (eventKey) => {
- const rounds = {};
+ // 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 = {};
main.json.tourneys[eventKey].games.forEach(game => {
- const name = UI.getRoundName(main.json.rounds[game.rId]);
- if (rounds[name] === undefined) {
- rounds[name] = [];
+ const teams = [game.t1, game.t2].sort();
+ const addr = `${teams[0]}-${teams[1]}`;
+
+ if (games[addr] === undefined) {
+ games[addr] = [];
}
- rounds[name].push({
- id: game.rId,
- name: name,
- });
+ games[addr].push(game);
});
- return rounds;
+ return Object.keys(games).reduce((acc, k) => {
+ if (games[k].length > 1) {
+ acc.push(games[k]);
+ }
+
+ return acc;
+ }, []);
},
generateUI: () => {
@@ -74,10 +98,120 @@ 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;
+
+ // 127/110 Germany 153/137 Switzerland
+ // if (`${d.source.index},${d.source.subindex}` === "14,10" &&
+ // `${d.target.index},${d.target.subindex}` === "5,2") {
+ // // source has to split into 1/5, 4/5
+ //
+ // const sourceAngle = d.source.endAngle - d.source.startAngle;
+ // const targetAngle = d.target.endAngle - d.target.startAngle;
+ //
+ // const sourceNew = Object.assign({}, d.source);
+ // sourceNew.startAngle = d.source.startAngle + sourceAngle * (1/5);
+ // d.source.endAngle = d.source.startAngle + sourceAngle * (1/5);
+ //
+ // const targetNew = Object.assign({}, d.target);
+ // targetNew.endAngle = d.target.startAngle + targetAngle * (2/3);
+ // d.target.startAngle = d.target.startAngle + targetAngle * (2/3);
+ //
+ // chords.push({ source: sourceNew, target: targetNew });
+ // }
+ }, []);
+
+ chords.groups = tmp.groups;
+ //
+ // console.warn(test)
- const matrix = Matrices.buildMatrix(main.json, state.eventKey);
Diagram.clear();
- Diagram.build(main.json, state.eventKey, state.sort, state.scheme, UI.SORT_TYPES, matrix);
+
+ 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 });
UI.updateTourneyPane(state.eventKey);
UI.updateEventsPane(state.eventKey);
diff --git a/js/matrices.js b/js/matrices.js
index e1c262e..a08e875 100644
--- a/js/matrices.js
+++ b/js/matrices.js
@@ -36,9 +36,9 @@ const Matrices = {
else {
s2 += g.s2;
}
-
- matrix[i1][i2] = g.s1 + g.se1 + g.sp1;
- matrix[i2][i1] = g.s2 + g.se2 + g.sp2;
+
+ matrix[i1][i2] = s1;
+ matrix[i2][i1] = s2;
}, []);
return matrix;