Round state and functionality complete.

master
Ben Burlingham 9 years ago
parent 7506974691
commit a1dec26fc5
  1. 7
      index.html
  2. 7
      js/constants.js
  3. 16
      js/diagram.js
  4. 60
      js/main.js
  5. 110
      js/ui.js
  6. 1
      res/diagram.css
  7. 14
      res/rounds.css
  8. 1
      res/sort.css

@ -11,7 +11,7 @@
} }
body { body {
font: 10px sans-serif; font-family: sans-serif;
padding: 20px; padding: 20px;
} }
@ -29,7 +29,6 @@ body {
</style> </style>
<script src="http://d3js.org/d3.v4.0.0-alpha.50.min.js"></script> <script src="http://d3js.org/d3.v4.0.0-alpha.50.min.js"></script>
<script src="http://d3js.org/d3-chord.v0.0.min.js"></script> <script src="http://d3js.org/d3-chord.v0.0.min.js"></script>
<script src='js/constants.js'></script>
<script src='js/matrices.js'></script> <script src='js/matrices.js'></script>
<script src='js/diagram.js'></script> <script src='js/diagram.js'></script>
<script src='js/ui.js'></script> <script src='js/ui.js'></script>
@ -72,17 +71,19 @@ body {
https://openfootball.github.io/questions.html https://openfootball.github.io/questions.html
<h5>TODO</h5> <h5>TODO</h5>
fix setState to not remove everything
1974 two germanies?
embiggen current event flag embiggen current event flag
move styling out of index.html move styling out of index.html
move fetch into main move fetch into main
add sort metric below team name add sort metric below team name
hide rounds hide rounds
round persistence round persistence
sort persistence
better layout better layout
better colors better colors
webpack 2 / css modules? webpack 2 / css modules?
add three.js sketchup clone to a list somewhere add three.js sketchup clone to a list somewhere
separate three.js swell map below post or something
tweet it! tweet it!
</div> </div>
</body> </body>

@ -1,7 +0,0 @@
const CONSTANTS = {
SORT_TYPES: {
GOALS: 'goals',
COUNTRY: 'country',
POPULATION: 'population',
},
};

@ -197,9 +197,19 @@ const Diagram = {
.data(function(chords) { return chords; }) .data(function(chords) { return chords; })
.enter().append("path") .enter().append("path")
.attr("d", ribbon) .attr("d", ribbon)
.style("fill", function(d) { return color(d.target.index); }) .attr("data-round-id", (d) => {
.style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); }) const t1 = data.tourneys[eventKey].teams[d.source.index];
.attr("class", "ribbon") 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") .append("title")
.text(function(d) { .text(function(d) {
const t1 = data.tourneys[eventKey].teams[d.source.index]; const t1 = data.tourneys[eventKey].teams[d.source.index];

@ -10,6 +10,21 @@ const fetch = (url) => new Promise((resolve, reject) => {
}); });
const main = { const main = {
SORT_TYPES: {
GOALS: 'goals',
COUNTRY: 'country',
POPULATION: 'population',
},
ROUND_TYPES: {
PRELIM: 'prelims',
ROUNDOF16: 'round-of-16',
QUARTERFINAL: 'quarterfinals',
SEMIFINAL: 'semifinals',
CONSOLATION: 'consolation',
FINAL: 'finals',
},
changeEvent: (e) => { changeEvent: (e) => {
const target = UI.findRoot(e.target); const target = UI.findRoot(e.target);
main.setState({ eventKey: target.getAttribute(UI.DATA.EVENT) }); main.setState({ eventKey: target.getAttribute(UI.DATA.EVENT) });
@ -17,9 +32,17 @@ const main = {
}, },
changeRound: (e) => { changeRound: (e) => {
const state = main.getState();
const target = UI.findRoot(e.target); const target = UI.findRoot(e.target);
main.setState({ round: target.getAttribute(UI.DATA.ROUND) }); const rounds = state.rounds ? state.rounds.split(',') : [];
main.updateUI(); const r = target.getAttribute(UI.DATA.ROUND)
const i = rounds.indexOf(r);
(i === -1) ? rounds.push(r) : rounds.splice(i, 1);
UI.toggleRoundRibbons(rounds, main.ROUND_TYPES, main.json.rounds);
UI.toggleRoundItem(target);
main.setState({ rounds });
}, },
changeSort: (e) => { changeSort: (e) => {
@ -29,34 +52,40 @@ const main = {
}, },
getRounds: (eventKey) => { getRounds: (eventKey) => {
const reducer = (acc, v) => (acc.indexOf(v.rId) === -1 ? acc.concat(v.rId) : acc); const rounds = {};
const roundIds = main.json.tourneys[eventKey].games.reduce(reducer, []);
return roundIds.map(v => ({ main.json.tourneys[eventKey].games.forEach(game => {
roundId: v, const name = UI.getRoundName(main.json.rounds[game.rId]);
roundName: UI.getRoundName(main.json.rounds[v]), if (rounds[name] === undefined) {
}) rounds[name] = [];
); }
rounds[name].push({
id: game.rId,
name: name,
});
});
return rounds;
}, },
generateUI: () => { generateUI: () => {
const state = main.getState(); const state = main.getState();
UI.buildEventsPane(main.changeEvent); UI.buildEventsPane(main.changeEvent);
UI.buildSortPane(main.changeSort, CONSTANTS.SORT_TYPES); UI.buildSortPane(main.changeSort, main.SORT_TYPES);
UI.buildRoundsPane(main.changeRound); UI.buildRoundsPane(main.changeRound, main.ROUND_TYPES);
}, },
updateUI: () => { updateUI: () => {
const state = main.getState(); const state = main.getState();
const rounds = main.getRounds(state.eventKey);
UI.updateEventsPane(state.eventKey); UI.updateEventsPane(state.eventKey);
// UI.updateRoundsPane(rounds);
UI.updateSortPane(state.sort); UI.updateSortPane(state.sort);
const matrix = Matrices.buildMatrix(main.json, state.eventKey); const matrix = Matrices.buildMatrix(main.json, state.eventKey);
Diagram.clear(); Diagram.clear();
Diagram.build(main.json, state.eventKey, state.sort, CONSTANTS.SORT_TYPES, matrix); Diagram.build(main.json, state.eventKey, state.sort, main.SORT_TYPES, matrix);
}, },
initJSON: (strData) => { initJSON: (strData) => {
@ -89,6 +118,7 @@ const main = {
} }
if (state.rounds === undefined) { if (state.rounds === undefined) {
state.rounds = Object.values(main.ROUND_TYPES);
} }
main.setState(state); main.setState(state);
@ -99,7 +129,7 @@ const main = {
const url = window.location.href.split('?')[0]; const url = window.location.href.split('?')[0];
const eventKey = next.eventKey || prev.eventKey; const eventKey = next.eventKey || prev.eventKey;
const rounds = next.rounds || prev.rounds || null; const rounds = next.rounds || prev.rounds;
const sort = next.sort || prev.sort || null; const sort = next.sort || prev.sort || null;
history.pushState(null, null, `${url}?eventKey=${eventKey}&sort=${sort}&rounds=${rounds}`); history.pushState(null, null, `${url}?eventKey=${eventKey}&sort=${sort}&rounds=${rounds}`);

@ -11,6 +11,12 @@ const UI = {
ITEM: 'sort-item', ITEM: 'sort-item',
TEXT: 'sort-text', TEXT: 'sort-text',
}, },
ROUND: {
ITEM: 'round-item',
HIDE: 'round-hide',
TEXT: 'round-text',
},
}, },
DATA: { DATA: {
@ -20,6 +26,11 @@ const UI = {
SORT: 'data-sort-key', SORT: 'data-sort-key',
}, },
I18N: {
HIDE: 'hide',
SHOW: 'show',
},
findRoot: (node) => { findRoot: (node) => {
while (node !== document.body && node.getAttribute(UI.DATA.ROOT) === null) { while (node !== document.body && node.getAttribute(UI.DATA.ROOT) === null) {
node = node.parentNode; node = node.parentNode;
@ -36,6 +47,23 @@ const UI = {
}); });
}, },
toggleRoundItem: (target) => {
const hide = target.querySelector(`.${UI.CLASSNAMES.ROUND.HIDE}`);
hide.innerHTML = (hide.innerHTML === UI.I18N.HIDE ? UI.I18N.SHOW : UI.I18N.HIDE);
},
toggleRoundRibbons: (roundsToShow, ROUND_TYPES, allRounds) => {
const ribbons = document.querySelectorAll('.ribbon');
ribbons.forEach(ribbon => {
const name = allRounds[ribbon.getAttribute("data-round-id")];
const type = UI.getRoundType(name, ROUND_TYPES);
roundsToShow.indexOf(type) === -1
? ribbon.style.display = 'none'
: ribbon.style.display = 'inline';
});
},
updateEventsPane: (eventKey) => { updateEventsPane: (eventKey) => {
const eventItems = document.querySelectorAll(`.${UI.CLASSNAMES.EVENT.ITEM}`); const eventItems = document.querySelectorAll(`.${UI.CLASSNAMES.EVENT.ITEM}`);
UI.clearActive(eventItems); UI.clearActive(eventItems);
@ -140,7 +168,6 @@ const UI = {
item.addEventListener('click', onClick); item.addEventListener('click', onClick);
item.setAttribute(UI.DATA.SORT, sort.value); item.setAttribute(UI.DATA.SORT, sort.value);
item.setAttribute(UI.DATA.ROOT, true); item.setAttribute(UI.DATA.ROOT, true);
item.addEventListener('click', onClick);
text.className = UI.CLASSNAMES.SORT.TEXT; text.className = UI.CLASSNAMES.SORT.TEXT;
text.innerHTML = sort.text; text.innerHTML = sort.text;
@ -150,33 +177,44 @@ const UI = {
}); });
}, },
buildRoundsPane: (onClick) => { buildRoundsPane: (onClick, ROUND_TYPES) => {
// const roundsDiv = document.querySelector('.rounds'); const roundsList = [
// { text: 'Preliminaries', value: ROUND_TYPES.PRELIM },
// while (roundsDiv.hasChildNodes()) { { text: 'Round of 16', value: ROUND_TYPES.ROUNDOF16 },
// roundsDiv.firstChild.remove(); { text: 'Quarterfinals', value: ROUND_TYPES.QUARTERFINAL },
// } { text: 'Semifinals', value: ROUND_TYPES.SEMIFINAL },
// { text: 'Consolation', value: ROUND_TYPES.CONSOLATION },
// rounds.forEach(round => { { text: 'Final', value: ROUND_TYPES.FINAL },
// const item = document.createElement('div'); ];
// item.className = 'round-item';
// item.setAttribute('data-round-id', round.roundId); const roundsDiv = document.querySelector('.rounds');
//
// const hide = document.createElement('div'); while (roundsDiv.hasChildNodes()) {
// hide.className = 'round-hide'; roundsDiv.firstChild.remove();
// hide.innerHTML = 'hide'; }
//
// const text = document.createElement('div'); roundsList.forEach(round => {
// text.className = 'round-text'; const item = document.createElement('div');
// text.innerHTML = round.roundName; item.className = UI.CLASSNAMES.ROUND.ITEM;
// item.addEventListener('click', onClick);
// item.appendChild(text); item.setAttribute(UI.DATA.ROUND, round.value);
// item.appendChild(hide); item.setAttribute(UI.DATA.ROOT, true);
// roundsDiv.appendChild(item);
// }); const hide = document.createElement('div');
hide.className = UI.CLASSNAMES.ROUND.HIDE;
hide.innerHTML = 'hide';
const text = document.createElement('div');
text.className = UI.CLASSNAMES.ROUND.TEXT;
text.innerHTML = round.text;
item.appendChild(text);
item.appendChild(hide);
roundsDiv.appendChild(item);
});
}, },
getRoundName: (name) => { getRoundType: (name, ROUND_TYPES) => {
const name2 = name.match(/^Matchday/) ? 'First round' : name; const name2 = name.match(/^Matchday/) ? 'First round' : name;
switch (name2) { switch (name2) {
@ -187,27 +225,25 @@ const UI = {
case 'Group-2 Play-off': case 'Group-2 Play-off':
case 'Group-3 Play-off': case 'Group-3 Play-off':
case 'Group-4 Play-off': case 'Group-4 Play-off':
return "Preliminaries"; return ROUND_TYPES.PRELIM;
case 'Round of 16': case 'Round of 16':
return "Round of 16"; return ROUND_TYPES.ROUNDOF16;
case 'Quarter-finals':
case 'Quarter-finals replays':
return "Quarter Finals";
case 'Semi-finals':
return "Semi Finals";
case 'Third place match': case 'Third place match':
case 'Third-place match': case 'Third-place match':
case 'Match for third place': case 'Match for third place':
case 'Third place play-off': case 'Third place play-off':
case 'Third-place play-off': case 'Third-place play-off':
return "Third Place Match"; return ROUND_TYPES.CONSOLATION;
case 'Quarterfinals': case 'Quarterfinals':
return "Quarterfinals"; case 'Quarter-finals':
case 'Quarter-finals replays':
return ROUND_TYPES.QUARTERFINAL;
case 'Semifinals': case 'Semifinals':
return "Semifinals"; case 'Semi-finals':
return ROUND_TYPES.SEMIFINAL;
case 'Final': case 'Final':
case 'Finals': case 'Finals':
return "Final"; return ROUND_TYPES.FINAL;
} }
console.error(`Unknown round name: ${name}`); console.error(`Unknown round name: ${name}`);

@ -1,4 +1,5 @@
.diagram { .diagram {
font-size: 10px;
height: 700px; height: 700px;
left: 200px; left: 200px;
position: absolute; position: absolute;

@ -1,7 +1,6 @@
.rounds { .rounds {
bottom: 0; bottom: 0;
color: #000; color: #000;
height: 500px;
position: absolute; position: absolute;
right: 0; right: 0;
text-align: right; text-align: right;
@ -10,10 +9,23 @@
} }
.round-item { .round-item {
cursor: pointer;
font-size: 13px;
line-height: 34px;
padding: 0 10px;
}
.round-item:hover {
background: yellow;
} }
.round-hide { .round-hide {
display: inline-block;
font-size: 9px;
margin-left: 20px;
text-transform: uppercase;
} }
.round-text { .round-text {
display: inline-block;
} }

@ -13,6 +13,7 @@
cursor: pointer; cursor: pointer;
font-size: 13px; font-size: 13px;
line-height: 34px; line-height: 34px;
padding: 0 10px;
} }
.sort-item:hover { .sort-item:hover {

Loading…
Cancel
Save