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.

71 lines (70 loc) 4.94 kB
import { Position } from '../types.js'; import { drawFieldRotated90CCW } from './drawFieldRotated.js'; import { drawTeamLabelRotated90CCW } from './drawTeamLabelRotated.js'; import { calculatePlayerCoordinates } from './calculatePlayerCoordinates.js'; import { calculateLabelPositions } from './calculateLabelPositions.js'; import { rotatePlayerCoordinates90CCW } from './rotateCoordinates.js'; import { drawPlayer } from './drawPlayer.js'; import { drawSubstitutesSplit } from './drawSubstitutesSplit.js'; export function renderSplitPitch(ctx, lineupData, config, customCoordinates) { const gap = 60; // Gap between the two separate fields // Draw FIRST ROTATED FIELD for home team (left side) drawFieldRotated90CCW(ctx, config.width, config.height, config.fieldColor, config.lineColor, 0, true); drawTeamLabelRotated90CCW(ctx, lineupData.homeTeam.name, true, config.width, config.height, config.homeTeamColor, config.awayTeamColor, config.fontSize, 0); // Draw SECOND ROTATED FIELD for away team (right side) drawFieldRotated90CCW(ctx, config.width, config.height, config.fieldColor, config.lineColor, config.height + gap, true); drawTeamLabelRotated90CCW(ctx, lineupData.awayTeam.name, false, config.width, config.height, config.homeTeamColor, config.awayTeamColor, config.fontSize, config.height + gap); // Calculate coordinates for home team players (first field, exclude substitutes) const homeFieldPlayers = lineupData.homeTeam.players.filter(p => p.position !== Position.SUBSTITUTE); const homePlayerCoordsOriginal = calculatePlayerCoordinates(homeFieldPlayers, config.width, config.height, config.layoutType, 0, false, true, 0); // Calculate coordinates for away team players (second field, exclude substitutes) const awayFieldPlayers = lineupData.awayTeam.players.filter(p => p.position !== Position.SUBSTITUTE); const awayPlayerCoordsOriginal = calculatePlayerCoordinates(awayFieldPlayers, config.width, config.height, config.layoutType, 0, // No offset since we'll handle positioning with rotation false, true, 0); // Rotate coordinates for both teams const homePlayerCoords = rotatePlayerCoordinates90CCW(homePlayerCoordsOriginal, config.width, config.height); const awayPlayerCoords = rotatePlayerCoordinates90CCW(awayPlayerCoordsOriginal, config.width, config.height).map(({ player, coordinates }) => ({ player, coordinates: { x: coordinates.x + config.height + gap, // Offset for second field (side by side) y: coordinates.y } })); // Apply custom coordinates AFTER all transformations (rotation + offset) if (customCoordinates) { homePlayerCoords.forEach((playerCoord) => { const key = `${playerCoord.player.team}-${playerCoord.player.player.id}`; const customCoord = customCoordinates.get(key); if (customCoord) { playerCoord.coordinates = customCoord; } }); awayPlayerCoords.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 for each team separately (since they're on different rotated fields) const homePlayersWithLabelPositions = calculateLabelPositions(homePlayerCoords); const awayPlayersWithLabelPositions = calculateLabelPositions(awayPlayerCoords); // Draw home team players on FIRST rotated field (left side) for (const playerWithLabel of homePlayersWithLabelPositions) { drawPlayer(ctx, playerWithLabel.player, playerWithLabel.coordinates, true, config.homeTeamColor, config.awayTeamColor, config.playerCircleSize, config.showJerseyNumbers, config.showPlayerNames, config.fontSize, homePlayerCoords, playerWithLabel.shouldPlaceLabelAbove); } // Draw away team players on SECOND rotated field (right side) for (const playerWithLabel of awayPlayersWithLabelPositions) { drawPlayer(ctx, playerWithLabel.player, playerWithLabel.coordinates, false, config.homeTeamColor, config.awayTeamColor, config.playerCircleSize, config.showJerseyNumbers, config.showPlayerNames, config.fontSize, awayPlayerCoords, playerWithLabel.shouldPlaceLabelAbove); } // Draw substitutes if enabled if (config.showSubstitutes.enabled) { drawSubstitutesSplit(ctx, lineupData, config.height, config.height + gap, config.homeTeamColor, config.awayTeamColor, config.playerCircleSize, config.showJerseyNumbers, config.showPlayerNames, config.fontSize); } // Return all player coordinates for interactive controller return [ ...homePlayerCoords.map(pc => ({ ...pc, isHomeTeam: true })), ...awayPlayerCoords.map(pc => ({ ...pc, isHomeTeam: false })) ]; }