You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
padelclub_backend/tournaments/static/tournaments/js/tournament_bracket.js

426 lines
16 KiB

function renderBracket(options) {
const bracket = document.getElementById("bracket");
const matchTemplates = document.getElementById("match-templates").children;
const rounds = [];
const matchPositions = [];
const matchDisabled = [];
const doubleButterflyMode = options.doubleButterflyMode;
const displayLoserFinal = options.displayLoserFinal;
const tournamentId = options.tournamentId;
const isBroadcast = options.isBroadcast;
// Group matches by round
Array.from(matchTemplates).forEach((template) => {
const roundIndex = parseInt(template.dataset.matchRound);
if (!rounds[roundIndex]) {
rounds[roundIndex] = [];
}
rounds[roundIndex].push(template);
});
// First create a test match to get natural height
const firstMatch = document.createElement("div");
firstMatch.className = "butterfly-match";
firstMatch.innerHTML = `<div class="match-content">${rounds[0][0].innerHTML}</div>`;
bracket.appendChild(firstMatch);
const matchHeight = firstMatch.offsetHeight;
const matchSpacing = 10;
const baseDistance = matchHeight + matchSpacing;
bracket.innerHTML = "";
const roundCount = rounds.length;
let finalRoundIndex = roundCount - 1;
if (doubleButterflyMode == true) {
finalRoundIndex = finalRoundIndex / 2;
}
let nextMatchDistance = baseDistance;
let minimumMatchDistance = 1;
const totalRounds = document.querySelectorAll(".butterfly-round").length;
const screenWidth = window.innerWidth;
let roundTotalCount = roundCount;
if (doubleButterflyMode == true && roundCount > 1) {
roundTotalCount = roundCount - 1;
}
const padding = 50 * roundTotalCount; // Account for some padding/margin
const availableWidth = screenWidth - padding;
responsiveMatchWidth = Math.min(
365,
Math.max(365, Math.floor(availableWidth / roundTotalCount)),
);
if (isBroadcast) {
responsiveMatchWidth = Math.min(
365,
Math.floor(availableWidth / roundTotalCount),
);
}
rounds.forEach((roundMatches, roundIndex) => {
if (rounds[0].length <= 2 && doubleButterflyMode) {
minimumMatchDistance = 2;
nextMatchDistance = baseDistance * 2;
}
const roundDiv = document.createElement("div");
roundDiv.className = "butterfly-round";
roundDiv.style.setProperty("--match-width", `${responsiveMatchWidth}px`);
// Create title
const titleDiv = document.createElement("div");
titleDiv.className = "round-title";
if (isBroadcast) {
titleDiv.className = "round-title broadcast-mode";
}
// Get the match group name and format
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
let nameSpan = document.createElement("div");
nameSpan.className = "round-name";
nameSpan.textContent = matchGroupName;
if (
roundIndex == finalRoundIndex ||
(roundIndex == finalRoundIndex - 1 && displayLoserFinal) ||
(roundIndex == finalRoundIndex + 1 && displayLoserFinal) ||
isBroadcast
) {
} else {
nameSpan = document.createElement("a");
nameSpan.className = "round-name";
nameSpan.classList.add("button");
nameSpan.textContent = matchGroupName;
if (roundId) {
nameSpan.href = `/tournament/${tournamentId}/round/${roundId}/bracket/`;
nameSpan.style.cursor = "pointer";
}
}
const formatSpan = document.createElement("div");
formatSpan.className = "round-format";
formatSpan.textContent = matchFormat;
titleDiv.appendChild(nameSpan);
titleDiv.appendChild(formatSpan);
// Create matches container
const matchesContainer = document.createElement("div");
matchesContainer.className = "matches-container";
if (doubleButterflyMode == true) {
if (roundIndex >= finalRoundIndex - 1) {
matchesContainer.style.transform = `translateX(-50%)`;
if (roundIndex >= finalRoundIndex + 2) {
matchesContainer.style.transform = `translateX(-100%)`;
}
}
}
roundDiv.appendChild(matchesContainer);
if (matchPositions[roundIndex] == undefined) {
matchPositions[roundIndex] = {};
}
matchDisabled[roundIndex] = []; // Initialize array for this round
roundMatches.forEach((matchTemplate, matchIndex) => {
const matchTitle = matchTemplate.dataset.matchTitle;
const matchRealIndex = matchTemplate.dataset.matchRealIndex;
const matchDiv = document.createElement("div");
matchDiv.className = "butterfly-match";
matchDiv.style.position = "absolute";
const isDisabled = matchTemplate.dataset.disabled === "true";
matchDisabled[roundIndex][matchRealIndex] = isDisabled;
let isIncomingLineIsDisabled = isDisabled;
let isOutgoingLineIsDisabled = isDisabled;
let top;
const currentMatchesCount = roundMatches.length;
if (roundIndex > finalRoundIndex) {
matchDiv.classList.add("reverse-bracket");
if (roundIndex <= finalRoundIndex + 2) {
const values = Object.values(
matchPositions[roundCount - roundIndex - 1],
);
top = values[matchIndex];
} else {
top = matchPositions[roundIndex][matchRealIndex];
console.log(matchTitle, top);
}
}
if (roundIndex === 0) {
nextMatchDistance = 0;
if (roundCount > 1) {
const nextMatchesCount = rounds[roundIndex + 1].length;
if (currentMatchesCount == nextMatchesCount && roundCount > 2) {
nextMatchDistance = 0;
}
} else {
nextMatchDistance = 0;
}
top = matchIndex * (matchHeight + matchSpacing) * minimumMatchDistance;
if (roundCount == 3 && doubleButterflyMode) {
top = top + (matchHeight + matchSpacing) / 2;
}
} else if (roundIndex === roundCount - 1 && doubleButterflyMode == true) {
nextMatchDistance = 0;
} else if (roundIndex == finalRoundIndex) {
const values = Object.values(matchPositions[roundIndex - 1]);
const parentPos1 = values[0];
const parentPos2 = values[1];
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 = parentPos1 - baseDistance / 2;
} else {
top = parentPos1 + baseDistance / 2;
}
nextMatchDistance = 0;
} else {
top = parentPos1;
nextMatchDistance = 0;
}
} else {
top = (parentPos1 + parentPos2) / 2;
if (matchIndex == 0) {
nextMatchDistance = parentPos2 - parentPos1;
} else {
nextMatchDistance = 0;
}
if (displayLoserFinal == true) {
if (matchIndex == 1) {
top = matchPositions[roundIndex][0] + baseDistance + 80;
isIncomingLineIsDisabled = true;
}
}
}
} else if (roundIndex < finalRoundIndex) {
const parentIndex1 = matchRealIndex * 2 + 1;
const parentIndex2 = matchRealIndex * 2 + 2;
const parentPos1 = matchPositions[roundIndex - 1][parentIndex1];
const parentPos2 = matchPositions[roundIndex - 1][parentIndex2];
const parent1Disable = matchDisabled[roundIndex - 1][parentIndex1];
const parent2Disable = matchDisabled[roundIndex - 1][parentIndex2];
if (
(parent1Disable == undefined || parent1Disable == true) &&
(parent2Disable == undefined || parent2Disable == true)
) {
isIncomingLineIsDisabled = true;
}
if (
matchPositions[roundIndex - 1][parentIndex1] != undefined &&
matchPositions[roundIndex - 1][parentIndex2] != undefined
) {
top = (parentPos1 + parentPos2) / 2;
if (parent1Disable && parent2Disable) {
nextMatchDistance = 0;
} else {
nextMatchDistance = parentPos2 - parentPos1;
}
} else if (matchPositions[roundIndex - 1][parentIndex1] != undefined) {
nextMatchDistance = 0;
top = matchPositions[roundIndex - 1][parentIndex1];
} else if (matchPositions[roundIndex - 1][parentIndex2] != undefined) {
nextMatchDistance = 0;
top = matchPositions[roundIndex - 1][parentIndex2];
} else {
nextMatchDistance = 0;
top = 0;
}
} else if (roundIndex < roundCount) {
const parentIndex1 = matchRealIndex * 2 + 1;
const parentIndex2 = matchRealIndex * 2 + 2;
const parentMatch1 = rounds[roundIndex + 1].find(
(match) => parseInt(match.dataset.matchRealIndex) === parentIndex1,
);
const parentMatch2 = rounds[roundIndex + 1].find(
(match) => parseInt(match.dataset.matchRealIndex) === parentIndex2,
);
if (matchPositions[roundIndex + 1] == undefined) {
matchPositions[roundIndex + 1] = {};
}
if (
parentMatch1 != undefined &&
parentMatch2 != undefined &&
parentMatch1.dataset.disabled == "false" &&
parentMatch2.dataset.disabled == "false"
) {
console.log(
roundIndex,
matchTitle,
parentMatch1.dataset.matchTitle,
parentMatch2.dataset.matchTitle,
parentMatch1.dataset.disabled,
parentMatch2.dataset.disabled,
top,
);
nextMatchDistance = baseDistance;
matchPositions[roundIndex + 1][parentIndex1] = top - baseDistance / 2;
matchPositions[roundIndex + 1][parentIndex2] = top + baseDistance / 2;
console.log(matchPositions[roundIndex + 1]);
// } else if (parentMatch1 != undefined) {
// matchPositions[roundIndex + 1][parentIndex1] = top;
// nextMatchDistance = 0;
// } else if (parentMatch2 != undefined) {
// matchPositions[roundIndex + 1][parentIndex1] = top;
// nextMatchDistance = 0;
} else if (
parentMatch2 != undefined &&
parentMatch2.dataset.disabled == "false"
) {
nextMatchDistance = 0;
matchPositions[roundIndex + 1][parentIndex2] = top;
} else if (
parentMatch1 != undefined &&
parentMatch1.dataset.disabled == "false"
) {
nextMatchDistance = 0;
matchPositions[roundIndex + 1][parentIndex1] = top;
} else {
isOutgoingLineIsDisabled = true;
}
}
if (doubleButterflyMode == true) {
if (roundIndex >= finalRoundIndex - 2) {
if (roundIndex == finalRoundIndex - 1) {
matchDiv.classList.add("reverse-bracket");
isIncomingLineIsDisabled = true;
nextMatchDistance = nextMatchDistance / 2;
}
if (roundIndex == finalRoundIndex + 1) {
matchDiv.classList.remove("reverse-bracket");
isOutgoingLineIsDisabled = true;
nextMatchDistance = nextMatchDistance;
}
}
}
matchDiv.style.setProperty(
"--semi-final-distance",
`${baseDistance / 2}px`,
);
matchDiv.style.setProperty(
"--next-match-distance",
`${nextMatchDistance}px`,
);
matchDiv.style.top = `${top}px`;
matchPositions[roundIndex][matchRealIndex] = top;
if (matchIndex === 0) {
// // Add logo for final round
// if (roundIndex == finalRoundIndex) {
// const logoDiv = document.createElement('div');
// logoDiv.className = 'round-logo';
// const logoImg = document.createElement('img');
// logoImg.src = '/static/tournaments/images/PadelClub_logo_512.png';
// logoImg.alt = 'PadelClub Logo';
// logoDiv.appendChild(logoImg);
// logoDiv.style.transform = `translateX(-50%)`;
// matchesContainer.appendChild(logoDiv);
// }
// Position title above the first match
if (
roundIndex < finalRoundIndex - 1 ||
roundIndex > finalRoundIndex + 1
) {
titleDiv.style.top = `${-80}px`; // Adjust the 60px offset as needed
} else {
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 = "60px";
} else if (roundIndex == finalRoundIndex + 1) {
titleDiv.style.marginLeft = "-60px";
}
}
matchesContainer.appendChild(titleDiv);
}
if (
roundIndex == finalRoundIndex &&
matchIndex === 1 &&
matchDisabled[roundIndex][matchRealIndex] == false &&
displayLoserFinal == true &&
doubleButterflyMode == false
) {
let nameSpan = document.createElement("div");
nameSpan.className = "round-name";
nameSpan.textContent = matchTitle;
const formatSpan = document.createElement("div");
formatSpan.className = "round-format";
formatSpan.textContent = matchFormat;
const titleDiv = document.createElement("div");
titleDiv.className = "round-title";
titleDiv.appendChild(nameSpan);
titleDiv.appendChild(formatSpan);
titleDiv.style.top = `${top - 80}px`; // Adjust the 60px offset as needed
titleDiv.style.position = "absolute";
matchesContainer.appendChild(titleDiv);
}
matchDiv.innerHTML = `
<div class="incoming-line ${isIncomingLineIsDisabled ? "disabled" : ""}"></div>
<div class="match-content ${isDisabled ? "disabled" : ""}">${matchTemplate.innerHTML}</div>
<div class="outgoing-line ${isOutgoingLineIsDisabled ? "disabled" : ""}"></div>
`;
if (doubleButterflyMode == true) {
if (roundIndex >= finalRoundIndex - 2) {
if (roundIndex === finalRoundIndex - 2) {
if (matchIndex === 0) {
const outgoingLine = document.createElement("div");
outgoingLine.className = "outgoing-line-downward";
matchDiv.appendChild(outgoingLine);
} else {
const outgoingLine = document.createElement("div");
outgoingLine.className = "outgoing-line-upward";
matchDiv.appendChild(outgoingLine);
}
}
if (roundIndex === finalRoundIndex + 2) {
if (matchIndex === 0) {
const outgoingLine = document.createElement("div");
outgoingLine.className = "outgoing-line-downward";
matchDiv.appendChild(outgoingLine);
} else {
const outgoingLine = document.createElement("div");
outgoingLine.className = "outgoing-line-upward";
matchDiv.appendChild(outgoingLine);
}
}
}
}
// if (
// roundIndex == finalRoundIndex - 1 &&
// displayLoserFinal == true &&
// doubleButterflyMode == true
// ) {
// const matchDiv2 = document.createElement("div");
// matchDiv2.className = "butterfly-match";
// matchDiv2.classList.add("inward");
// matchDiv2.classList.add("semi-final");
// matchDiv2.style.setProperty(
// "--next-match-distance",
// `${baseDistance}px`,
// );
// matchDiv2.style.top = `${top}px`;
// matchDiv2.innerHTML = `<div class="match-content">${rounds[0][0].innerHTML}</div>`;
// matchesContainer.appendChild(matchDiv2); // Append to matchesContainer instead of roundDiv
// }
matchesContainer.appendChild(matchDiv); // Append to matchesContainer instead of roundDiv
});
bracket.appendChild(roundDiv);
});
}