react-native-football-formation 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +447 -0
- package/dist/assets/index.d.ts +13 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +15 -0
- package/dist/components/FormationField.d.ts +5 -0
- package/dist/components/FormationField.d.ts.map +1 -0
- package/dist/components/FormationField.js +147 -0
- package/dist/components/PlayerCard.d.ts +5 -0
- package/dist/components/PlayerCard.d.ts.map +1 -0
- package/dist/components/PlayerCard.js +365 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +10 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/theme/defaultTheme.d.ts +12 -0
- package/dist/theme/defaultTheme.d.ts.map +1 -0
- package/dist/theme/defaultTheme.js +70 -0
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +17 -0
- package/dist/types/component.types.d.ts +48 -0
- package/dist/types/component.types.d.ts.map +1 -0
- package/dist/types/component.types.js +2 -0
- package/dist/types/formation.types.d.ts +59 -0
- package/dist/types/formation.types.d.ts.map +1 -0
- package/dist/types/formation.types.js +5 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +19 -0
- package/dist/types/theme.types.d.ts +44 -0
- package/dist/types/theme.types.d.ts.map +1 -0
- package/dist/types/theme.types.js +5 -0
- package/dist/utils/formationCoordinates.d.ts +10 -0
- package/dist/utils/formationCoordinates.d.ts.map +1 -0
- package/dist/utils/formationCoordinates.js +311 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/transformLineup.d.ts +21 -0
- package/dist/utils/transformLineup.d.ts.map +1 -0
- package/dist/utils/transformLineup.js +126 -0
- package/package.json +60 -0
- package/src/assets/images/field.png +0 -0
- package/src/assets/images/football.png +0 -0
- package/src/assets/images/kicker.png +0 -0
- package/src/assets/images/ownGoals.png +0 -0
- package/src/assets/images/playerPlaceholder.png +0 -0
- package/src/assets/images/renewal.png +0 -0
- package/src/assets/index.ts +12 -0
- package/src/components/FormationField.tsx +182 -0
- package/src/components/PlayerCard.tsx +452 -0
- package/src/components/index.ts +2 -0
- package/src/index.ts +20 -0
- package/src/theme/defaultTheme.ts +74 -0
- package/src/theme/index.ts +1 -0
- package/src/types/component.types.ts +72 -0
- package/src/types/formation.types.ts +88 -0
- package/src/types/index.ts +3 -0
- package/src/types/theme.types.ts +48 -0
- package/src/utils/formationCoordinates.ts +335 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/transformLineup.ts +158 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TeamLineup,
|
|
3
|
+
Player,
|
|
4
|
+
PlayerStats,
|
|
5
|
+
LineupFormationPlayer,
|
|
6
|
+
FieldCoordinate,
|
|
7
|
+
} from '../types';
|
|
8
|
+
import { FORMATION_COORDINATES_BY_PLACE } from './formationCoordinates';
|
|
9
|
+
|
|
10
|
+
type Stats = (PlayerStats | null)[];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if a player has a specific stat type
|
|
14
|
+
*/
|
|
15
|
+
export const hasStat = (stats: Stats | undefined, statType: string): boolean => {
|
|
16
|
+
return stats?.some(stat => stat?.type === statType) ?? false;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the value of a specific stat type for a player
|
|
21
|
+
*/
|
|
22
|
+
export const getStatValue = (
|
|
23
|
+
stats: Stats | undefined,
|
|
24
|
+
statType: string
|
|
25
|
+
): number | string => {
|
|
26
|
+
return stats?.find(stat => stat?.type === statType)?.value ?? 0;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get formation coordinates by formation place (1-11)
|
|
31
|
+
*/
|
|
32
|
+
const getCoordinatesByFormationPlace = (
|
|
33
|
+
formation: string,
|
|
34
|
+
formationPlace: string
|
|
35
|
+
): FieldCoordinate => {
|
|
36
|
+
const formationCoords = FORMATION_COORDINATES_BY_PLACE[formation as keyof typeof FORMATION_COORDINATES_BY_PLACE];
|
|
37
|
+
if (!formationCoords) {
|
|
38
|
+
return { x: 49, y: 40 }; // Default position (center field)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return formationCoords[formationPlace] || { x: 49, y: 40 };
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Determine position type based on formationPlace and formation
|
|
46
|
+
*/
|
|
47
|
+
const getPositionTypeByFormationPlace = (
|
|
48
|
+
formation: string,
|
|
49
|
+
formationPlace: string
|
|
50
|
+
): string => {
|
|
51
|
+
const placeInt = parseInt(formationPlace);
|
|
52
|
+
|
|
53
|
+
// Common position mappings based on formationPlace
|
|
54
|
+
if (placeInt === 1) return 'GK';
|
|
55
|
+
|
|
56
|
+
// For most formations, places 2-6 are defenders
|
|
57
|
+
if (placeInt >= 2 && placeInt <= 6) {
|
|
58
|
+
if (formation?.startsWith('3-')) {
|
|
59
|
+
// 3-back formations: 4,5,6 are CBs, 2,3 might be wing-backs
|
|
60
|
+
if (placeInt >= 4 && placeInt <= 6) return 'CB';
|
|
61
|
+
if (placeInt === 2) return 'RB';
|
|
62
|
+
if (placeInt === 3) return 'LB';
|
|
63
|
+
} else if (formation?.startsWith('5-')) {
|
|
64
|
+
// 5-back formations: all are defenders
|
|
65
|
+
return placeInt === 2 || placeInt === 3 ? 'LB' : 'CB';
|
|
66
|
+
} else {
|
|
67
|
+
// 4-back formations
|
|
68
|
+
if (placeInt === 2) return 'RB';
|
|
69
|
+
if (placeInt === 3) return 'LB';
|
|
70
|
+
return 'CB';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Places 7-8 are usually midfielders
|
|
75
|
+
if (placeInt >= 7 && placeInt <= 8) return 'CM';
|
|
76
|
+
|
|
77
|
+
// Place 9 is usually striker
|
|
78
|
+
if (placeInt === 9) return 'ST';
|
|
79
|
+
|
|
80
|
+
// Places 10-11 vary by formation
|
|
81
|
+
if (placeInt >= 10 && placeInt <= 11) {
|
|
82
|
+
if (formation.includes('-3-') && formation.endsWith('3')) {
|
|
83
|
+
return placeInt === 10 ? 'RW' : 'LW'; // 4-3-3, 3-4-3 etc.
|
|
84
|
+
}
|
|
85
|
+
return 'CAM'; // Default to attacking midfielder
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return 'CM'; // Default fallback
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Transform lineup data by formation place into positioned players
|
|
93
|
+
*
|
|
94
|
+
* @param data - TeamLineup data with players and formation
|
|
95
|
+
* @param formation - Formation string (e.g., "4-3-3", "4-2-3-1")
|
|
96
|
+
* @param getPlayerPhotoUrl - Optional function to generate photo URLs
|
|
97
|
+
* @returns Array of positioned players with stats
|
|
98
|
+
*/
|
|
99
|
+
export const transformLineupByFormationPlace = (
|
|
100
|
+
data: TeamLineup,
|
|
101
|
+
formation: string = '4-2-3-1',
|
|
102
|
+
getPlayerPhotoUrl?: (playerId: string) => string
|
|
103
|
+
): LineupFormationPlayer[] => {
|
|
104
|
+
// Filter starters (players with formationPlace 1-11)
|
|
105
|
+
const starters =
|
|
106
|
+
data?.players?.filter(
|
|
107
|
+
(p: Player) =>
|
|
108
|
+
p?.formationPlace &&
|
|
109
|
+
parseInt(p?.formationPlace) >= 1 &&
|
|
110
|
+
parseInt(p?.formationPlace) <= 11 &&
|
|
111
|
+
p?.position !== 'Substitute'
|
|
112
|
+
) || [];
|
|
113
|
+
|
|
114
|
+
if (starters?.length < 11) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const transformedPlayers = starters?.map(player => {
|
|
119
|
+
const coordinates = getCoordinatesByFormationPlace(formation, player?.formationPlace!);
|
|
120
|
+
const positionType = getPositionTypeByFormationPlace(formation, player?.formationPlace!);
|
|
121
|
+
|
|
122
|
+
// Generate photo URL using custom function or empty string
|
|
123
|
+
const photoUrl = getPlayerPhotoUrl
|
|
124
|
+
? getPlayerPhotoUrl(player?.playerId)
|
|
125
|
+
: '';
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
playerId: player?.playerId,
|
|
129
|
+
matchName: player?.matchName || '',
|
|
130
|
+
position: positionType,
|
|
131
|
+
formationPlace: player?.formationPlace!,
|
|
132
|
+
rating: player?.rating,
|
|
133
|
+
isScorer: player?.stats && player?.stats?.length ? hasStat(player?.stats, 'goals') : false,
|
|
134
|
+
isSubstitute:
|
|
135
|
+
player?.stats && player?.stats?.length ? hasStat(player?.stats, 'totalSubOff') : false,
|
|
136
|
+
isYellowCard:
|
|
137
|
+
player?.stats && player?.stats?.length ? hasStat(player?.stats, 'yellowCard') : false,
|
|
138
|
+
isRedCard: player?.stats && player?.stats?.length ? hasStat(player?.stats, 'redCard') : false,
|
|
139
|
+
isGoalAssist:
|
|
140
|
+
player?.stats && player?.stats?.length ? hasStat(player?.stats, 'goalAssist') : false,
|
|
141
|
+
isOwnGoal:
|
|
142
|
+
player?.stats && player?.stats?.length ? hasStat(player?.stats, 'ownGoals') : false,
|
|
143
|
+
goals: Number(getStatValue(player?.stats, 'goals')),
|
|
144
|
+
ownGoals: Number(getStatValue(player?.stats, 'ownGoals')),
|
|
145
|
+
shirtNumber: player?.shirtNumber,
|
|
146
|
+
photo: photoUrl,
|
|
147
|
+
x: coordinates?.x,
|
|
148
|
+
y: coordinates?.y,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Sort by formationPlace to maintain consistent ordering
|
|
153
|
+
transformedPlayers.sort((a, b) => {
|
|
154
|
+
return parseInt(a.formationPlace) - parseInt(b.formationPlace);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return transformedPlayers;
|
|
158
|
+
};
|