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

3rd Annual All American Summer Classic – Softball

07/31/2025 - 08/03/2025
Old Orchard Beach , Maine

INFORMATION

  • Age groups:
    3 Divisions 14U 16U 18U
  • Pool Play:
    Thursday, July 31st through Saturday, August 2nd, 2025
  • Price:
    14U - $109916U - $119918U - $1199
  • Playoffs/Championships:
    Sunday, August 3rd, 2025
  • 5 game guarantee: Pool play format will be used for all teams competing (weather permitting).
  • Softballs, Lineup cards and Umpires are provided by Firecracker Softball as part of your team's registration fee, this is NOT a pay at plate event.
  • All Umpires are High School board certified and we supply 2 for every game.
  • 14U Registration Fee: $1099.00
  • 16U - 18U Registration Fee: $1,199.00
  • We offer multi-team/event discounts, please inquire for more savings!
  • Preliminary round games will take place at area high school and collegiate fields with the playoffs and championship games at college facilities including St. Joseph's College of Maine, University of New England, University of Southern Maine, Southern Maine Community College and more.
  • 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 per team based on competitor's prices)
  • All teams are subject to play at any time at the tournament director's request.

Acceptance into this tournament is not guaranteed and secured until full payment is received. Payment is due on February 1, 2025. Teams who have registered and have not paid by February 1, 2025 will be taken off of the registration list and placed on the waiting list.

Registration

  • DIVISION:
    • 14U
    • 16U
    • 18U
    • OPEN
    • OPEN
    • OPEN
    24 Teams Registered
    COST: $1099 - $1199

College Coaches Attending

Teams

(9 teams) - OPEN
(8 teams) - OPEN
(7 teams) - OPEN

Locations

University of Southern Maine

37 College Avenue

Gorham ME ,US

Get Directions
VENUE DIVISIONS
  • 18U
VENUE DETAILS

University of Southern Maine

schedule

HOTELS

To Hold a Team Block: Click Here!

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

Brackets

TOP PERFORMERS

RULES

There is no rules.

WEATHER

`);printWindow.document.close(); }); function gpe_get_schedules_list() { const event_id = '39424';let division_filter_drop = $("#division_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, 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 = '39424'; let division_filter_drop = $("#division_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 }, 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: true }); } }); } $('#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() { const divisionId = $("#division_select").val(); const eventId = '39424';if (!divisionId) return;$.when( $.ajax({ url: gpe.ajax_url, type: "POST", dataType: "json", data: { action: "gpe_ajax", type: "get_saved_bracket", event_id: eventId, division_id: divisionId } }), getPoolsByDivision(divisionId) ).done(function (bracketRes, poolsRes) { const bracketData = bracketRes[0]?.data?.bracket_data || []; const poolMap = {}; poolsRes[0]?.data?.forEach(pool => { poolMap[pool.id] = pool.title; });renderSavedBracket(bracketData, poolMap); }).fail(function () { $("#bracket").html("
Error loading bracket.
"); }); } 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 = '39424';// 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 = $("
").addClass("bracket_wrapper"); let bracketDiv = $("
").attr("id", "bracket"); bracketWrapper.append(bracketDiv); $("#bracket").replaceWith(bracketWrapper);if (!bracketData || bracketData.length === 0) { bracketDiv.append(`

No bracket data found.

`); return; }let groups = {}; let serialMap = {}; let matchCounter = 1;bracketData.forEach(match => { 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 columns = Object.keys(groups[group]).sort((a, b) => a - b);const groupMatches = {};// 🔧 Special layout for 5-team / 4-match bracket const allMatches = Object.values(groups[group]).flat(); const isFiveTeam = allMatches.length === 4 && columns.length === 3;if (isFiveTeam) { let roundDiv1 = $("
").addClass("round").attr("data-column", columns[0]); let roundDiv2a = $("
").addClass("round").attr("data-column", columns[1]); let roundDiv2b = $("
").addClass("round").attr("data-column", columns[1]); let roundDiv3 = $("
").addClass("round").attr("data-column", columns[2]);groupMatches[columns[0]] = [allMatches[0]]; // Match 1 groupMatches[columns[1]] = [allMatches[1], allMatches[2]]; // Match 2 + 3 groupMatches[columns[2]] = [allMatches[3]]; // Match 4allMatches.sort((a, b) => parseInt(a.name) - parseInt(b.name));allMatches.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 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) roundDiv2a.append(matchContainer); else if (i === 2) roundDiv2b.append(matchContainer); else if (i === 3) roundDiv3.append(matchContainer); });columnsContainer.append(roundDiv1); columnsContainer.append($("
").addClass("connector-column")); columnsContainer.append(roundDiv2a); columnsContainer.append($("
").addClass("connector-column")); columnsContainer.append(roundDiv2b); columnsContainer.append($("
").addClass("connector-column")); columnsContainer.append(roundDiv3);groupDiv.append(columnsContainer); groupScrollWrapper.append(groupDiv);setTimeout(() => { positionMatches(groupMatches, group); waitForLayoutAndDraw(serialMap, 20); }, 100);continue; // Skip normal rendering }// 🔁 Default rendering for other brackets 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 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 = {}; let bottomMost = 0;const isFiveTeamBracket = levels.length === 3 && groupMatches[levels[0]]?.length === 1 && groupMatches[levels[1]]?.length === 2 && groupMatches[levels[2]]?.length === 1;if (isFiveTeamBracket) { // Custom manual layout const match1 = groupMatches[levels[0]][0]; const match2 = groupMatches[levels[1]][1]; const match3 = groupMatches[levels[1]][0]; const match4 = groupMatches[levels[2]][0];const setMatchPosition = (match, top) => { const matchId = `match-serial-${group}-${match.serial}`; const $el = $(`#${matchId}`).closest(".match-container"); $el.css({ position: "absolute", top: `${top}px` }); matchCenters[match.serial] = top + $el.outerHeight() / 2; bottomMost = Math.max(bottomMost, top + $el.outerHeight()); };setMatchPosition(match1, 200); // Centered in Column 1 setMatchPosition(match3, 0); // Top of Column 2 setMatchPosition(match2, 250); // Below match3 with spacing setMatchPosition(match4, 160); // Centered in Column 3$(`.group[data-group="${group}"]`).css("height", bottomMost + 160); return; }// Default behavior (for non-5-team brackets) const spacing = 200;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 (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 + 160); }function waitForLayoutAndDraw(serialMap, maxTries = 10) { window._lastSerialMap = serialMap;let tries = 0; function tryDraw() { const wrapper = document.querySelector(".bracket_wrapper"); const rect = wrapper?.getBoundingClientRect();if (!rect || rect.width < 100 || rect.height < 100) { if (tries < maxTries) { tries++; requestAnimationFrame(tryDraw); } return; }// Initial draw drawBracketConnectors(serialMap, true);// ✅ Scroll listener: only add once if (!window._bracketScrollListenerAttached) { window._bracketScrollListenerAttached = true;let scrollRedrawTimeout; wrapper?.addEventListener("scroll", () => { clearTimeout(scrollRedrawTimeout); scrollRedrawTimeout = setTimeout(() => { drawBracketConnectors(window._lastSerialMap, true); }, 30); }); } }requestAnimationFrame(tryDraw); }function drawBracketConnectors(serialMap, forceRedraw = false) { const svgNS = "http://www.w3.org/2000/svg"; let svg = document.getElementById("bracket-connector-svg"); const wrapper = document.querySelector(".bracket_wrapper");// 🧠 Refresh bounding and scroll AFTER DOM changes const wrapperRect = wrapper.getBoundingClientRect(); const scrollLeft = wrapper.scrollLeft; const scrollTop = wrapper.scrollTop;// Create SVG if it doesn't exist 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";// 🧠 Generate layout hash ONLY from static layout (not scroll) const layoutHash = JSON.stringify( Object.values(serialMap).map(m => { const el = document.getElementById(`match-serial-${m.group}-${m.serial}`); const wrapper = document.querySelector(".bracket_wrapper"); if (wrapper) { wrapper.style.willChange = "transform"; } 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 }; }) );// 💡 Bypass hash check if forced if (!forceRedraw && window._lastLayoutHash === layoutHash) { return; }window._lastLayoutHash = layoutHash;// Clear SVG children 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;if (isFiveMatch) { const s1 = matchMap[1], s2 = matchMap[2], s3 = matchMap[3], s4 = matchMap[4]; if (s1?.el && s3?.el) drawLine(s1, s3); if (s3?.el && s4?.el) drawLine(s3, s4); if (s2?.el && s4?.el && s3?.el) drawCustomLineAround(s2, s4, s3); continue; }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 && input2) { drawDefaultConnect(input1, input2, targetMatch); } else if (input1 || input2) { drawLine(input1 || input2, targetMatch); } } }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 drawCustomLineAround(from, to, avoidBox) { if (!from?.rect || !to?.rect || !avoidBox?.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 + to.rect.width / 2 + scrollLeft - wrapperRect.left; const y2 = to.rect.bottom + scrollTop - wrapperRect.top;const midX1 = x1 + 40; const midY = avoidBox.rect.bottom + scrollTop - wrapperRect.top + 30;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 ${midX1} V ${midY} H ${x2} V ${y2}`); 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