|
|
|
@ -1,72 +1,10 @@ |
|
|
|
|
const goalsFor = {}; |
|
|
|
|
const goalsAgainst = {}; |
|
|
|
|
|
|
|
|
|
const Diagram = { |
|
|
|
|
clear: () => d3.select('svg').selectAll("*").remove(), |
|
|
|
|
|
|
|
|
|
swap: (i, j) => { |
|
|
|
|
const fst = Object.assign({}, chords.groups[i]); |
|
|
|
|
const snd = Object.assign({}, chords.groups[j]); |
|
|
|
|
|
|
|
|
|
// Calculate and apply offsets for adjacent group arcs.
|
|
|
|
|
deltaFst = snd.endAngle - fst.endAngle; |
|
|
|
|
deltaSnd = snd.startAngle - fst.startAngle |
|
|
|
|
|
|
|
|
|
chords.groups[i].startAngle += deltaFst; |
|
|
|
|
chords.groups[i].endAngle += deltaFst; |
|
|
|
|
|
|
|
|
|
chords.groups[j].startAngle -= deltaSnd; |
|
|
|
|
chords.groups[j].endAngle -= deltaSnd; |
|
|
|
|
|
|
|
|
|
// Apply offsets to relevant chords.
|
|
|
|
|
chords.forEach((v,i) => { |
|
|
|
|
const sourceProps = {}; |
|
|
|
|
const targetProps = {} |
|
|
|
|
|
|
|
|
|
// Adjust source and target arcs for first index.
|
|
|
|
|
if (v.source.index === fst.index) { |
|
|
|
|
sourceProps.index = snd.index; |
|
|
|
|
sourceProps.startAngle = v.source.startAngle + deltaFst; |
|
|
|
|
sourceProps.endAngle = v.source.endAngle + deltaFst; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (v.target.index === fst.index) { |
|
|
|
|
targetProps.index = snd.index; |
|
|
|
|
targetProps.startAngle = v.target.startAngle + deltaFst; |
|
|
|
|
targetProps.endAngle = v.target.endAngle + deltaFst; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (v.source.subindex === fst.index) { |
|
|
|
|
sourceProps.subindex = snd.index; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (v.target.subindex === fst.index) { |
|
|
|
|
targetProps.subindex = snd.index; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Adjust source and target arcs for second index.
|
|
|
|
|
if (v.source.index === snd.index) { |
|
|
|
|
sourceProps.index = fst.index; |
|
|
|
|
sourceProps.startAngle = v.source.startAngle - deltaSnd; |
|
|
|
|
sourceProps.endAngle = v.source.endAngle - deltaSnd; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (v.target.index === snd.index) { |
|
|
|
|
targetProps.index = fst.index; |
|
|
|
|
targetProps.startAngle = v.target.startAngle - deltaSnd; |
|
|
|
|
targetProps.endAngle = v.target.endAngle - deltaSnd; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (v.source.subindex === snd.index) { |
|
|
|
|
sourceProps.subindex = fst.index; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (v.target.subindex === snd.index) { |
|
|
|
|
targetProps.subindex = fst.index; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Object.assign(v.source, sourceProps) |
|
|
|
|
Object.assign(v.target, targetProps) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return chords; |
|
|
|
|
|
|
|
|
|
// // json.tourneys[eventKey].teams.sort()
|
|
|
|
|
//
|
|
|
|
@ -112,7 +50,7 @@ const Diagram = { |
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
swap: (chords, i, j) => { |
|
|
|
|
swapGroupArcs: (chords, i, j) => { |
|
|
|
|
if (i < 0 || j < 0 || i === j) { |
|
|
|
|
return chords; |
|
|
|
|
} |
|
|
|
@ -131,12 +69,12 @@ const Diagram = { |
|
|
|
|
// Bring first forward.
|
|
|
|
|
chords.groups[f].startAngle = snd.endAngle - fstAngle; |
|
|
|
|
chords.groups[f].endAngle = snd.endAngle; |
|
|
|
|
// chords.groups[f].index = snd.index;
|
|
|
|
|
chords.groups[f].index = snd.index; |
|
|
|
|
|
|
|
|
|
// Bring second back.
|
|
|
|
|
chords.groups[s].startAngle = fst.startAngle; |
|
|
|
|
chords.groups[s].endAngle = fst.startAngle + sndAngle; |
|
|
|
|
// chords.groups[s].index = fst.index;
|
|
|
|
|
chords.groups[s].index = fst.index; |
|
|
|
|
|
|
|
|
|
// Bump other groups forward.
|
|
|
|
|
for (let ii = f + 1; ii < s; ii++) { |
|
|
|
@ -152,6 +90,23 @@ const Diagram = { |
|
|
|
|
return chords; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
swapGroups: (data, eventIndex, chords, i, j) => { |
|
|
|
|
Diagram.swapGroupArcs(chords, i, j); |
|
|
|
|
Matrices.swapIndices(data.tourneys[eventIndex].teams, i, j); |
|
|
|
|
return chords; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
getCountryName: (data, eventIndex, n) => { |
|
|
|
|
const countryId = data.teams[data.tourneys[eventIndex].teams[n]]; |
|
|
|
|
return data.countries[countryId].n; |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// getGoalsFor: (data, eventIndex, n) => {
|
|
|
|
|
// data.tourneys[eventIndex].games.reduce(
|
|
|
|
|
//
|
|
|
|
|
// return Math.round(100 * Math.random);
|
|
|
|
|
// },
|
|
|
|
|
|
|
|
|
|
build: (data, eventIndex, metaMatrix, chordMatrix) => { |
|
|
|
|
const svg = d3.select("svg"), |
|
|
|
|
width = +svg.attr("width"), |
|
|
|
@ -160,10 +115,14 @@ const Diagram = { |
|
|
|
|
outerRadius = Math.min(width, height) * 0.5 - 125, |
|
|
|
|
innerRadius = outerRadius - outerArcThickness; |
|
|
|
|
|
|
|
|
|
const chord = d3.chord() |
|
|
|
|
.padAngle(0.05); |
|
|
|
|
const chords = d3.chord() |
|
|
|
|
.padAngle(0.05) |
|
|
|
|
.call(null, chordMatrix); |
|
|
|
|
|
|
|
|
|
const sortedChords = Diagram.sort(chord(chordMatrix)); |
|
|
|
|
const sortedChords = Sorter.sort(chords, 0, chords.groups.length - 1, |
|
|
|
|
Diagram.getCountryName.bind(null, data, eventIndex), |
|
|
|
|
// Diagram.getGoalsFor.bind(null, data, eventIndex),
|
|
|
|
|
Diagram.swapGroups.bind(null, data, eventIndex)); |
|
|
|
|
|
|
|
|
|
const arc = d3.arc() |
|
|
|
|
.innerRadius(innerRadius) |
|
|
|
@ -200,34 +159,34 @@ 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) |
|
|
|
|
.style("fill", function(d) { return color(d.target.index); }) |
|
|
|
|
.style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); }) |
|
|
|
|
.attr("class", "ribbon") |
|
|
|
|
// .append("title")
|
|
|
|
|
// .text(function(d) {
|
|
|
|
|
// const meta1 = metaMatrix[d.target.index][d.source.index];
|
|
|
|
|
// const meta2 = metaMatrix[d.source.index][d.target.index];
|
|
|
|
|
//
|
|
|
|
|
// const g = meta1.game;
|
|
|
|
|
//
|
|
|
|
|
// const t1 = lookup.teams[g.t1];
|
|
|
|
|
// const t2 = lookup.teams[g.t2];
|
|
|
|
|
//
|
|
|
|
|
// const e1 = g.s1e ? `(+${g.s1e} in extended time)` : '';
|
|
|
|
|
// const e2 = g.s2e ? `(+${g.s2e} in extended time)` : '';
|
|
|
|
|
//
|
|
|
|
|
// const p1 = g.s1p ? `(+${g.s1p} in penalties)` : '';
|
|
|
|
|
// const p2 = g.s2p ? `(+${g.s2p} in penalties)` : '';
|
|
|
|
|
//
|
|
|
|
|
// return `${t1}: ${g.s1} ${e1} ${p1}\n${t2}: ${g.s2} ${e2} ${p2}`;
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// g.append("g")
|
|
|
|
|
// .attr("class", "ribbons")
|
|
|
|
|
// .selectAll("path")
|
|
|
|
|
// .data(function(chords) { return chords; })
|
|
|
|
|
// .enter().append("path")
|
|
|
|
|
// .attr("d", ribbon)
|
|
|
|
|
// .style("fill", function(d) { return color(d.target.index); })
|
|
|
|
|
// .style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); })
|
|
|
|
|
// .attr("class", "ribbon")
|
|
|
|
|
// // .append("title")
|
|
|
|
|
// // .text(function(d) {
|
|
|
|
|
// // const meta1 = metaMatrix[d.target.index][d.source.index];
|
|
|
|
|
// // const meta2 = metaMatrix[d.source.index][d.target.index];
|
|
|
|
|
// //
|
|
|
|
|
// // const g = meta1.game;
|
|
|
|
|
// //
|
|
|
|
|
// // const t1 = lookup.teams[g.t1];
|
|
|
|
|
// // const t2 = lookup.teams[g.t2];
|
|
|
|
|
// //
|
|
|
|
|
// // const e1 = g.s1e ? `(+${g.s1e} in extended time)` : '';
|
|
|
|
|
// // const e2 = g.s2e ? `(+${g.s2e} in extended time)` : '';
|
|
|
|
|
// //
|
|
|
|
|
// // const p1 = g.s1p ? `(+${g.s1p} in penalties)` : '';
|
|
|
|
|
// // const p2 = g.s2p ? `(+${g.s2p} in penalties)` : '';
|
|
|
|
|
// //
|
|
|
|
|
// // return `${t1}: ${g.s1} ${e1} ${p1}\n${t2}: ${g.s2} ${e2} ${p2}`;
|
|
|
|
|
// // });
|
|
|
|
|
//
|
|
|
|
|
group.append("text") |
|
|
|
|
.each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; }) |
|
|
|
|
.attr("dy", ".35em") |
|
|
|
|