import type { Layer } from "./layers.types.ts"; import type { Language, SurfaceOptions } from "./types.ts"; /** The things that have a target seen end-on: the sports with a goal, cricket's stumps and baseball's strike zone. */ export declare const TARGET_SPORTS: readonly ["nhl", "soccer", "handball", "waterpolo", "lacrosse", "fieldhockey", "cricket", "mlb"]; /** A sport that has a target. */ export type TargetSport = (typeof TARGET_SPORTS)[number]; /** The sports whose target is a goal. */ export declare const GOAL_SPORTS: readonly ["nhl", "soccer", "handball", "waterpolo", "lacrosse", "fieldhockey"]; export type GoalSport = (typeof GOAL_SPORTS)[number]; /** The unit of a number across a target. */ export type TargetUnit = "m" | "ft" | "in" | "cm" | "yd"; /** A shot, a delivery or a pitch where it crossed the target. */ export interface TargetShot { /** Your id for the mark, written on it as `data-mark-id`. */ id?: string | number; /** Across the target from its middle, positive to the viewer's right (the shooter's, the bowler's; the catcher's for a pitch: Statcast's `plate_x`), in the options' `units`. */ x: number | null; /** Up from the ground (Statcast's `plate_z`), in `units`. */ z: number | null; /** * What became of it. A goal: `goal`, `saved`, `post`, `crossbar`, `wide`, `high`, `blocked`. A pitch: `ball`, `called-strike`, `swinging-strike`, `foul`, `in-play`, `hit-by-pitch`. * A delivery: `wicket`, `runs`, `dot`. Without one, `wide` or `high` if the place is outside the frame, else `shot`. */ outcome?: string; /** The pitch type (`FF`, `SL`) a pitch is coloured by when `colorBy` is `type`. */ type?: string; /** The order of a pitch in the at-bat, 1 first: the number written on its mark. The order given is the default. */ order?: number; /** Expected goals (or any value) that sizes a goal's mark when the options ask. */ value?: number; team?: string; title?: string; /** For a delivery: how far from the batter's stumps it pitched, in the options' `units`: the length zone. */ length?: number; } /** What the target draws. */ export interface TargetOptions { /** `nhl`, `soccer`, `handball`, `waterpolo`, `lacrosse` or `fieldhockey` for a goal, `cricket` for the stumps, `mlb` for the strike zone. */ sport: TargetSport; /** The unit of the shots' `x` and `z`, and of `goal`, `top` and `bottom`: the unit the sport's rulebook prints the target in (feet for hockey, lacrosse and baseball, metres for the rest). */ units?: TargetUnit; /** A league of the sport whose rulebook gives another goal (lacrosse: `nll`, the box floor's 4 ft 9 in by 4 ft; `ncaa-men`). */ league?: string; /** A soccer pitch (the goal of a small-sided format is another size). */ pitch?: SurfaceOptions["pitch"]; /** A goal of another size, in `units`. */ goal?: { width: number; height: number; }; /** Draw the zones as cells with their names (`labels`), or leave them out. On by default for a goal's grid, off for the stumps, the strike zone's 9 cells are always drawn. */ zones?: boolean | "labels"; /** For the strike zone: the top and the bottom of the batter's zone in `units` (feet): the rulebook's definition depends on the batter (the midpoint between the shoulders and the belt, the hollow under the kneecap). 3.5 and 1.5 by default, a batter of average build and ours, not the rulebook's. */ top?: number; bottom?: number; /** The side the batter bats from: `R` (the default) or `L`. The marker stands at his side of the plate. */ bats?: "L" | "R"; /** The 13-zone chase grid: the four outside zones round the 9 inside. On by default. */ chase?: boolean; /** Colour the pitches by their `result` (the default) or their `type`. */ colorBy?: "result" | "type"; /** Write the order number on each pitch (on by default for the strike zone). */ numbers?: boolean; /** Size the marks by their `value`. */ sizeBy?: "value"; language?: Language; id?: string; title?: string; theme?: SurfaceOptions["theme"]; style?: SurfaceOptions["style"]; className?: string; } /** The target as drawn and as data. */ export interface TargetDrawing { /** The drawing as an SVG string. */ svg: string; /** The layers of the marks, in the frame of the target (x across and y up, in `units`), if you want to draw them another way. */ layers: Layer[]; /** The shots that had a place and the ones that did not. */ placed: number; skipped: number; /** How many marks are in each zone, by id. */ zones: Record; /** What the colours and shapes mean: one entry for each result (or type) present. */ key: { id: string; label: string; shape: string; hollow: boolean; color?: string; }[]; /** The frame of the target: the width and height of the opening and of the view, in `units`. */ target: TargetFrame; /** The table of the marks with their place across the target. */ table(): string; } /** The size of a target and of what is drawn round it, in the unit it is in. */ export interface TargetFrame { sport: TargetSport; unit: TargetUnit; /** The opening: the goal's width and height, the stumps' 9 inches by 28, the strike zone's plate width and the zone's height. */ width: number; height: number; /** Where the opening's bottom is: 0 for a goal and the stumps, the bottom of the zone for the strike zone. */ floor: number; /** The view: from `x0` to `x1` across, from `z0` to `z1` up. */ view: { x0: number; x1: number; z0: number; z1: number; }; /** The rulebook line (or the sentence) the size comes from. */ source: string; } /** The size of a goal in its rulebook unit. Hockey: the NHL's net (Rule 2.1) 6 by 4 feet. Soccer: the Laws' 7.32 by 2.44 m, or the format's. Handball: the IHF's 3 by 2 m. Water polo: World Aquatics' 3 m, the crossbar 0.9 m over the water. Lacrosse: 6 by 6 feet (World Lacrosse 1.83 m, NCAA, PLL), the box floor's 4 ft 9 in by 4 ft. Field hockey: the FIH's 3.66 by 2.14 m. */ export declare function goalSize(sport: GoalSport, options?: Pick): { width: number; height: number; unit: "m" | "ft"; source: string; }; /** The ids of the 3 by 3 grid across a goal, left to right and top to bottom: the shooter's left first. */ export declare function goalZoneIds(sport: GoalSport): string[]; /** The length zones of a delivery by where it pitched, in metres from the batter's stumps (the convention here is ours: broadcasters' bands differ with the bowler's pace). */ export declare const LENGTH_ZONES: readonly { id: string; to: number; }[]; /** The length zone of a delivery that pitched this many metres from the batter's stumps. */ export declare function lengthZoneOf(metres: number): string; /** Where a shot lies across a target: the id of its zone, and whether it is inside the opening, wide of it, over it or on its frame. */ export interface TargetPlace { zone: string; placement: "in" | "wide" | "high" | "wide-high" | "frame"; } /** * The zone of a place across a goal, the stumps or the strike zone, in the options' units. A goal: its nine cells (the top shelf and the five-hole in hockey), or `wide-left`, `wide-right` and `over-the-bar` * outside the opening; the stumps: the line zones; the strike zone: `zone-1` to `zone-9` and the chase zones `zone-11` to `zone-14`, else `outside`. * @example * ```ts * import { targetZoneAt } from "@johnmorrisdotca/kyogijo-stadiums/target"; * // A hockey net is 6 by 4 feet: a shot 2.5 feet to the right and 3.7 feet up is under the crossbar in the top right corner. * console.log(targetZoneAt({ sport: "nhl" }, 2.5, 3.7), targetZoneAt({ sport: "nhl" }, 0, 0.3).zone); * // { zone: 'top-right-corner', placement: 'in' } five-hole * ``` */ export declare function targetZoneAt(options: TargetOptions, x: number, z: number): TargetPlace; export declare const KYOGIJO_TARGET_STYLE = "\n.kyogijo .ky-tg-bg{fill:var(--ky-surface)}\n.kyogijo.ky-target-field .ky-tg-bg{fill:var(--ky-apron)}\n.kyogijo .ky-tg-open{fill:var(--ky-zone);opacity:.55}\n.kyogijo.ky-target-field .ky-tg-open{fill:var(--ky-surface);opacity:.5}\n.kyogijo .ky-tg-cell{fill:none;stroke:var(--ky-line);opacity:.6}\n.kyogijo .ky-tg-out{fill:none;stroke:var(--ky-line);opacity:.4}\n.kyogijo .ky-tg-cell:hover,.kyogijo .ky-tg-out:hover{opacity:1}\n.kyogijo .ky-tg-label{fill:var(--ky-line);font-family:var(--ky-font);font-weight:700;opacity:.85;text-anchor:middle;pointer-events:none}\n.kyogijo .ky-tg-frame{fill:none;stroke:var(--ky-line);stroke-linejoin:round;stroke-linecap:round}\n.kyogijo .ky-tg-solid{fill:var(--ky-line);stroke:none}\n.kyogijo .ky-tg-net{stroke:var(--ky-line);opacity:.3}\n.kyogijo .ky-tg-mark{fill:var(--ky-line);font-family:var(--ky-font);font-weight:800;text-anchor:middle;opacity:.9}\n.kyogijo .ky-tg-ink.ky-tg-cell,.kyogijo .ky-tg-ink.ky-tg-out,.kyogijo .ky-tg-ink.ky-tg-frame{stroke:var(--ky-ink)}\n.kyogijo .ky-tg-ink.ky-tg-solid,.kyogijo .ky-tg-ink.ky-tg-mark{fill:var(--ky-ink)}\n"; /** Draw a goal, the stumps or a strike zone with shots laid on it. */ export declare function drawTarget(shots: readonly TargetShot[], options: TargetOptions): TargetDrawing; /** * The mouth of a goal seen from the shooter's side, with the shots laid on it: where each crossed the goal line (`x` across from the middle, positive to the shooter's right, and `z` up). A shot wide of the posts or over the bar is drawn * outside the frame, a post or crossbar on it; the nine zones (the top shelf and the five-hole in hockey, the top corners and the bottom corners everywhere) are drawn when asked and counted in `zones`. * @example * ```ts * import { drawGoalMouth } from "@johnmorrisdotca/kyogijo-stadiums/target"; * const view = drawGoalMouth( * [ * { x: -2.4, z: 3.6, outcome: "goal" }, * { x: 0, z: 0.4, outcome: "saved" }, * { x: 3.4, z: 2, outcome: "wide" }, * ], * { sport: "nhl", zones: true }, * ); * console.log(view.placed, view.zones["top-left-corner"], view.zones["wide-right"], view.target.width, view.target.height); * // 3 1 1 6 4 * ``` */ export declare function drawGoalMouth(shots: readonly TargetShot[], options: Omit & { sport: GoalSport; }): TargetDrawing; /** * The strike zone seen from the catcher's position: home plate's 17 inches across, the zone from the batter's knees to his belt (`bottom` and `top`, in feet), the nine cells of the zone (1 to 9, top left to bottom right as the catcher sees them) and * the four chase zones round them (11 to 14), the batter's side, and the pitches numbered in order, coloured by result or type and shaped by what became of them. The place is Statcast's `plate_x` and `plate_z`. * @example * ```ts * import { drawStrikeZone } from "@johnmorrisdotca/kyogijo-stadiums/target"; * const view = drawStrikeZone([ * { x: 0.1, z: 2.6, outcome: "called-strike", type: "FF" }, * { x: 1.3, z: 1.1, outcome: "ball", type: "SL" }, * { x: -0.4, z: 2.0, outcome: "swinging-strike", type: "SL" }, * ], { bats: "R" }); * console.log(view.placed, view.zones["zone-5"], view.zones["zone-13"] ?? 0, view.key.map((k) => k.id).join(" ")); * // 3 1 0 ball called-strike swinging-strike * ``` */ export declare function drawStrikeZone(pitches: readonly TargetShot[], options?: Omit): TargetDrawing; /** * The stumps seen from the bowler's end: three stumps across 9 inches and 28 inches high with the bails, the line zones either side of them, and the deliveries where they reached the stumps' line (`x` across, `z` up), each with the length it * pitched at if you give one (`length`): `lengthZoneOf` names its length zone. * @example * ```ts * import { drawStumps, lengthZoneOf } from "@johnmorrisdotca/kyogijo-stadiums/target"; * const view = drawStumps([{ x: 0.02, z: 0.4, outcome: "wicket", length: 5.1 }, { x: 0.5, z: 0.9, outcome: "dot", length: 7.4 }]); * console.log(view.zones["on-stumps"], view.zones["wide-right"], lengthZoneOf(5.1), lengthZoneOf(7.4)); * // 1 1 good-length short-of-a-length * ``` */ export declare function drawStumps(deliveries: readonly TargetShot[], options?: Omit): TargetDrawing;