fix bracket

shop
Razmig Sarkissian 8 months ago
parent 067e5351fa
commit 60dd2ca335
  1. 6
      tournaments/models/match.py
  2. 7
      tournaments/models/tournament.py
  3. 1
      tournaments/static/tournaments/css/style.css
  4. 71
      tournaments/templates/tournaments/tournament_bracket.html
  5. 1
      tournaments/urls.py
  6. 55
      tournaments/views.py

@ -430,7 +430,10 @@ class Match(models.Model):
class Team:
def __init__(self, id, image, names, scores, weight, is_winner, walk_out, is_lucky_loser):
# print(f"image = {image}, names= {names}, scores ={scores}, weight={weight}, win={is_winner}")
if id is not None:
self.id = str(id)
else:
self.id = None
self.image = image
self.names = names
self.scores = scores
@ -451,7 +454,8 @@ class Team:
"is_winner": self.is_winner,
"walk_out": self.walk_out,
"is_walk_out": self.is_walk_out(),
"is_lucky_loser": self.is_lucky_loser
"is_lucky_loser": self.is_lucky_loser,
"id": self.id
}
class LiveMatch:

@ -534,7 +534,7 @@ class Tournament(models.Model):
return groups
def create_match_group(self, name, matches):
def create_match_group(self, name, matches, round_id=None):
matches = list(matches)
live_matches = [match.live_match() for match in matches]
# Filter out matches that have a start_date of None
@ -551,7 +551,7 @@ class Tournament(models.Model):
time_format = 'l d M'
formatted_schedule = f" - {formats.date_format(local_start, format=time_format)}"
return MatchGroup(name, live_matches, formatted_schedule)
return MatchGroup(name, live_matches, formatted_schedule, round_id)
def live_group_stages(self):
group_stages = self.get_computed_group_stage()
@ -1330,10 +1330,11 @@ class Tournament(models.Model):
class MatchGroup:
def __init__(self, name, matches, formatted_schedule):
def __init__(self, name, matches, formatted_schedule, round_id=None):
self.name = name
self.matches = matches
self.formatted_schedule = formatted_schedule
self.round_id = round_id
def add_match(self, match):
self.matches.append(match)

@ -818,7 +818,6 @@ h-margin {
text-decoration: none;
color: inherit;
display: block;
padding: 2px 8px;
border-radius: 6px;
}

@ -20,6 +20,7 @@
data-disabled="{{ match.disabled|lower }}"
data-match-group-name="{{ match_group.name }}"
data-match-format="{{ match.format }}"
data-round-id="{{ match_group.round_id }}"
class="match-template">
{% include 'tournaments/bracket_match_cell.html' %}
</div>
@ -29,13 +30,15 @@
</div>
<script>
const tournamentId = "{{ tournament.id }}";
function renderBracket() {
const bracket = document.getElementById('bracket');
const matchTemplates = document.getElementById('match-templates').children;
const rounds = [];
const matchPositions = [];
const doubleButterflyMode = {{ double_butterfly_mode|lower }};
const displayLoserFinal = {{ display_loser_final|lower }};
// Group matches by round
Array.from(matchTemplates).forEach(template => {
@ -56,7 +59,10 @@ function renderBracket() {
const baseDistance = matchHeight + matchSpacing;
bracket.innerHTML = '';
const roundCount = rounds.length;
const finalRoundIndex = (roundCount - 1) / 2;
let finalRoundIndex = (roundCount - 1);
if (doubleButterflyMode == true) {
finalRoundIndex = finalRoundIndex / 2;
}
let nextMatchDistance = baseDistance;
let minimumMatchDistance = 1;
@ -77,10 +83,22 @@ function renderBracket() {
const firstMatchTemplate = roundMatches[0].closest('.match-template');
const matchGroupName = firstMatchTemplate.dataset.matchGroupName;
const matchFormat = firstMatchTemplate.dataset.matchFormat;
const roundId = firstMatchTemplate.dataset.roundId; // Add this line
const nameSpan = document.createElement('div');
let nameSpan = document.createElement('div');
nameSpan.className = 'round-name';
nameSpan.textContent = matchGroupName;
if (roundIndex == finalRoundIndex) {
} else {
nameSpan = document.createElement('a');
nameSpan.className = 'round-name btn small-button';
nameSpan.textContent = matchGroupName;
if (roundId) {
nameSpan.href = `/tournament/${tournamentId}/round/${roundId}/bracket/`;
nameSpan.style.cursor = 'pointer';
}
nameSpan.style.textDecoration = 'None';
}
const formatSpan = document.createElement('div');
formatSpan.className = 'round-format';
@ -92,8 +110,8 @@ function renderBracket() {
// Create matches container
const matchesContainer = document.createElement('div');
matchesContainer.className = 'matches-container';
if (roundCount > 5 && doubleButterflyMode == true) {
if (roundIndex >= finalRoundIndex - 1) {
if (roundCount > 5) {
matchesContainer.style.transform = `translateX(-50%)`;
if (roundIndex >= finalRoundIndex + 2) {
matchesContainer.style.transform = `translateX(-100%)`;
@ -119,27 +137,51 @@ function renderBracket() {
}
if (roundIndex === 0) {
if (roundCount > 1) {
const nextMatchesCount = rounds[roundIndex + 1].length;
if (currentMatchesCount == nextMatchesCount) {
nextMatchDistance = 0;
}
} else {
nextMatchDistance = 0;
}
top = matchIndex * (matchHeight + matchSpacing) * minimumMatchDistance;
} else if (roundIndex === roundCount - 1) {
if (roundCount == 3 && doubleButterflyMode) {
top = top + (matchHeight + matchSpacing) / 2
}
} else if (roundIndex === roundCount - 1 && doubleButterflyMode == true) {
const nextMatchesCount = rounds[roundIndex - 1].length;
if (currentMatchesCount == nextMatchesCount) {
nextMatchDistance = 0;
}
} else if (roundIndex == finalRoundIndex) {
if (doubleButterflyMode == true) {
let lgth = matchPositions[0].length / 2;
let index = lgth + matchIndex - 1;
// If index goes negative, use 0 instead
if (displayLoserFinal == true) {
if (matchIndex == 0) {
top = matchPositions[roundIndex - 1][0] - baseDistance / 2;
} else {
top = matchPositions[roundIndex - 1][0] + baseDistance / 2;
}
nextMatchDistance = baseDistance;
} else {
top = matchPositions[roundIndex - 1][0];
nextMatchDistance = 0;
}
} else {
const parentIndex1 = matchIndex * 2;
const parentIndex2 = parentIndex1 + 1;
const parentPos1 = matchPositions[roundIndex - 1][parentIndex1];
const parentPos2 = matchPositions[roundIndex - 1][parentIndex2];
top = (parentPos1 + parentPos2) / 2;
nextMatchDistance = 0;
}
} else if (roundIndex < finalRoundIndex) {
const previousMatchesCount = rounds[roundIndex - 1].length;
const nextMatchesCount = rounds[roundIndex + 1].length;
@ -172,8 +214,8 @@ function renderBracket() {
}
}
if (roundCount > 5 && doubleButterflyMode == true) {
if (roundIndex >= finalRoundIndex - 2) {
if (roundCount > 5) {
if (roundIndex == finalRoundIndex - 1) {
matchDiv.classList.add('inward');
}
@ -184,12 +226,13 @@ function renderBracket() {
nextMatchDistance = nextMatchDistance - baseDistance;
}
}
}
if (roundIndex == finalRoundIndex - 1 || roundIndex == finalRoundIndex + 1) {
if (displayLoserFinal == true) {
if (doubleButterflyMode == true && (roundIndex == finalRoundIndex - 1 || roundIndex == finalRoundIndex + 1)) {
nextMatchDistance = baseDistance;
}
}
matchDiv.style.setProperty('--next-match-distance', `${nextMatchDistance}px`);
matchDiv.style.top = `${top}px`;
@ -212,12 +255,13 @@ function renderBracket() {
// Position title above the first match
titleDiv.style.top = `${top - 80}px`; // Adjust the 60px offset as needed
titleDiv.style.position = 'absolute';
if (roundCount >= 5 && doubleButterflyMode == true) {
if (roundIndex == finalRoundIndex - 1) {
titleDiv.style.marginLeft = '50px';
} else if (roundIndex == finalRoundIndex + 1) {
titleDiv.style.marginLeft = '-50px';
}
}
matchesContainer.appendChild(titleDiv);
}
@ -226,7 +270,7 @@ function renderBracket() {
<div class="match-content ${isDisabled ? 'disabled' : ''}">${matchTemplate.innerHTML}</div>
`;
if (roundIndex == finalRoundIndex - 1) {
if (roundIndex == finalRoundIndex - 1 && displayLoserFinal == true) {
const matchDiv2 = document.createElement('div');
matchDiv2.className = 'butterfly-match';
matchDiv2.classList.add('inward');
@ -295,8 +339,13 @@ function renderBracket() {
}
.round-name {
font-size: 1.5em; /* Make the round name bigger */
font-size: 1.5em;
margin-bottom: 5px;
transition: color 0.2s;
}
.round-name a:hover {
color: orange;
}
.round-format {

@ -18,6 +18,7 @@ urlpatterns = [
path('teams/', views.tournament_teams, name='tournament-teams'),
path('info/', views.tournament_info, name='tournament-info'),
path('bracket/', views.tournament_bracket, name='tournament-bracket'),
path('round/<str:round_id>/bracket/', views.round_bracket, name='round-bracket'),
path('prog/', views.tournament_prog, name='tournament-prog'),
path('summons/', views.tournament_summons, name='tournament-summons'),
path('broadcast/summons/', views.tournament_broadcasted_summons, name='broadcasted-summons'),

@ -960,18 +960,39 @@ def tournament_bracket(request, tournament_id):
View to display tournament bracket structure.
"""
tournament = get_object_or_404(Tournament, pk=tournament_id)
context = get_bracket(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=False)
return render(request, 'tournaments/tournament_bracket.html', context)
def round_bracket(request, tournament_id, round_id):
"""
View to display round bracket structure.
"""
tournament = get_object_or_404(Tournament, pk=tournament_id)
round = get_object_or_404(Round, pk=round_id)
context = get_bracket(tournament, round, double_butterfly_mode=False, display_loser_final=False)
return render(request, 'tournaments/tournament_bracket.html', context)
def get_bracket(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=False):
loser_final = None
main_rounds_reversed = []
if parent_round:
double_butterfly_mode = False
display_loser_final = False
# Get main bracket rounds (excluding children/ranking matches)
main_rounds = tournament.round_set.filter(
parent=None,
parent=parent_round,
group_stage_loser_bracket=False
).order_by('-index')
if double_butterfly_mode:
main_rounds_reversed = tournament.round_set.filter(
parent=None,
parent=parent_round,
group_stage_loser_bracket=False
).order_by('index') # Removed the minus sign before 'index'
).order_by('index')
loser_final = None
if display_loser_final:
if len(main_rounds_reversed) >= 1:
semi = main_rounds_reversed[1]
loser_round = tournament.round_set.filter(
@ -989,7 +1010,7 @@ def tournament_bracket(request, tournament_id):
matches = round.match_set.filter(disabled=False).order_by('index')
if matches:
if len(matches) > 1:
if len(matches) > 1 and double_butterfly_mode:
midpoint = int(len(matches) / 2)
first_half_matches = matches[:midpoint]
else:
@ -1001,31 +1022,41 @@ def tournament_bracket(request, tournament_id):
if first_half_matches:
name = round.name()
if parent_round:
name = first_half_matches[0].computed_name()
match_group = tournament.create_match_group(
name=round.name(),
matches=first_half_matches
name=name,
matches=first_half_matches,
round_id=round.id
)
serializable_match_groups.append(match_group)
if double_butterfly_mode:
for round in main_rounds_reversed:
matches = round.match_set.filter(disabled=False).order_by('index')
if matches:
if len(matches) > 1:
midpoint = int(len(matches) / 2)
first_half_matches = matches[midpoint:]
name = round.name()
if parent_round:
name = first_half_matches[0].computed_name()
match_group = tournament.create_match_group(
name=round.name(),
matches=first_half_matches
name=name,
matches=first_half_matches,
round_id=round.id
)
serializable_match_groups.append(match_group)
context = {
'tournament': tournament,
'match_groups': serializable_match_groups
'match_groups': serializable_match_groups,
'double_butterfly_mode': double_butterfly_mode,
'display_loser_final': display_loser_final
}
return render(request, 'tournaments/tournament_bracket.html', context)
return context
def tournament_prog(request, tournament_id):
tournament = get_object_or_404(Tournament, id=tournament_id)

Loading…
Cancel
Save