import { type FrameUnit } from "../frames.ts"; import { type SoccerLayout, type SoccerSpec } from "./soccer-spec.ts"; /** The providers, by the id the options use. */ export type SoccerProviderId = "opta" | "statsbomb" | "wyscout" | "tracab" | "metrica" | "skillcorner" | "secondspectrum" | "impect" | "uefa" | "international"; /** * A pitch as a data provider writes it down. Everything is in the provider's own unit. * * `xLeft` and `xRight` are x at the two goal lines, with the team attacking left to right; `yTop` and `yBottom` are y * at the touchlines as they lie in a picture with the first at the top. So the frame says both where the origin is and * which way y runs: Opta (y up) has `yTop: 100, yBottom: 0`; StatsBomb (y down) has `yTop: 0, yBottom: 80`. The depths * are measured from the goal line along x, the half widths from the middle of the pitch along y. */ export interface SoccerFrame { id: string; name: string; /** The unit of the numbers, for people. */ unit: string; xLeft: number; xRight: number; yTop: number; yBottom: number; /** How far the penalty area reaches from the goal line, and half its width. */ penaltyDepth: number; penaltyHalfWidth: number; /** How far the goal area reaches, and half its width. */ goalAreaDepth: number; goalAreaHalfWidth: number; /** The penalty mark, from the goal line. */ spot: number; /** Half the width of the goal, between the posts. */ goalHalfWidth: number; } /** A provider: its name, the page its figures were read from, and its frame (which for some depends on the size of the pitch). */ export interface SoccerProvider { id: SoccerProviderId; name: string; /** The unit of its numbers, for people. */ unit: string; /** The unit as the frames registry names it. */ frameUnit: FrameUnit; /** Where (0, 0) lies, in words. */ origin: string; /** True when its extents follow the size of the pitch (Tracab's centimetres from the centre): the frame is made for a size. */ sized: boolean; /** The page of the provider's own documentation the figures were read from. */ source: string; /** One line on how the numbers run, for people. */ note: string; /** The frame, for a pitch of this length and width in metres (ignored unless `sized`). */ frame: (length: number, width: number) => SoccerFrame; } /** * The providers. Where a provider's own page gives the figures (StatsBomb's and Wyscout's diagrams, Impect's glossary, * Metrica's and SkillCorner's READMEs) they are those; Opta's, Tracab's and Second Spectrum's specifications are not * public, so theirs are the figures the open-source libraries mplsoccer, ggsoccer and kloppy agree on, which docs/sources.md says. */ export declare const SOCCER_PROVIDERS: Readonly>; /** The ids of the providers, in the order a menu lists them. */ export declare const SOCCER_PROVIDER_IDS: readonly SoccerProviderId[]; /** Whether a frame can be drawn and mapped: its numbers are finite, its extents are not empty and its landmarks lie in order. */ export declare function validFrame(f: unknown): f is SoccerFrame; /** Where the landmarks of a frame stand on each axis, in its units, from the left goal line to the right and from the top touchline to the bottom. */ export declare function soccerLandmarks(f: SoccerFrame): { x: number[]; y: number[]; }; /** A length and width in metres: what a provider whose numbers follow the pitch needs to know. */ export interface PitchMetres { length: number; width: number; } /** * The frame of a provider (by id), or a frame of your own as it is, for a pitch of this size in metres (which matters * only to a provider whose numbers follow the pitch). An id that is not a provider, or a frame that cannot be * drawn, gives `undefined`. * @example * ```ts * import { soccerFrame } from "@johnmorrisdotca/kyogijo-stadiums"; * const opta = soccerFrame("opta"); * console.log(opta?.xRight, opta?.yTop); * // 100 100 * ``` */ export declare function soccerFrame(frame: SoccerProviderId | SoccerFrame | string | undefined, pitch?: PitchMetres): SoccerFrame | undefined; /** The frame an option asks for, for the pitch being drawn. */ export declare const resolveFrame: (pitchType: SoccerProviderId | SoccerFrame | string | undefined, spec: Pick) => SoccerFrame | undefined; /** Where a provider's lines stand on a pitch of this size, in metres: its figures turned to metres. */ export declare function layoutFromFrame(f: SoccerFrame, spec: Pick): SoccerLayout; /** * The matrix `[a, b, c, d, e, f]` of an SVG `transform` that turns a provider's numbers into metres on a pitch of this * size, the left goal line at x 0 and the top touchline at y 0. A group with this transform takes the provider's raw * x and y: that is the `ky-data` group in a drawing made with `pitchType`. */ export declare function frameMatrix(f: SoccerFrame, spec: Pick): [number, number, number, number, number, number]; /** A map from one provider's coordinates to another's. */ export interface Rescaler { (x: number, y: number): [number, number]; /** Only the x of a point. */ x(value: number): number; /** Only the y of a point. */ y(value: number): number; /** The map the other way: from the second provider's coordinates to the first's. */ inverse: Rescaler; from: SoccerFrame; to: SoccerFrame; } /** * The map from one coordinate system to another, piecewise linear between the landmarks (it is built on `piecewise` of * `@johnmorrisdotca/kyogijo-stadiums/frames`), so that a point on a line of the pitch (the goal line, the goal area, the penalty * mark, the penalty area, the halfway line, the touchline, the posts) lands on the same line in the other system. Between * two landmarks the map is linear; beyond the goal lines and the touchlines (a ball out of play) it runs on along the last * piece. Give a pitch size in metres for a provider whose numbers follow the pitch (Tracab, SkillCorner, Second * Spectrum, Metrica, `international`). The same map, through the surface and in feet, is `convert` of the frames module. * @example * ```ts * import { rescale } from "@johnmorrisdotca/kyogijo-stadiums"; * const toStatsBomb = rescale("opta", "statsbomb"); * // The middle of Opta's penalty-box line, 17 units from the goal line, is on StatsBomb's, 18 yards from it. * const [x, y] = toStatsBomb(100 - 17, 50); * console.log(x, y); * // 102 40 * ``` */ export declare function rescale(from: SoccerProviderId | SoccerFrame, to: SoccerProviderId | SoccerFrame, pitch?: PitchMetres): Rescaler;