© Copyright 2018 – 2024 FIRECRACKER SPORTS. All Rights Reserved.​ TERMS OF USE  |  PRIVACY POLICY

5th Annual Memorial Day Patriotic Bash

05/23/2025 - 05/26/2025
Providence , Rhode Island

INFORMATION

  • Age groups:
    6 Divisions 9U 10U 11U 12U 13U 14U
  • Pool Play:
    Friday, May 23rd through Sunday, May 25th, 2025
  • Price:
    9U - $124910U - $124911U - $124912U - $124913U - $144914U - $1449
  • Playoffs/Championships:
    Monday, May 26th, 2025

  • 4 Game pool play guarantee, weather permitting.
  • Our annual FanFest on Friday night featuring opening night games, Home Run Derby for 10U and 12U, music, food and much more being added on soon.
  • Local teams must be available to play 1 game Friday evening (5:30PM or 7:45PM) if needed. Normally only 2-4 teams will play Friday evening.
  • 9U - 12U Registration Fee: $1,249.00. (10 - 20 teams per division only)
  • 13U & 14U Registration Fee: $1,449.00 (30 teams per division only)
  • There is a hotel obligation for this event.
  • Bats: 9U - 14U Metal Only *Please view our tournament rules for age specific bat rules*
  • Baseballs and lineup cards are included for each team for this event.
  • Two (2) High School board certified Umpires are supplied for every game except for 9U (1 ump per game).
  • Preliminary round games will take place at area town, high school and collegiate fields with the playoffs and championship games at college facilities.
  • Above and Beyond our Competition...Expanded Social Media Coverage included during the entirety of this event. Our digital content team promotes players and teams on our various social media platforms, conducts pre and post game interviews with players and coaches, captures photographs and videos during the event and reports the days activity all on our website! Also included are live in game scores, stats and standings for everyone to follow along on our website and app!
  • NO GATE FEES EVER! (Savings of $250.00 per team based on competitor's prices)
  • All teams are subject to play at any time at tournament director's request

    Full payment is due on February 1, 2025. Your registration into this tournament is not guaranteed or secured until full payment is received. Teams who have registered and have not paid by February 1, 2025 are subject to being replaced by another fully paid registrant.

Registration

  • DIVISION:
    • 9U
    • 10U
    • 11U
    • 12U
    • 13U
    • 14U
    • OPEN
    • Premier
    • Champions
    • Premier
    • Champions
    • Premier
    • Champions
    • Premier
    • Champions
    • Premier
    • Champions
    196 Teams Registered
    COST: $1249 - $1449

College Coaches Attending

Teams

(14 teams) - OPEN
(10 teams) - Champions
(15 teams) - Premier
(16 teams) - Champions
(15 teams) - Premier
(20 teams) - Premier
(20 teams) - Champions
(23 teams) - Premier
(15 teams) - Champions
(22 teams) - Premier

Locations

Militia Park

Mahoney Road North Easton

Easton massachusetts ,

Get Directions
VENUE DIVISIONS
  • 9U
  • 10U
  • 12U
Fields
  • Field #1 (50/70)
    • Grass
    • Permanent Bathrooms
  • Field #2 (50/70)
    • Grass
    • Permanent Bathrooms
  • Field #1 (46/60)
    • Grass
    • Permanent Bathrooms
  • Field #2 (46/60)
    • Grass
    • Permanent Bathrooms
  • Field #3 (46/60)
    • Grass
    • Permanent Bathrooms
North Attleboro Community

45 South Washington Street

North Attleborough massachusetts ,

Get Directions
VENUE DIVISIONS
  • 13U
Fields
  • North Attleboro Community
    • Grass
Pope Park

Pope Street

Acushnet massachusetts ,

Get Directions
VENUE DIVISIONS
  • 13U
Fields
  • 60/90 Field
    • Grass
  • 50/70 Field
    • Grass
  • 46/60 Field
    • Grass
Campanelli Stadium

1 Feinberg Way

Brockton massachusetts ,United States

Get Directions
VENUE DIVISIONS
  • 14U
Fields
  • Campanelli Stadium
Cranston West Little League

450 Hope Rd

Cranston rhode island ,USA

Get Directions
VENUE DIVISIONS
  • 14U
Fields
  • 50/70 Field
    • Grass
    • Permanent Bathrooms
McMorrow Field

598 Randall Road

Wrentham massachusetts ,United States Of America

Get Directions
VENUE DIVISIONS
  • 14U
Fields
  • McMorrow Field
    • Lights
    • Grass
    • Portable Bathrooms
Mason Field

446 Elm St

North Attleborough massachusetts ,USA

Get Directions
VENUE DIVISIONS
  • 9U
  • 10U
  • 11U
Fields
  • Little Mason #1
    • Lights
    • Grass
    • Portable Bathrooms
    • Concession Stand
  • Little Mason #2
    • Lights
    • Grass
    • Portable Bathrooms
    • Concession Stand
  • Mason Field 50/70
    • Lights
    • Grass
    • Portable Bathrooms
    • Concession Stand
Fletcher Field

51 Peck St

Franklin ,

Get Directions
VENUE DIVISIONS
  • 10U
  • 11U
Fields
  • Fletcher Field #1
    • Grass
    • Permanent Bathrooms
    • Concession Stand
  • Fletcher Field #2
    • Grass
    • Permanent Bathrooms
    • Concession Stand
King Street Memorial Park

740 King Street

Franklin ,

Get Directions
VENUE DIVISIONS
  • 10U
  • 11U
Fields
  • King Street Memorial Park
    • Grass
    • Permanent Bathrooms
Warwick Continental LL Complex

225 Crossings Blvd

Warwick rhode island ,USA

Get Directions
VENUE DIVISIONS
  • 11U
  • 12U
Fields
  • D’Abrosca Memorial Field
    • Lights
    • Grass
    • Permanent Bathrooms
    • Concession Stand
  • Founders Field
    • Grass
    • Permanent Bathrooms
    • Concession Stand
Boyd Field

600 Sandy Ln

Warwick rhode island ,USA

Get Directions
VENUE DIVISIONS
  • 9U
Fields
  • Boyd Field
Sprague Memorial Field

179 Kingston Road

Narraganset ,

Get Directions
VENUE DIVISIONS
  • 9U
Fields
  • Sprague Memorial Field
    • Lights
    • Grass
    • Portable Bathrooms
VENUE DETAILS

Sprague Memorial Field

Mount Pleasant High School

434 Mount Pleasant Ave

Providence ,

Get Directions
VENUE DIVISIONS
  • 13U
  • 14U
Fields
    VENUE DETAILS

    Mount Pleasant High School

    Rhode Island College

    600 Library Road

    Providence ,

    Get Directions
    VENUE DIVISIONS
    • 13U
    • 14U
    Fields
    • Pontarelli Field
      • Grass
      • Permanent Bathrooms
      • Concession Stand
    VENUE DETAILS

    Rhode Island College

    Slater Park

    401 Newport Ave

    Pawtucket rhode island ,

    Get Directions
    VENUE DIVISIONS
    • 13U
    Fields
    • McConnon Field
      • Lights
      • Grass
      • Portable Bathrooms
    • Dick Cosimini Field
      • Grass
    Hank Soar Athletic Complex

    470 Prospect St

    Pawtucket rhode island ,

    Get Directions
    VENUE DIVISIONS
    • 10U
    • 11U
    • 12U
    Fields
    • Field #1
      • Lights
      • Grass
      • Permanent Bathrooms
    • Field #2
      • Lights
      • Grass
      • Permanent Bathrooms
    • Field #3
      • Lights
      • Grass
      • Permanent Bathrooms
    Rice Complex

    54 Emerald St

    Wrentham massachusetts ,USA

    Get Directions
    VENUE DIVISIONS
    • 10U
    • 12U
    • 13U
    • 14U
    Fields
    • Duffy Field
      • Grass
      • Portable Bathrooms
    • Bogardus Field
      • Grass
      • Portable Bathrooms
    • 60/90 Field
      • Grass
      • Portable Bathrooms
    Strong Field

    50 Strong Avenue

    East Bridgewater ,

    Get Directions
    VENUE DIVISIONS
    • 13U
    Fields
    • Strong Field
      • Grass
      • Permanent Bathrooms
    VENUE DETAILS

    Strong Field

    University of Rhode Island

    3 Keaney Rd

    Kingston rhode island ,USA

    Get Directions
    VENUE DIVISIONS
    • 13U
    Fields
    • Bill Beck Field
      • Turf
      • Portable Bathrooms
    VENUE DETAILS

    The following items are prohibited at this turf venue…

    • Metal Spikes
    • Sunflower Seeds
    • Gum

    Roger Williams University

    1 Old Ferry Rd

    Bristol ,

    Get Directions
    VENUE DIVISIONS
    • 14U
    Fields
    • Roger Williams University
      • Grass
      • Permanent Bathrooms
    Riverpoint Park

    106 Hay St

    West Warwick rhode island ,USA

    Get Directions
    VENUE DIVISIONS
    • 13U
    • 14U
    Fields
    • McCarthy Stadium
      • Lights
      • Grass
      • Permanent Bathrooms
      • Portable Bathrooms
    • Ray Silva Field
      • Lights
      • Grass
      • Permanent Bathrooms
      • Portable Bathrooms
    Johnson & Wales University

    100 Harborside Blvd

    Providence rhode island ,USA

    Get Directions
    VENUE DIVISIONS
    • 13U
    • 14U
    Fields
    • Scotts Miracle Gro Baseball Field
      • Lights
      • Grass
      • Portable Bathrooms
    Dean College (Longley Athletic Complex)

    69 Maple Street

    Franklin ,

    Get Directions
    VENUE DIVISIONS
    • 13U
    • 14U
    Fields
    • Dean College
      • Grass
      • Permanent Bathrooms
    Bryant University

    1150 Douglas Pike

    Smithfield ,

    Get Directions
    VENUE DIVISIONS
    • 13U
    • 14U
    Fields
    • Conaty Park
      • Lights
      • Turf
      • Portable Bathrooms
    VENUE DETAILS

    The following items are prohibited at this turf venue…

    • Metal Spikes
    • Sunflower Seeds
    • Gum

    schedule

    HOTELS

    No More Team Hotel Blocks are Available for this Event due to Popular Demand…We Apologize for the Inconvenience

    To Book Using your Team Block or to Book as an Individual, Not Within a Team Block: Click Here!

    Our Hotel Policies

    ALL TRAVELING TEAM MANAGERS/CLUB ADMINISTRATORS MUST REVIEW OUR HOTEL POLICY & RULES PRESENTED BELOW. FAILURE TO KNOW OUR POLICY COULD SUBJECT YOUR TEAM TO NON-ACCEPTANCE OR REMOVAL FROM THE TOURNAMENT

    To insure the quality of service provided during a Firecracker Sports event this organization has put in a Hotel Obligation Policy.

    WHAT IS A “HOTEL OBLIGATION” TOURNAMENT?

    Simply stated, if your team requires hotel accommodations (team traveling 75 miles or more to the event’s destination city) your team MUST stay at one of the approved participating tournament partner hotels. Teams are required to designate a representative to block off rooms for the entire team through our hotel portal or staff. These participating hotels are reviewable by clicking on the “hotel” links on the tournament event page or on the main page of Firecracker Sports. We do not have a full “stay to play” policy but we do require 75% of your team/coaches to stay with one of our partner hotels through our website. Reservations should be made ASAP as the hotels fill up quick.

    We do have a waiver policy, if teams do NOT want to book through us, but want to participate in our events. Please see below.

    WHY DOES THIS TOURNAMENT HAVE A “HOTEL OBLIGATION?”

    We work very hard to keep our costs down and also balance the economic impact a tournament like ours can have towards the communities and programs we serve. The approved hotels on this website assist with both concerns and the following are the benefits to our programs:

    • We only require 75% of your team to stay with one of our hotels. This allows 25% of your team to use points for their stay at another hotel, use Air BNB or camp sites for their travel preferences.
    • To make it manageable we have room nights “blocked” for our out-of-town teams from our participating tournament partner hotels.
    • Because we do not use a Third Party Housing Group and we negotiate large blocks of rooms with the hotels directly, you’ll find a wide variety of best pricing and amenities from our hotels.
    • Care in selecting location and proximity to our playing field. See our “fields/facilities” tab to find out where your team most likely will be playing so you can lock down hotels near your fields.
    • All of our tournament hotels have been approved due to their quality and desire to give our guests the best event experience.
    • Room inventory which is shared with the tournament to ensure that room demands can be met from year to year.

    SCHEDULES & STANDINGS

    Standings

     TeamWLTRARSRDW%
    DateTimeGameDivisionLocationTeamScoreTeamNotes

    Brackets

    TOP PERFORMERS

    RULES

    There is no rules.

    WEATHER

    `);printWindow.document.close(); }); function gpe_get_schedules_list() { const event_id = '39389'; let division_filter_drop = $("#division_filter_drop").val(); let pool_filter_drop = $("#pool_filter_drop").val(); let date_filter_drop = $("#date_filter_drop").val();// Show processing indicator (manually trigger it) table.destroy(); // Destroy old DataTable before making new AJAX call $("#schedules_table tbody").html('Loading...'); // Temporary loader row$.ajax({ url: gpe.ajax_url, type: 'post', data: { action: 'gpe_ajax', type: 'gpe_get_schedules_list', event_id: event_id, division_filter_drop: division_filter_drop, pool_filter_drop: pool_filter_drop, date_filter_drop: date_filter_drop }, success: function (response) { // Clear the table body and add new content $("#schedules_table tbody").empty().html(response.data.html);// Reinitialize DataTable with processing enabled table = $("#schedules_table").DataTable({ processing: true, serverSide: false, // Keep it false unless loading data dynamically searching: true, paging: true, autoWidth: false }); } }); } function gpe_get_standing_list() { const event_id = '39389'; let division_filter_drop = $("#division_filter_drop_for_standing").val(); let pool_filter_drop = $("#pool_filter_drop_for_standing").val(); // Show processing indicator (manually trigger it) standings_table.destroy(); // Destroy old DataTable before making new AJAX call $("#standings_table tbody").html('Loading...'); // Temporary loader row $.ajax({ url: gpe.ajax_url, type: 'post', data: { action: 'gpe_ajax', type: 'gpe_get_standing_list', event_id: event_id, division_filter_drop: division_filter_drop, pool_filter_drop: pool_filter_drop }, success: function (response) { // Clear the table body and add new content $("#standings_table tbody").empty().html(response.data.html); // Reinitialize DataTable with processing enabled standings_table = $("#standings_table").DataTable({ processing: true, serverSide: false, // Keep it false unless loading data dynamically searching: true, paging: false }); } }); } $('#shareDropdown').change(function(){ var selectedOption = $(this).val(); if (selectedOption === "copy") { var pageLink = window.location.href; var tempInput = $(""); $("body").append(tempInput); tempInput.val(pageLink).select(); document.execCommand("copy"); tempInput.remove(); Swal.fire({ title:"Success", text:"Copied to clipboard!", icon:'success' }); // Reset dropdown selection $(this).prop('selectedIndex', 0); } }); }); function gpeCustomeTabs(evt, cityName) { var i, tabcontent, tablinks; tabcontent = document.getElementsByClassName("gpe_tabcontent"); for (i = 0; i < tabcontent.length; i++) { tabcontent[i].style.display = "none"; } tablinks = document.getElementsByClassName("gpe_tablinks"); for (i = 0; i < tablinks.length; i++) { tablinks[i].className = tablinks[i].className.replace(" gpe_active", ""); } document.getElementById(cityName).style.display = "block"; evt.currentTarget.className += " gpe_active"; // Redraw connectors when Bracket tab is activated if (cityName === "brackets" && window.globalSerialMap) { // Wait until the browser has painted the visible DOM //requestAnimationFrame(() => { //setTimeout(() => { waitForLayoutAndDraw(window.globalSerialMap, 20); //}, 100); //}); } }// Get the element with id="defaultOpen" and click on it document.getElementById("defaultOpen").click(); var acc = document.getElementsByClassName("gpe_accordion"); var i; for (i = 0; i < acc.length; i++) { acc[i].addEventListener("click", function() { this.classList.toggle("active"); var panel = this.nextElementSibling; if (panel.style.maxHeight) { panel.style.maxHeight = null; } else { panel.style.maxHeight = panel.scrollHeight + "px"; } }); }var latitude = document.getElementById("latitude").value; var longitude = document.getElementById("longitude").value;var iframe = document.createElement("iframe"); iframe.src = "https://www.google.com/maps/embed?pb=!1m28!1m12!1m3!1d19797.686238814687!2d-71.3765509!3d41.8633795!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!4m13!3e6!4m5!1s0x89e45a80fc2b13ab%3A0x8f62f2e279889968!2sCurrent%20Location!3m2!1d" + latitude + "!2d" + longitude + "!4m5!1s0x89e45a7a2b41f7f3%3A0x6cb46461e8d0c1b4!2s" + latitude + "%2C" + longitude + "!3m2!1d" + latitude + "!2d" + longitude + "!5e0!3m2!1sen!2sus!4v1644233201036!5m2!1sen!2sus"; iframe.width = "528"; iframe.height = "295"; iframe.style.border = "0"; iframe.allowfullscreen = true;var mapContainer = document.getElementById("mapContainer"); mapContainer.innerHTML = ""; mapContainer.appendChild(iframe); function getPoolsByDivision(divisionId) { return $.ajax({ url: gpe.ajax_url, method: "POST", dataType: "json", data: { action: "gpe_ajax", type: "get_pools_save", division_id: divisionId } }); }function loadSavedBracket() { // Get the division ID from the division select dropdown const divisionId = $("#division_select").val(); // Get the current event ID dynamically from PHP const eventId = '39389';// If division ID is not selected, exit early if (!divisionId) return;// Perform both AJAX requests in parallel $.when( $.ajax({ url: gpe.ajax_url, // URL for the AJAX request type: "POST", // HTTP method dataType: "json", // Expected response type data: { action: "gpe_ajax", // WordPress action hook for AJAX type: "get_saved_bracket", // Custom action to get saved bracket data event_id: eventId, // The current event ID division_id: divisionId // The selected division ID } }), getPoolsByDivision(divisionId) // Function to get pools for the selected division ).done(function (bracketRes, poolsRes) { // Extract bracket data from the first response (bracketRes) const bracketData = bracketRes[0]?.data?.bracket_data || []; // Prepare a map of pool ID to pool title const poolMap = {}; poolsRes[0]?.data?.forEach(pool => { poolMap[pool.id] = pool.title; });// Call renderSavedBracket function to render the bracket renderSavedBracket(bracketData, poolMap); }).fail(function () { // In case of failure, show an error message in the bracket container $("#bracket").html("
    Error loading bracket.
    "); }); } function renderSavedBracket(bracketData, poolMap) { let bracketWrapper = $(".bracket_wrapper"); if (bracketWrapper.length === 0) { bracketWrapper = $("
    ").addClass("bracket_wrapper"); // Append it to the main container if it's missing $("#bracket").replaceWith(bracketWrapper); } else { bracketWrapper.empty(); // Clear existing content if already present } let bracketDiv = $("
    ").attr("id", "bracket"); bracketWrapper.append(bracketDiv); if (!bracketData || bracketData.length === 0) { bracketDiv.append(`

    No bracket data found.

    `); return; } let groups = {}; let serialMap = {}; let matchCounter = 1; bracketData.forEach(match => { if (match.is_important === "1") { if (!groups[match.group_number]) groups[match.group_number] = {}; if (!groups[match.group_number][match.column_number]) groups[match.group_number][match.column_number] = []; groups[match.group_number][match.column_number].push(match); } }); const sortedGroups = Object.keys(groups).sort(); const mainGroup = sortedGroups[0]; let groupScrollWrapper = $("
    ").addClass("group-scroll-wrapper"); for (let group of sortedGroups) { let groupSerialCounter = 1; let groupDiv = $("
    ").addClass("group").attr("data-group", group); let columnsContainer = $("
    ").addClass("columns-container"); let groupMatchesArray = Object.values(groups[group]).flat(); let groupLabel = groupMatchesArray[0]?.group_label ?? `Group ${group}`; let labelDiv = $("
    ").addClass("group-label").text(groupLabel); groupDiv.append(labelDiv); let columns = Object.keys(groups[group]).sort((a, b) => a - b); const groupMatches = {}; const allMatches = Object.values(groups[group]).flat(); const matchCount = allMatches.length; const isFiveTeam = allMatches.length === 4 && columns.length === 3; const isSevenTeam = matchCount === 6 && columns.length === 4; const isTenTeam = matchCount === 9 && columns.length === 4; const isNineTeam = matchCount === 8 && columns.length === 4; const isSixTeam = matchCount === 5 && columns.length === 3; const isTwelveTeam = matchCount === 11 && columns.length === 4; // Adjust if using 12 matches if (isTwelveTeam) { allMatches.sort((a, b) => parseInt(a.name) - parseInt(b.name)); const displayOrder = [ allMatches[0], allMatches[1], allMatches[2], allMatches[3], // Round 1 allMatches[4], allMatches[5], allMatches[6], allMatches[7], // Round 2 allMatches[8], allMatches[9], // Semifinals allMatches[10] // Final ];let roundDiv1 = $("
    ").addClass("round").attr("data-column", columns[0]); let roundDiv2 = $("
    ").addClass("round").attr("data-column", columns[1]); let roundDiv3 = $("
    ").addClass("round").attr("data-column", columns[2]); let roundDiv4 = $("
    ").addClass("round").attr("data-column", columns[3]);displayOrder.forEach((match, i) => { const serial = groupSerialCounter++; const matchId = `match-serial-${group}-${serial}`; let matchDiv = $("
    ") .addClass("match") .attr("id", matchId) .attr("data-match-index", match.name);let score1 = match.team1_score ?? "-"; let score2 = match.team2_score ?? "-"; //let team1 = match.team_name1 ?? "Team 1"; //let team2 = match.team_name2 ?? "Team 2"; let team1 = match.source_label_team1 && match.source_label_team1.trim() !== "" ? match.source_label_team1 : (match.team_name1 ?? "Team 1"); let team2 = match.source_label_team2 && match.source_label_team2.trim() !== "" ? match.source_label_team2 : (match.team_name2 ?? "Team 2");let startTime = match.start_time || ""; let location = match.location || "";matchDiv.html(`
    ${serial}
    ${startTime}
    ${location}
    ${team1} ${score1}
    ${team2} ${score2}
    `);const matchContainer = $("
    ").addClass("match-container").css("margin-bottom", "20px"); matchContainer.append(matchDiv);match.serial = serial; if (!groupMatches[match.column_number]) groupMatches[match.column_number] = []; groupMatches[match.column_number].push(match); serialMap[`${group}-${serial}`] = { ...match, group, column: match.column_number, serial };if (i < 4) roundDiv1.append(matchContainer); // Round 1 else if (i < 8) roundDiv2.append(matchContainer); // Round 2 else if (i < 10) roundDiv3.append(matchContainer); // Semis else roundDiv4.append(matchContainer); // Final });columnsContainer.append(roundDiv1); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv2); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv3); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv4);groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100);continue; }if (isSixTeam) { allMatches.sort((a, b) => parseInt(a.name) - parseInt(b.name));const displayOrder = [ allMatches[0], // Match 1 allMatches[1], // Match 2 allMatches[2], // Match 3 allMatches[3], // Match 4 allMatches[4] // Final ];let roundDiv1 = $("
    ").addClass("round").attr("data-column", columns[0]); let roundDiv2 = $("
    ").addClass("round").attr("data-column", columns[1]); let roundDiv3 = $("
    ").addClass("round").attr("data-column", columns[2]);displayOrder.forEach((match, i) => { const serial = groupSerialCounter++; const matchId = `match-serial-${group}-${serial}`;let matchDiv = $("
    ") .addClass("match") .attr("id", matchId) .attr("data-match-index", match.name);let score1 = match.team1_score ?? "-"; let score2 = match.team2_score ?? "-"; //let team1 = match.team_name1 ?? "Team 1"; //let team2 = match.team_name2 ?? "Team 2"; let team1 = match.source_label_team1 && match.source_label_team1.trim() !== "" ? match.source_label_team1 : (match.team_name1 ?? "Team 1"); let team2 = match.source_label_team2 && match.source_label_team2.trim() !== "" ? match.source_label_team2 : (match.team_name2 ?? "Team 2");let startTime = match.start_time || ""; let location = match.location || "";matchDiv.html(`
    ${serial}
    ${startTime}
    ${location}
    ${team1} ${score1}
    ${team2} ${score2}
    `);const matchContainer = $("
    ").addClass("match-container").css("margin-bottom", "20px"); matchContainer.append(matchDiv);match.serial = serial; if (!groupMatches[match.column_number]) groupMatches[match.column_number] = []; groupMatches[match.column_number].push(match);serialMap[`${group}-${serial}`] = { ...match, group, column: match.column_number, serial };if (i < 2) roundDiv1.append(matchContainer); else if (i < 4) roundDiv2.append(matchContainer); else roundDiv3.append(matchContainer); });columnsContainer.append(roundDiv1); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv2); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv3);groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100);continue; } if (isNineTeam) { allMatches.sort((a, b) => parseInt(a.name) - parseInt(b.name));const displayOrder = [ allMatches[0], // Game 1 - Round 1 allMatches[1], // Game 2 - Round 2 allMatches[2], // Game 3 allMatches[3], // Game 4 allMatches[4], // Game 5 allMatches[5], // Game 6 - Round 3 allMatches[6], // Game 7 allMatches[7] // Game 8 - Round 4 (Final) ];let roundDiv1 = $("
    ").addClass("round").attr("data-column", columns[0]); let roundDiv2 = $("
    ").addClass("round").attr("data-column", columns[1]); let roundDiv3 = $("
    ").addClass("round").attr("data-column", columns[2]); let roundDiv4 = $("
    ").addClass("round").attr("data-column", columns[3]);displayOrder.forEach((match, i) => { const serial = groupSerialCounter++; const matchId = `match-serial-${group}-${serial}`;let matchDiv = $("
    ") .addClass("match") .attr("id", matchId) .attr("data-match-index", match.name);let score1 = match.team1_score ?? "-"; let score2 = match.team2_score ?? "-"; //let team1 = match.team_name1 ?? "Team 1"; //let team2 = match.team_name2 ?? "Team 2"; let team1 = match.source_label_team1 && match.source_label_team1.trim() !== "" ? match.source_label_team1 : (match.team_name1 ?? "Team 1"); let team2 = match.source_label_team2 && match.source_label_team2.trim() !== "" ? match.source_label_team2 : (match.team_name2 ?? "Team 2");let startTime = match.start_time || ""; let location = match.location || "";matchDiv.html(`
    ${serial}
    ${startTime}
    ${location}
    ${team1} ${score1}
    ${team2} ${score2}
    `);const matchContainer = $("
    ").addClass("match-container").css("margin-bottom", "20px"); matchContainer.append(matchDiv);match.serial = serial; if (!groupMatches[match.column_number]) groupMatches[match.column_number] = []; groupMatches[match.column_number].push(match);serialMap[`${group}-${serial}`] = { ...match, group, column: match.column_number, serial };if (i === 0) roundDiv1.append(matchContainer); else if (i >= 1 && i <= 4) roundDiv2.append(matchContainer); else if (i === 5 || i === 6) roundDiv3.append(matchContainer); else if (i === 7) roundDiv4.append(matchContainer); });columnsContainer.append(roundDiv1); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv2); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv3); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv4);groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100);continue; }if (isTenTeam) { allMatches.sort((a, b) => parseInt(a.name) - parseInt(b.name)); console.log("10-team allMatches:", allMatches.map(m => ({ name: m.name, id: m.id, column: m.column_number })));// Custom display order: Round 2 is visually reordered // Custom display order: Round 2 is visually reordered const displayOrder = [ allMatches[0], allMatches[1], // Round 1: Match 36, 37 allMatches[2], allMatches[3], allMatches[4], allMatches[5], // Round 2: Matches 3, 4, 5, 6 (in order) allMatches[6], allMatches[7], // Round 3: Matches 42–43 allMatches[8] // Final: Match 44 ];let roundDiv1 = $("
    ").addClass("round").attr("data-column", columns[0]); let roundDiv2 = $("
    ").addClass("round").attr("data-column", columns[1]); let roundDiv3 = $("
    ").addClass("round").attr("data-column", columns[2]); let roundDiv4 = $("
    ").addClass("round").attr("data-column", columns[3]);displayOrder.forEach((match, i) => { const serial = groupSerialCounter++; const matchId = `match-serial-${group}-${serial}`;let matchDiv = $("
    ") .addClass("match") .attr("id", matchId) .attr("data-match-index", match.name);let score1 = match.team1_score ?? "-"; let score2 = match.team2_score ?? "-"; //let team1 = match.team_name1 ?? "Team 1"; //let team2 = match.team_name2 ?? "Team 2"; let team1 = match.source_label_team1 && match.source_label_team1.trim() !== "" ? match.source_label_team1 : (match.team_name1 ?? "Team 1"); let team2 = match.source_label_team2 && match.source_label_team2.trim() !== "" ? match.source_label_team2 : (match.team_name2 ?? "Team 2");let startTime = match.start_time || ""; let location = match.location || "";matchDiv.html(`
    ${serial}
    ${startTime}
    ${location}
    ${team1} ${score1}
    ${team2} ${score2}
    `);const matchContainer = $("
    ") .addClass("match-container") .css("margin-bottom", "20px"); // ← add spacing between matchesmatchContainer.append(matchDiv);match.serial = serial; if (!groupMatches[match.column_number]) groupMatches[match.column_number] = []; groupMatches[match.column_number].push(match);serialMap[`${group}-${serial}`] = { ...match, group, column: match.column_number, serial };if (i < 2) roundDiv1.append(matchContainer); // Round 1 else if (i >= 2 && i <= 5) { // Force desired visual order for Round 2: Matches 38, 39, 40, 41 // Map i to visual index: 2→0, 3→1, 4→2, 5→3 const round2Order = [2, 3, 4, 5]; const targetIndex = round2Order.indexOf(i);if (targetIndex !== -1) { const container = roundDiv2.find(".match-container").eq(targetIndex); if (container.length) { container.before(matchContainer); } else { roundDiv2.append(matchContainer); } } }else if (i < 8) roundDiv3.append(matchContainer); // Round 3 else roundDiv4.append(matchContainer); // Final });columnsContainer.append(roundDiv1); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv2); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv3); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv4);groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100);continue; }if (isFiveTeam) { allMatches.sort((a, b) => parseInt(a.name) - parseInt(b.name)); const displayOrder = [allMatches[0], allMatches[2], allMatches[1], allMatches[3]]; groupMatches[columns[0]] = [allMatches[0]]; groupMatches[columns[1]] = [allMatches[2], allMatches[1]]; groupMatches[columns[2]] = [allMatches[3]]; let roundDiv1 = $("
    ").addClass("round").attr("data-column", columns[0]); let roundDiv2 = $("
    ").addClass("round").attr("data-column", columns[1]); let roundDiv3 = $("
    ").addClass("round").attr("data-column", columns[2]); displayOrder.forEach((match, i) => { const serial = groupSerialCounter++; const matchId = `match-serial-${group}-${serial}`; let matchDiv = $("
    ") .addClass("match") .attr("id", matchId) .attr("data-match-index", match.name);let score1 = match.team1_score ?? "-"; let score2 = match.team2_score ?? "-"; //let team1 = match.team_name1 ?? "Team 1"; //let team2 = match.team_name2 ?? "Team 2"; let team1 = match.source_label_team1 && match.source_label_team1.trim() !== "" ? match.source_label_team1 : (match.team_name1 ?? "Team 1"); let team2 = match.source_label_team2 && match.source_label_team2.trim() !== "" ? match.source_label_team2 : (match.team_name2 ?? "Team 2");let startTime = match.start_time || ""; let location = match.location || "";matchDiv.html(`
    ${serial}
    ${startTime}
    ${location}
    ${team1} ${score1}
    ${team2} ${score2}
    `); const matchContainer = $("
    ").addClass("match-container"); matchContainer.append(matchDiv);match.serial = serial; serialMap[`${group}-${serial}`] = { ...match, group, column: match.column_number, serial };if (i === 0) roundDiv1.append(matchContainer); else if (i === 1 || i === 2) roundDiv2.append(matchContainer); else if (i === 3) roundDiv3.append(matchContainer); });columnsContainer.append(roundDiv1); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv2); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv3);groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100);continue; }if (isSevenTeam) { allMatches.sort((a, b) => parseInt(a.name) - parseInt(b.name));const displayOrder = [ allMatches[0], // Match 1 allMatches[1], // Match 2 allMatches[2], // Match 3 allMatches[3], // Match 4 allMatches[4], // Match 5 allMatches[5] // Match 6 ];// Use only the first 3 columns for layout let roundDiv1 = $("
    ").addClass("round").attr("data-column", columns[0]); let roundDiv2 = $("
    ").addClass("round").attr("data-column", columns[1]); let roundDiv3 = $("
    ").addClass("round").attr("data-column", columns[2]);displayOrder.forEach((match, i) => { const serial = groupSerialCounter++; const matchId = `match-serial-${group}-${serial}`;let matchDiv = $("
    ") .addClass("match") .attr("id", matchId) .attr("data-match-index", match.name);let score1 = match.team1_score ?? "-"; let score2 = match.team2_score ?? "-"; //let team1 = match.team_name1 ?? "Team 1"; //let team2 = match.team_name2 ?? "Team 2"; let team1 = match.source_label_team1 && match.source_label_team1.trim() !== "" ? match.source_label_team1 : (match.team_name1 ?? "Team 1"); let team2 = match.source_label_team2 && match.source_label_team2.trim() !== "" ? match.source_label_team2 : (match.team_name2 ?? "Team 2");let startTime = match.start_time || ""; let location = match.location || "";matchDiv.html(`
    ${serial}
    ${startTime}
    ${location}
    ${team1} ${score1}
    ${team2} ${score2}
    `);const matchContainer = $("
    ").addClass("match-container"); matchContainer.append(matchDiv);match.serial = serial; if (!groupMatches["1"]) groupMatches["1"] = []; groupMatches["1"].push(match); serialMap[`${group}-${serial}`] = { ...match, group, column: match.column_number, serial };if (i < 3) { roundDiv1.append(matchContainer); // Matches 0,1,2 } else if (i < 5) { roundDiv2.append(matchContainer); // Matches 3,4 } else { roundDiv3.append(matchContainer); // Match 5 }});columnsContainer.append(roundDiv1); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv2); columnsContainer.append($("
    ").addClass("connector-column")); columnsContainer.append(roundDiv3);groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100);continue; } columns.forEach((column, columnIndex) => { groups[group][column].sort((a, b) => parseInt(a.name) - parseInt(b.name)); let roundDiv = $("
    ").addClass("round").attr("data-column", column); groupMatches[column] = [];groups[group][column].forEach(match => { const serial = groupSerialCounter++; const matchId = `match-serial-${group}-${serial}`;let matchDiv = $("
    ") .addClass("match") .attr("id", matchId) .attr("data-match-index", match.name);let score1 = match.team1_score ?? "-"; let score2 = match.team2_score ?? "-"; //let team1 = match.team_name1 ?? "Team 1"; //let team2 = match.team_name2 ?? "Team 2"; let team1 = match.source_label_team1 && match.source_label_team1.trim() !== "" ? match.source_label_team1 : (match.team_name1 ?? "Team 1"); let team2 = match.source_label_team2 && match.source_label_team2.trim() !== "" ? match.source_label_team2 : (match.team_name2 ?? "Team 2");let startTime = match.start_time || ""; let location = match.location || "";matchDiv.html(`
    ${serial}
    ${startTime}
    ${location}
    ${team1} ${score1}
    ${team2} ${score2}
    `);const matchContainer = $("
    ").addClass("match-container"); matchContainer.append(matchDiv); roundDiv.append(matchContainer);match.serial = serial; serialMap[`${group}-${serial}`] = { ...match, group, column, serial };groupMatches[column].push(match); });columnsContainer.append(roundDiv); if (columnIndex < columns.length - 1) { columnsContainer.append($("
    ").addClass("connector-column")); } });groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100); }bracketDiv.append(groupScrollWrapper);const observer = new MutationObserver(() => { const visible = $(".bracket_wrapper:visible").length > 0; if (visible) { setTimeout(() => { waitForLayoutAndDraw(window._lastSerialMap || {}, 20); }, 100); } });observer.observe(document.body, { childList: true, subtree: true }); window.globalSerialMap = serialMap; } function positionMatches(groupMatches, group) { const levels = Object.keys(groupMatches).sort((a, b) => +a - +b); const matchCenters = {}; const spacing = 200; let bottomMost = 0; const totalMatches = Object.values(groupMatches).flat().length; const isFiveTeamLayout = totalMatches === 4; const isSixTeamLayout = totalMatches === 5; const isSevenTeamLayout = totalMatches === 6; const isTenTeamLayout = totalMatches === 9; const isNineTeamLayout = totalMatches === 8; const isTwelveTeamLayout = totalMatches === 11;if (isTwelveTeamLayout) { const serialPositions = { 1: 200, // Round 1 2: 400, 3: 600, 4: 800, 5: 100, 6: 300, // Quarterfinals 7: 500, 8: 700, 9: 200, 10: 600, // Semifinal 1 11: 400 // Final };// Position matches Object.keys(serialPositions).forEach((serialStr) => { const serial = parseInt(serialStr); const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const y = serialPositions[serial]; $match.css({ position: "absolute", top: `${y}px` }); matchCenters[serial] = y + $match.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $match.outerHeight()); } });// Draw connector lines (you may need to tweak based on actual match setup) drawConnectorLine(group, 1, 5, 'left', 'bottom'); drawConnectorLine(group, 2, 6, 'left', 'bottom'); drawConnectorLine(group, 3, 7, 'left', 'bottom'); drawConnectorLine(group, 4, 8, 'left', 'bottom'); drawConnectorLine(group, 5, 9, 'right', 'top'); drawConnectorLine(group, 6, 9, 'right', 'bottom'); drawConnectorLine(group, 7, 10, 'right', 'top'); drawConnectorLine(group, 8, 10, 'right', 'bottom'); drawConnectorLine(group, 9, 11, 'right', 'top'); drawConnectorLine(group, 10, 11, 'right', 'bottom');$(`.group[data-group="${group}"]`).css("height", `${bottomMost + 250}px`); return; }if (isNineTeamLayout) { const serialPositions = { 1: 200, // Game 1 (Round 1) 2: 100, // Game 2 (Round 2) 3: 300, // Game 3 4: 500, // Game 4 5: 700, // Game 5 6: 200, // Game 6 (Round 3) 7: 600, // Game 7 8: 400 // Game 8 (Final) };[1, 2, 3, 4, 5, 6, 7, 8].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const y = serialPositions[serial]; $match.css({ position: "absolute", top: `${y}px` }); matchCenters[serial] = y + $match.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $match.outerHeight()); } }); // Draw connector lines based on logical flow drawConnectorLine(group, 1, 2); // Game 1 → Game 2 drawConnectorLine(group, 2, 6); // Game 2 → Game 6 drawConnectorLine(group, 3, 6); // Game 3 → Game 6 drawConnectorLine(group, 4, 7); // Game 4 → Game 7 drawConnectorLine(group, 5, 7); // Game 5 → Game 7 drawConnectorLine(group, 6, 8); // Game 6 → Game 8 drawConnectorLine(group, 7, 8); // Game 7 → Game 8bottomMost = 0; [1, 2, 3, 4, 5, 6, 7, 8].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const y = serialPositions[serial]; $match.css({ position: "absolute", top: `${y}px` }); matchCenters[serial] = y + $match.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $match.outerHeight()); } });// Apply accurate height to container $(`.group[data-group="${group}"]`).css("height", `${bottomMost + 250}px`); return; }// Ten Team Layout if (isTenTeamLayout) { const serialPositions = { 1: 200, 2: 600, 3: 100, 4: 300, 5: 500, 6: 700, 7: 200, 8: 600, 9: 400 };// Loop through matches 1 to 9 to set positions [1, 2, 3, 4, 5, 6, 7, 8, 9].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const y = serialPositions[serial]; $match.css({ position: "absolute", top: `${y}px` }); matchCenters[serial] = y + $match.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $match.outerHeight()); } });// Draw connector lines for Round 1, 2, and 3 drawConnectorLine(group, 1, 3, 'left', 'bottom'); drawConnectorLine(group, 2, 5, 'left', 'bottom'); drawConnectorLine(group, 3, 7, 'right', 'top'); drawConnectorLine(group, 4, 7, 'right', 'bottom'); drawConnectorLine(group, 5, 8, 'right', 'top'); drawConnectorLine(group, 6, 8, 'right', 'bottom'); drawConnectorLine(group, 7, 9, 'right', 'top'); drawConnectorLine(group, 8, 9, 'right', 'bottom');bottomMost = 0; [1, 2, 3, 4, 5, 6, 7, 8, 9].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const y = serialPositions[serial]; $match.css({ position: "absolute", top: `${y}px` }); matchCenters[serial] = y + $match.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $match.outerHeight()); } }); $(`.group[data-group="${group}"]`).css("height", `${bottomMost + 250}px`); return; } if (isSevenTeamLayout) { const matchCenters = {}; let bottomMost = 0;// More generous vertical spacing between 1 → 2 → 3 (adjusted for more matches) const serialPositions = { 1: 0, // Match 1 at the top 2: 180, // Match 2 below Match 1 3: 400, // Match 3 below Match 2 4: 620, // Match 4 below Match 3 (between 1 & 2) 5: 840, // Match 5 below Match 4 (between 2 & 3) 6: 1060, // Match 6 below Match 5 (between 4 & 5) 7: 1280 // Match 7 at the bottom (below Match 6) };// Position Matches 1–7 (Play-ins) [1, 2, 3, 4, 5, 6, 7].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const y = serialPositions[serial]; $match.css({ position: "absolute", top: `${y}px` }); matchCenters[serial] = y + $match.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $match.outerHeight()); } }); console.log('Height1'+bottomMost); // Adjust positions for the additional matches if necessary: // Match 4: between 1 & 2 (Positioned earlier in `serialPositions`) const $match4 = $(`#match-serial-${group}-4`).closest(".match-container"); if ($match4.length) { const centerY = (matchCenters[1] + matchCenters[2]) / 2 - $match4.outerHeight() / 2; $match4.css({ position: "absolute", top: `${centerY}px` }); matchCenters[4] = centerY + $match4.outerHeight() / 2; bottomMost = Math.max(bottomMost, centerY + $match4.outerHeight()); }// Match 5: between 2 and 3 — center with slight right offset const $match5 = $(`#match-serial-${group}-5`).closest(".match-container"); if ($match5.length && matchCenters[2] && matchCenters[3]) { const centerY = (matchCenters[2] + matchCenters[3]) / 2 - $match5.outerHeight() / 2; const rightOffset = 40; // slight offset to center horizontally $match5.css({ position: "absolute", top: `${centerY}px` }); matchCenters[5] = centerY + $match5.outerHeight() / 2; bottomMost = Math.max(bottomMost, centerY + $match5.outerHeight()); }// Match 6: between match 4 and 5, centered to the right const $match6 = $(`#match-serial-${group}-6`).closest(".match-container"); if ($match6.length && matchCenters[4] && matchCenters[5]) { const centerY = (matchCenters[4] + matchCenters[5]) / 2 - $match6.outerHeight() / 2; const rightOffset = 60; // adjust as needed for proper placement $match6.css({ position: "absolute", top: `${centerY}px` }); matchCenters[6] = centerY + $match6.outerHeight() / 2; bottomMost = Math.max(bottomMost, centerY + $match6.outerHeight()); }// Match 7: below match 6, at the bottom-most position const $match7 = $(`#match-serial-${group}-7`).closest(".match-container"); if ($match7.length && matchCenters[6]) { const centerY = matchCenters[6] + 180; // 180px down from match 6 $match7.css({ position: "absolute", top: `${centerY}px` }); matchCenters[7] = centerY + $match7.outerHeight() / 2; bottomMost = Math.max(bottomMost, centerY + $match7.outerHeight()); }// Draw connector lines between matches drawConnectorLine(group, 1, 4); drawConnectorLine(group, 2, 5); drawConnectorLine(group, 3, 5); drawConnectorLine(group, 4, 6); drawConnectorLine(group, 5, 6); drawConnectorLine(group, 6, 7); // Adding connector line for Match 7// Set container height based on the bottom-most position // Recalculate actual bottom-most point after all matches are positioned bottomMost = 0; [1, 2, 3, 4, 5, 6, 7].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const top = parseFloat($match.css("top")) || 0; const height = $match.outerHeight() || 0; bottomMost = Math.max(bottomMost, top + height); } }); // Apply accurate height to container $(`.group[data-group="${group}"]`).css("height", `${bottomMost + 250}px`); return; } if (isSixTeamLayout) { const serialPositions = { 1: 225, // Game 1 2: 400, // Game 2 3: 100, // Game 3 (Winner G1 vs Team 5) 4: 525, // Game 4 (Winner G2 vs Team 6) 5: 300 // Game 5 (Final) };[1, 2, 3, 4, 5].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const y = serialPositions[serial]; $match.css({ position: "absolute", top: `${y}px` }); matchCenters[serial] = y + $match.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $match.outerHeight()); } });// Draw correct connector lines //drawConnectorLine(group, 1, 3, 'right', 'top'); //drawConnectorLine(group, 2, 4, 'right', 'bottom'); //drawConnectorLine(group, 3, 5, 'right', 'top'); //drawConnectorLine(group, 4, 5, 'right', 'bottom');// Adjust container height bottomMost = 0; [1, 2, 3, 4, 5].forEach((serial) => { const $match = $(`#match-serial-${group}-${serial}`).closest(".match-container"); if ($match.length) { const top = parseFloat($match.css("top")) || 0; const height = $match.outerHeight() || 0; bottomMost = Math.max(bottomMost, top + height); } }); $(`.group[data-group="${group}"]`).css("height", `${bottomMost + 250}px`); return; }// Helper function function drawConnectorLine(group, fromSerial, toSerial) { const fromEl = $(`#match-serial-${group}-${fromSerial}`).closest(".match-container"); const toEl = $(`#match-serial-${group}-${toSerial}`).closest(".match-container");if (!fromEl.length || !toEl.length) { console.warn(`Cannot draw line: from ${fromSerial} or to ${toSerial} not found.`); return; }const $group = $(`.group[data-group="${group}"]`); const $svg = $group.find("svg.connector-layer");if (!$svg.length) { console.warn(`Missing SVG layer in group ${group}`); return; }const fromOffset = fromEl.position(); const toOffset = toEl.position();const fromX = fromEl.position().left + fromEl.outerWidth(); const fromY = fromOffset.top + fromEl.outerHeight() / 2; const toX = toEl.position().left; const toY = toOffset.top + toEl.outerHeight() / 2;const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); line.setAttribute("x1", fromX); line.setAttribute("y1", fromY); line.setAttribute("x2", toX); line.setAttribute("y2", toY); line.setAttribute("stroke", "#333"); line.setAttribute("stroke-width", "2");$svg.append(line); }// Positioning for 5-team layout if (isFiveTeamLayout) { const serialPositions = { 1: 200, // First round (Play-in) 3: 80, // Semifinal 1 (top) 2: 320, // Semifinal 2 (bottom) 4: 200 // Final (centered between semi 1 and 2) };Object.entries(groupMatches).forEach(([level, matches]) => { matches.forEach((match) => { const matchId = `match-serial-${group}-${match.serial}`; const $el = $(`#${matchId}`).closest(".match-container");if (!$el.length) return;const y = serialPositions[match.serial] ?? 0; $el.css({ position: "absolute", top: `${y}px` });matchCenters[match.serial] = y + $el.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $el.outerHeight()); }); });$(`.group[data-group="${group}"]`).css("height", bottomMost + 160); return; }// Default layout for other brackets levels.forEach((level, levelIndex) => { const matches = groupMatches[level];matches.forEach((match, i) => { const matchId = `match-serial-${group}-${match.serial}`; const $el = $(`#${matchId}`).closest(".match-container");if (!$el.length) return;if (levelIndex === 0) { const pairIndex = Math.floor(i / 2); const y = i * spacing + pairIndex * 40; $el.css({ position: "absolute", top: `${y}px` }); matchCenters[match.serial] = y + $el.outerHeight() / 2; bottomMost = Math.max(bottomMost, y + $el.outerHeight()); } else { const prevLevel = levels[levelIndex - 1]; const prevMatches = groupMatches[prevLevel]; const prev1 = prevMatches[i * 2]; const prev2 = prevMatches[i * 2 + 1];if (prev1 && prev2) { const center1 = matchCenters[prev1.serial]; const center2 = matchCenters[prev2.serial]; const centerY = (center1 + center2) / 2; const topOffset = centerY - $el.outerHeight() / 2; $el.css({ position: "absolute", top: `${topOffset}px` }); matchCenters[match.serial] = centerY; bottomMost = Math.max(bottomMost, topOffset + $el.outerHeight()); } } }); });$(`.group[data-group="${group}"]`).css("height", bottomMost + 180); } function debounce(func, delay) { let timeout; return function (...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), delay); }; } function waitForLayoutAndDraw(serialMap, maxTries = 10) { if (window._isDrawingScheduled) return;window._isDrawingScheduled = true; window._lastSerialMap = serialMap;let tries = 0;function tryDraw() { const wrapper = document.querySelector(".bracket_wrapper");if (!wrapper) { if (tries < maxTries) { tries++; requestAnimationFrame(tryDraw); } else { window._isDrawingScheduled = false; // Reset if failed after all tries } return; }const rect = wrapper.getBoundingClientRect(); if (rect.width < 100 || rect.height < 100) { if (tries < maxTries) { tries++; requestAnimationFrame(tryDraw); } else { window._isDrawingScheduled = false; } return; }// ✅ Only draw once per layout session if (!wrapper.dataset.hasDrawn) { drawBracketConnectors(serialMap, true); wrapper.dataset.hasDrawn = "true"; }// 🟢 Reset the flag after a short time (if needed later) setTimeout(() => { window._isDrawingScheduled = false; wrapper.dataset.hasDrawn = ""; // Allow future redraws if needed }, 1000);// 🟢 Add scroll listener once if (!wrapper.dataset.scrollListenerAdded) { console.log("Ketan testing"); wrapper.addEventListener( "scroll", debounce(() => drawBracketConnectors(window._lastSerialMap, true), 100) ); wrapper.dataset.scrollListenerAdded = "true"; } }requestAnimationFrame(tryDraw); }function drawBracketConnectors(serialMap, forceRedraw = false) { console.log("Ketan test"); const svgNS = "http://www.w3.org/2000/svg"; let svg = document.getElementById("bracket-connector-svg"); const wrapper = document.querySelector(".bracket_wrapper");const wrapperRect = wrapper.getBoundingClientRect(); const scrollLeft = wrapper.scrollLeft; const scrollTop = wrapper.scrollTop;if (!svg) { svg = document.createElementNS(svgNS, "svg"); svg.setAttribute("id", "bracket-connector-svg"); svg.style.position = "absolute"; svg.style.top = "0"; svg.style.left = "0"; svg.style.pointerEvents = "none"; wrapper.appendChild(svg); }svg.style.width = wrapper.scrollWidth + "px"; svg.style.height = wrapper.scrollHeight + "px";const layoutHash = JSON.stringify( Object.values(serialMap).map(m => { const el = document.getElementById(`match-serial-${m.group}-${m.serial}`); const rect = el?.getBoundingClientRect(); return { serial: m.serial, group: m.group, column: m.column, rect: rect ? { top: rect.top, left: rect.left, width: rect.width, height: rect.height } : null }; }) );if (!forceRedraw && window._lastLayoutHash === layoutHash) return; window._lastLayoutHash = layoutHash;while (svg.firstChild) svg.removeChild(svg.firstChild);const groupMap = {}; for (const serial in serialMap) { const match = serialMap[serial]; if (!groupMap[match.group]) groupMap[match.group] = []; groupMap[match.group].push(match); }for (const group in groupMap) { const matches = groupMap[group].sort((a, b) => +a.serial - +b.serial); const matchMap = {};matches.forEach(match => { matchMap[match.serial] = match; match.el = document.getElementById(`match-serial-${group}-${match.serial}`); match.rect = match.el?.getBoundingClientRect(); });const isFiveMatch = matches.length === 4; const isThreeTeam = matches.length === 2 && matchMap["1"] && matchMap["2"]; if ( matches.length === 11 && matchMap["1"] && matchMap["2"] && matchMap["3"] && matchMap["4"] && matchMap["5"] && matchMap["6"] && matchMap["7"] && matchMap["8"] && matchMap["9"] && matchMap["10"] && matchMap["11"] ) { const m = matchMap;// Round 1 → Round 2 drawLConnectorCustom(m[1].rect, m[5].rect, "bottom", 40); drawLConnectorCustom(m[2].rect, m[6].rect, "bottom", 40);drawLConnectorCustom(m[3].rect, m[7].rect, "bottom", 40); drawLConnectorCustom(m[4].rect, m[8].rect, "bottom", 40);// Seeds 1-4 with byes go directly to M7–M10 // Assume M5 feeds M7, M6 feeds M8, and so ondrawLConnectorCustom(m[5].rect, m[9].rect, "top", 40); drawLConnectorCustom(m[6].rect, m[9].rect, "bottom", 40);drawLConnectorCustom(m[7].rect, m[10].rect, "top", 40); // adjust if seed logic differs drawLConnectorCustom(m[8].rect, m[10].rect, "bottom", 40);// Round 2 → Semifinal drawLConnectorCustom(m[9].rect, m[11].rect, "top", 40); drawLConnectorCustom(m[10].rect, m[11].rect, "bottom", 40);continue; }if ( matches.length === 9 && matchMap["1"] && matchMap["2"] && matchMap["3"] && matchMap["4"] && matchMap["5"] && matchMap["6"] && matchMap["7"] && matchMap["8"] && matchMap["9"] ) { const m1 = matchMap[1]; const m2 = matchMap[2]; const m3 = matchMap[3]; const m4 = matchMap[4]; const m5 = matchMap[5]; const m6 = matchMap[6]; const m7 = matchMap[7]; const m8 = matchMap[8]; const m9 = matchMap[9];// Round 1 if (m1?.rect && m5?.rect) drawLConnectorCustom(m1.rect, m3.rect, "bottom", 40); if (m2?.rect && m6?.rect) drawLConnectorCustom(m2.rect, m5.rect, "bottom", 40);// Round 2 if (m3?.rect && m7?.rect) drawLConnectorCustom(m3.rect, m7.rect, "top", 40); if (m4?.rect && m7?.rect) drawLConnectorCustom(m4.rect, m7.rect, "bottom", 40); if (m5?.rect && m8?.rect) drawLConnectorCustom(m5.rect, m8.rect, "top", 40); if (m6?.rect && m8?.rect) drawLConnectorCustom(m6.rect, m8.rect, "bottom", 40);// Round 3 (Final) if (m7?.rect && m9?.rect) drawLConnectorCustom(m7.rect, m9.rect, "top", 40); if (m8?.rect && m9?.rect) drawLConnectorCustom(m8.rect, m9.rect, "bottom", 40);continue; } if (matches.length === 5) { // Adjusted for 5 matches console.log("matches.length === 5", matches); // log matches array console.log("matchMap:", matchMap); // log matchMap objectconst m1 = matchMap[1]; const m2 = matchMap[2]; const m3 = matchMap[3]; const m4 = matchMap[4]; const m5 = matchMap[5]; // Remove m6 because it's not available// Round 1 → Round 2 // M1 → M4 (top) if (m1?.rect && m3?.rect) { console.log("Drawing connector for M1 to M3"); drawLConnectorCustom(m1.rect, m3.rect, "top", 40); }// M2 → M5 (top) if (m2?.rect && m4?.rect) { console.log("Drawing connector for M2 to M4"); drawLConnectorCustom(m2.rect, m4.rect, "top", 40); }// M3 → M5 (bottom) if (m3?.rect && m5?.rect) { console.log("Drawing connector for M3 to M5"); drawLConnectorCustom(m3.rect, m5.rect, "bottom", 40); }// Round 2 → Final // M4 → (no M6, adjust logic based on match availability) if (m4?.rect && m5?.rect) { console.log("Drawing connector for M4 to the final match"); // Draw a connector to the final match (if you have a final setup) // You might have a fallback if there's no M6 drawLConnectorCustom(m4.rect,m5.rect, "top", 40); }continue; // use continue, not return — don't break whole function }if (matches.length === 6 && matchMap["1"] && matchMap["2"] && matchMap["3"] && matchMap["4"] && matchMap["5"] && matchMap["6"]) {const m1 = matchMap[1]; const m2 = matchMap[2]; const m3 = matchMap[3]; const m4 = matchMap[4]; const m5 = matchMap[5]; const m6 = matchMap[6];// Round 1 → Round 2 // M1 → M4 (top) if (m1?.rect && m4?.rect) drawLConnectorCustom(m1.rect, m4.rect, "top", 40);// M2 → M5 (top) if (m2?.rect && m5?.rect) drawLConnectorCustom(m2.rect, m5.rect, "top", 40);// M3 → M5 (bottom) if (m3?.rect && m5?.rect) drawLConnectorCustom(m3.rect, m5.rect, "bottom", 40);// Round 2 → Final // M4 → M6 (top) if (m4?.rect && m6?.rect) drawLConnectorCustom(m4.rect, m6.rect, "top", 40);// M5 → M6 (bottom) if (m5?.rect && m6?.rect) drawLConnectorCustom(m5.rect, m6.rect, "bottom", 40);continue; }if (isThreeTeam) { console.log("This is a testing"); const fromMatch = matchMap[1]; const toMatch = matchMap[2];if (fromMatch?.rect && toMatch?.rect) { drawLConnectorCustom(fromMatch.rect, toMatch.rect, "right", 40); }continue; // only skip current group } /*if (matches.length === 5) { const m1 = matchMap[1], m2 = matchMap[2]; const m3 = matchMap[3], m4 = matchMap[4], m5 = matchMap[5];if (m1?.rect && m4?.rect) drawLConnectorCustom(m1.rect, m4.rect, "top", 40); if (m2?.rect && m4?.rect) drawLConnectorCustom(m2.rect, m4.rect, "bottom", 40); if (m3?.rect && m5?.rect) drawLConnectorCustom(m3.rect, m5.rect, "top", 40); if (m4?.rect && m5?.rect) drawLConnectorCustom(m4.rect, m5.rect, "bottom", 40); }*/if (isFiveMatch) { const s1 = matchMap[1], s2 = matchMap[2], s3 = matchMap[3], s4 = matchMap[4];if (s1?.rect && s3?.rect) drawLConnectorCustom(s1.rect, s3.rect, "bottom"); if (s2?.rect && s4?.rect) drawLConnectorCustom(s2.rect, s4.rect, "top", 40); if (s3?.rect && s4?.rect) drawLConnectorCustom(s3.rect, s4.rect, "bottom", 80);continue; // use continue, not return — don't break whole function }const columns = [...new Set(matches.map(m => +m.column))].sort((a, b) => a - b);for (let colIndex = 1; colIndex < columns.length; colIndex++) { const currentCol = columns[colIndex]; const prevCol = columns[colIndex - 1];const currentMatches = matches.filter(m => +m.column === currentCol); const prevMatches = matches.filter(m => +m.column === prevCol);for (let i = 0; i < currentMatches.length; i++) { const targetMatch = currentMatches[i]; const input1 = prevMatches[i * 2]; const input2 = prevMatches[i * 2 + 1];if (input1?.rect && input2?.rect && targetMatch?.rect) { drawLConnectorCustom(input1.rect, targetMatch.rect, "top", 40); drawLConnectorCustom(input2.rect, targetMatch.rect, "bottom", 40); } else if ((input1?.rect || input2?.rect) && targetMatch?.rect) { const fromRect = input1?.rect || input2?.rect; const direction = input1?.rect ? "top" : "bottom"; drawLConnectorCustom(fromRect, targetMatch.rect, direction, 40); } } }function drawLConnectorCustom(fromRect, toRect, toPoint = "center", elbowOffset = 40) { const startX = fromRect.right - wrapperRect.left + scrollLeft; const startY = fromRect.top + fromRect.height / 2 - wrapperRect.top + scrollTop;let toY; const headerOffset = 48;if (toPoint === "top") { toY = toRect.top + headerOffset + 10 - wrapperRect.top + scrollTop; } else if (toPoint === "bottom") { toY = toRect.bottom - 10 - wrapperRect.top + scrollTop; } else { toY = toRect.top + toRect.height / 2 - wrapperRect.top + scrollTop; }const endX = toRect.left - wrapperRect.left + scrollLeft + 5;const path = document.createElementNS(svgNS, "path"); path.setAttribute("stroke", "#999"); path.setAttribute("stroke-width", "1.5"); path.setAttribute("fill", "none"); path.setAttribute("stroke-linecap", "round");const d = ` M ${startX},${startY} H ${endX} V ${toY} `;path.setAttribute("d", d.trim().replace(/\s+/g, " ")); svg.appendChild(path); }function drawTConnector(fromRect, toRect) { const startX = fromRect.right - wrapperRect.left + scrollLeft; const startY = fromRect.top + fromRect.height / 2 - wrapperRect.top + scrollTop;const endX = toRect.left - wrapperRect.left + scrollLeft; const endY = toRect.top + toRect.height / 2 - wrapperRect.top + scrollTop; const midX = (startX + endX) / 2;const path1 = document.createElementNS(svgNS, "path"); path1.setAttribute("stroke", "#999"); path1.setAttribute("stroke-width", "1.5"); path1.setAttribute("fill", "none"); path1.setAttribute("stroke-linecap", "round"); path1.setAttribute("d", `M ${startX},${startY} H ${midX}`); svg.appendChild(path1);const path2 = document.createElementNS(svgNS, "path"); path2.setAttribute("stroke", "#999"); path2.setAttribute("stroke-width", "1.5"); path2.setAttribute("fill", "none"); path2.setAttribute("stroke-linecap", "round"); path2.setAttribute("d", `M ${endX},${endY} H ${midX}`); svg.appendChild(path2);const verticalLine = document.createElementNS(svgNS, "path"); verticalLine.setAttribute("stroke", "#999"); verticalLine.setAttribute("stroke-width", "1.5"); verticalLine.setAttribute("fill", "none"); verticalLine.setAttribute("stroke-linecap", "round"); verticalLine.setAttribute("d", `M ${midX},${startY} V ${endY}`); svg.appendChild(verticalLine); }function drawHorizontalConnector(fromRect, toRect) { const startX = fromRect.right - wrapperRect.left + scrollLeft; const startY = fromRect.top + fromRect.height / 2 - wrapperRect.top + scrollTop;const endX = toRect.left - wrapperRect.left + scrollLeft;const path = document.createElementNS(svgNS, "path"); path.setAttribute("stroke", "#999"); path.setAttribute("stroke-width", "1.5"); path.setAttribute("fill", "none"); path.setAttribute("stroke-linecap", "round");const d = `M ${startX},${startY} H ${endX}`; path.setAttribute("d", d.trim().replace(/\s+/g, " ")); svg.appendChild(path); }function drawRightThenVertical(fromRect, toRect, align = "top") { const startX = fromRect.right - wrapperRect.left + scrollLeft; const startY = fromRect.top + fromRect.height / 2 - wrapperRect.top + scrollTop; const elbowX = startX + 40;const toY = align === "top" ? toRect.top - wrapperRect.top + scrollTop : toRect.bottom - wrapperRect.top + scrollTop;const toX = toRect.left - wrapperRect.left + scrollLeft;const path = document.createElementNS(svgNS, "path"); path.setAttribute("stroke", "#888"); path.setAttribute("stroke-width", "4"); path.setAttribute("fill", "none"); path.setAttribute("stroke-linejoin", "round"); path.setAttribute("stroke-linecap", "round");const d = ` M ${startX},${startY} H ${elbowX} V ${toY} H ${toX} `; path.setAttribute("d", d.trim().replace(/\s+/g, " ")); svg.appendChild(path); }function drawLine(from, to) { if (!from?.rect || !to?.rect) return;const x1 = from.rect.right + scrollLeft - wrapperRect.left; const y1 = from.rect.top + from.rect.height / 2 + scrollTop - wrapperRect.top;const x2 = to.rect.left + scrollLeft - wrapperRect.left; const y2 = to.rect.top + to.rect.height / 2 + scrollTop - wrapperRect.top;const midX = (x1 + x2) / 2;const path = document.createElementNS(svgNS, "path"); path.setAttribute("stroke", "#999"); path.setAttribute("stroke-width", "2"); path.setAttribute("fill", "none"); path.setAttribute("d", `M ${x1},${y1} H ${midX} V ${y2} H ${x2}`); svg.appendChild(path); }function drawDefaultConnect(input1, input2, targetMatch) { if (!input1?.rect || !input2?.rect || !targetMatch?.rect) return;const x1 = input1.rect.right + scrollLeft - wrapperRect.left; const y1 = input1.rect.top + input1.rect.height / 2 + scrollTop - wrapperRect.top;const x2 = input2.rect.right + scrollLeft - wrapperRect.left; const y2 = input2.rect.top + input2.rect.height / 2 + scrollTop - wrapperRect.top;const toX = targetMatch.rect.left + scrollLeft - wrapperRect.left; const toY = targetMatch.rect.top + targetMatch.rect.height / 2 + scrollTop - wrapperRect.top;const midX = (x1 + toX) / 2; const midY = (y1 + y2) / 2;const path = document.createElementNS(svgNS, "path"); path.setAttribute("stroke", "#999"); path.setAttribute("stroke-width", "2"); path.setAttribute("fill", "none");const d = ` M ${x1},${y1} H ${midX} M ${x2},${y2} H ${midX} M ${midX},${y1} V ${y2} M ${midX},${midY} H ${toX} `; path.setAttribute("d", d.trim().replace(/\s+/g, ' ')); svg.appendChild(path); } } }
    ×

    Request for More Info