UNPKG

@talabes/football-lineup-generator

Version:

A TypeScript library for generating visual football lineup diagrams from team positioning data. Fork of ncamaa/football-lineup-generator with bug fixes and improvements.

74 lines (73 loc) 4.81 kB
import { Position } from '../types.js'; import { drawField } from './drawField.js'; import { drawTeamLabel } from './drawTeamLabel.js'; import { calculatePlayerCoordinates } from './calculatePlayerCoordinates.js'; import { calculateLabelPositions } from './calculateLabelPositions.js'; import { drawPlayer } from './drawPlayer.js'; import { mirrorCoordinatesForAwayTeam } from './mirrorCoordinates.js'; import { drawSubstitutesList } from './drawSubstitutesList.js'; export function renderFullPitch(ctx, lineupData, config, customCoordinates) { // Draw field drawField(ctx, config.width, config.height, config.fieldColor, config.lineColor); // Draw team labels drawTeamLabel(ctx, lineupData.homeTeam.name, true, config.width, config.homeTeamColor, config.awayTeamColor, config.fontSize); drawTeamLabel(ctx, lineupData.awayTeam.name, false, config.width, config.homeTeamColor, config.awayTeamColor, config.fontSize); // Calculate coordinates for home team players (exclude substitutes) // Apply -20px offset to move home team left and prevent center overlap const homeFieldPlayers = lineupData.homeTeam.players.filter(p => p.position !== Position.SUBSTITUTE); const homePlayerCoords = calculatePlayerCoordinates(homeFieldPlayers, config.width, config.height, config.layoutType, 0, false, true, -20 // Move home team left by 20px ); // Calculate coordinates for away team players (exclude substitutes) // Apply -20px offset which will become +20px after mirroring, moving away team right const awayFieldPlayers = lineupData.awayTeam.players.filter(p => p.position !== Position.SUBSTITUTE); const awayPlayerCoords = calculatePlayerCoordinates(awayFieldPlayers, config.width, config.height, config.layoutType, 0, false, false, -20 // This becomes +20px after mirroring, moving away team right ); // Create mirrored coordinates for away team const awayPlayerCoordsWithMirroring = awayPlayerCoords.map(({ player, coordinates }) => ({ player, coordinates: mirrorCoordinatesForAwayTeam(coordinates, config.width) })); // Apply custom coordinates AFTER transformations if (customCoordinates) { homePlayerCoords.forEach((playerCoord) => { const key = `${playerCoord.player.team}-${playerCoord.player.player.id}`; const customCoord = customCoordinates.get(key); if (customCoord) { playerCoord.coordinates = customCoord; } }); awayPlayerCoordsWithMirroring.forEach((playerCoord) => { const key = `${playerCoord.player.team}-${playerCoord.player.player.id}`; const customCoord = customCoordinates.get(key); if (customCoord) { playerCoord.coordinates = customCoord; } }); } // Calculate smart label positions with cross-team proximity analysis const allPlayersWithCoords = [...homePlayerCoords, ...awayPlayerCoordsWithMirroring]; const playersWithLabelPositions = calculateLabelPositions(allPlayersWithCoords, allPlayersWithCoords); // Draw home team players (left side) for (const playerWithLabel of playersWithLabelPositions) { const isHomePlayer = homePlayerCoords.some(hp => hp.player === playerWithLabel.player); if (isHomePlayer) { drawPlayer(ctx, playerWithLabel.player, playerWithLabel.coordinates, true, config.homeTeamColor, config.awayTeamColor, config.playerCircleSize, config.showJerseyNumbers, config.showPlayerNames, config.fontSize, allPlayersWithCoords, playerWithLabel.shouldPlaceLabelAbove); } } // Draw away team players (right side, mirrored) for (const playerWithLabel of playersWithLabelPositions) { const isAwayPlayer = awayPlayerCoordsWithMirroring.some(ap => ap.player === playerWithLabel.player); if (isAwayPlayer) { drawPlayer(ctx, playerWithLabel.player, playerWithLabel.coordinates, false, config.homeTeamColor, config.awayTeamColor, config.playerCircleSize, config.showJerseyNumbers, config.showPlayerNames, config.fontSize, allPlayersWithCoords, playerWithLabel.shouldPlaceLabelAbove); } } // Draw substitutes list if enabled if (config.showSubstitutes.enabled) { drawSubstitutesList(ctx, lineupData, config.width, config.height, config.homeTeamColor, config.awayTeamColor, config.fontSize, config.showSubstitutes.position); } // Return all player coordinates for interactive controller // Note: Don't use spread operator here as it would lose the mutations made above const homeCoords = homePlayerCoords.map(pc => ({ ...pc, isHomeTeam: true })); const awayCoords = awayPlayerCoordsWithMirroring.map(pc => ({ ...pc, isHomeTeam: false })); return [...homeCoords, ...awayCoords]; }