@johnmorrisdotca/kyogijo-stadiums 0.0.0-stage → 0.4.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/CHANGELOG.md +129 -0
- package/LICENSE +21 -0
- package/NOTICE.md +293 -0
- package/README.md +600 -2
- package/dist/annotate.d.ts +47 -0
- package/dist/annotate.js +349 -0
- package/dist/atlas-entry.d.ts +4 -0
- package/dist/atlas-entry.js +3 -0
- package/dist/atlas.d.ts +131 -0
- package/dist/atlas.js +149 -0
- package/dist/background.d.ts +56 -0
- package/dist/background.js +127 -0
- package/dist/ballpark.d.ts +48 -0
- package/dist/ballpark.js +129 -0
- package/dist/canvas-entry.d.ts +2 -0
- package/dist/canvas-entry.js +2 -0
- package/dist/canvas.d.ts +85 -0
- package/dist/canvas.js +279 -0
- package/dist/charts-entry.d.ts +10 -0
- package/dist/charts-entry.js +8 -0
- package/dist/charts.baseball.d.ts +30 -0
- package/dist/charts.baseball.js +152 -0
- package/dist/charts.curling.d.ts +52 -0
- package/dist/charts.curling.js +196 -0
- package/dist/charts.d.ts +172 -0
- package/dist/charts.js +508 -0
- package/dist/charts.network.d.ts +66 -0
- package/dist/charts.network.js +64 -0
- package/dist/charts.soccer.d.ts +43 -0
- package/dist/charts.soccer.js +191 -0
- package/dist/charts.types.d.ts +396 -0
- package/dist/charts.types.js +1 -0
- package/dist/colour.d.ts +29 -0
- package/dist/colour.js +97 -0
- package/dist/common.d.ts +14 -0
- package/dist/common.js +32 -0
- package/dist/court.d.ts +89 -0
- package/dist/court.js +248 -0
- package/dist/courts.style.d.ts +20 -0
- package/dist/courts.style.js +54 -0
- package/dist/cricket.board.d.ts +18 -0
- package/dist/cricket.board.js +67 -0
- package/dist/curling.board.d.ts +24 -0
- package/dist/curling.board.js +147 -0
- package/dist/d3-entry.d.ts +3 -0
- package/dist/d3-entry.js +2 -0
- package/dist/d3.d.ts +45 -0
- package/dist/d3.js +56 -0
- package/dist/draw.d.ts +52 -0
- package/dist/draw.js +705 -0
- package/dist/element-define.d.ts +2 -0
- package/dist/element-define.js +4 -0
- package/dist/element-entry.d.ts +1 -0
- package/dist/element-entry.js +2 -0
- package/dist/element.d.ts +39 -0
- package/dist/element.js +321 -0
- package/dist/eras-entry.d.ts +2 -0
- package/dist/eras-entry.js +2 -0
- package/dist/eras.d.ts +204 -0
- package/dist/eras.js +396 -0
- package/dist/events-entry.d.ts +3 -0
- package/dist/events-entry.js +3 -0
- package/dist/events.d.ts +54 -0
- package/dist/events.data.d.ts +59 -0
- package/dist/events.data.js +297 -0
- package/dist/events.js +127 -0
- package/dist/features.d.ts +31 -0
- package/dist/features.js +284 -0
- package/dist/field.score.d.ts +5 -0
- package/dist/field.score.js +33 -0
- package/dist/fields/afl.d.ts +11 -0
- package/dist/fields/afl.js +103 -0
- package/dist/fields/cricket.d.ts +9 -0
- package/dist/fields/cricket.js +81 -0
- package/dist/fields/fieldhockey.d.ts +6 -0
- package/dist/fields/fieldhockey.js +81 -0
- package/dist/fields/gaelic.d.ts +10 -0
- package/dist/fields/gaelic.js +86 -0
- package/dist/fields/handball.d.ts +6 -0
- package/dist/fields/handball.js +85 -0
- package/dist/fields/lacrosse.d.ts +17 -0
- package/dist/fields/lacrosse.js +169 -0
- package/dist/fields/rugby.d.ts +10 -0
- package/dist/fields/rugby.js +130 -0
- package/dist/fields.d.ts +12 -0
- package/dist/fields.js +44 -0
- package/dist/fields.kit.d.ts +63 -0
- package/dist/fields.kit.js +108 -0
- package/dist/fields.style.d.ts +4 -0
- package/dist/fields.style.js +19 -0
- package/dist/fields.types.d.ts +155 -0
- package/dist/fields.types.js +1 -0
- package/dist/format.d.ts +10 -0
- package/dist/format.js +28 -0
- package/dist/formations.d.ts +18 -0
- package/dist/formations.js +211 -0
- package/dist/frames-entry.d.ts +8 -0
- package/dist/frames-entry.js +7 -0
- package/dist/frames.d.ts +199 -0
- package/dist/frames.js +271 -0
- package/dist/frames.providers.d.ts +16 -0
- package/dist/frames.providers.js +302 -0
- package/dist/geojson-entry.d.ts +2 -0
- package/dist/geojson-entry.js +2 -0
- package/dist/geojson.d.ts +79 -0
- package/dist/geojson.js +147 -0
- package/dist/geometry-entry.d.ts +7 -0
- package/dist/geometry-entry.js +5 -0
- package/dist/geometry.d.ts +295 -0
- package/dist/geometry.js +361 -0
- package/dist/grounds-entry.d.ts +4 -0
- package/dist/grounds-entry.js +3 -0
- package/dist/grounds.d.ts +134 -0
- package/dist/grounds.data.d.ts +2 -0
- package/dist/grounds.data.js +1849 -0
- package/dist/grounds.js +74 -0
- package/dist/heat.colour.d.ts +37 -0
- package/dist/heat.colour.js +54 -0
- package/dist/heat.d.ts +43 -0
- package/dist/heat.js +614 -0
- package/dist/heat.stats.d.ts +123 -0
- package/dist/heat.stats.js +413 -0
- package/dist/heat.types.d.ts +145 -0
- package/dist/heat.types.js +1 -0
- package/dist/heat.zones.d.ts +54 -0
- package/dist/heat.zones.js +424 -0
- package/dist/homeside.d.ts +16 -0
- package/dist/homeside.js +43 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +29 -0
- package/dist/layers-entry.d.ts +19 -0
- package/dist/layers-entry.js +11 -0
- package/dist/layers.d.ts +41 -0
- package/dist/layers.env.d.ts +72 -0
- package/dist/layers.env.js +79 -0
- package/dist/layers.js +533 -0
- package/dist/layers.marks.d.ts +45 -0
- package/dist/layers.marks.js +168 -0
- package/dist/layers.types.d.ts +226 -0
- package/dist/layers.types.js +1 -0
- package/dist/layout.d.ts +97 -0
- package/dist/layout.js +381 -0
- package/dist/layout.style.d.ts +6 -0
- package/dist/layout.style.js +17 -0
- package/dist/layouts-entry.d.ts +5 -0
- package/dist/layouts-entry.js +4 -0
- package/dist/leagues/aussie.d.ts +57 -0
- package/dist/leagues/aussie.js +36 -0
- package/dist/leagues/baseball.d.ts +58 -0
- package/dist/leagues/baseball.js +171 -0
- package/dist/leagues/basketball.d.ts +67 -0
- package/dist/leagues/basketball.js +128 -0
- package/dist/leagues/courts.d.ts +212 -0
- package/dist/leagues/courts.js +114 -0
- package/dist/leagues/cricket.d.ts +45 -0
- package/dist/leagues/cricket.js +34 -0
- package/dist/leagues/curling.d.ts +64 -0
- package/dist/leagues/curling.js +53 -0
- package/dist/leagues/fieldhockey.d.ts +48 -0
- package/dist/leagues/fieldhockey.js +29 -0
- package/dist/leagues/fields.d.ts +10 -0
- package/dist/leagues/fields.js +6 -0
- package/dist/leagues/football.d.ts +8 -0
- package/dist/leagues/football.js +82 -0
- package/dist/leagues/gaelic.d.ts +50 -0
- package/dist/leagues/gaelic.js +29 -0
- package/dist/leagues/handball.d.ts +45 -0
- package/dist/leagues/handball.js +32 -0
- package/dist/leagues/hockey.d.ts +63 -0
- package/dist/leagues/hockey.js +166 -0
- package/dist/leagues/lacrosse.d.ts +103 -0
- package/dist/leagues/lacrosse.js +175 -0
- package/dist/leagues/rugby.d.ts +59 -0
- package/dist/leagues/rugby.js +72 -0
- package/dist/leagues/sources.d.ts +18 -0
- package/dist/leagues/sources.js +95 -0
- package/dist/leagues/types.d.ts +43 -0
- package/dist/leagues/types.js +5 -0
- package/dist/leagues-entry.d.ts +23 -0
- package/dist/leagues-entry.js +15 -0
- package/dist/leagues.d.ts +172 -0
- package/dist/leagues.js +462 -0
- package/dist/look.d.ts +50 -0
- package/dist/look.js +186 -0
- package/dist/mark.d.ts +35 -0
- package/dist/mark.js +59 -0
- package/dist/mount-entry.d.ts +2 -0
- package/dist/mount-entry.js +2 -0
- package/dist/mount.d.ts +63 -0
- package/dist/mount.js +167 -0
- package/dist/mow.d.ts +36 -0
- package/dist/mow.js +111 -0
- package/dist/names.d.ts +77 -0
- package/dist/names.js +97 -0
- package/dist/outline.d.ts +25 -0
- package/dist/outline.js +112 -0
- package/dist/parks-entry.d.ts +4 -0
- package/dist/parks-entry.js +3 -0
- package/dist/parks.d.ts +200 -0
- package/dist/parks.data.d.ts +2 -0
- package/dist/parks.data.js +4489 -0
- package/dist/parks.js +92 -0
- package/dist/plot-entry.d.ts +2 -0
- package/dist/plot-entry.js +2 -0
- package/dist/plot.d.ts +74 -0
- package/dist/plot.js +68 -0
- package/dist/png-entry.d.ts +2 -0
- package/dist/png-entry.js +2 -0
- package/dist/png.d.ts +26 -0
- package/dist/png.js +46 -0
- package/dist/ranges.d.ts +33 -0
- package/dist/ranges.js +178 -0
- package/dist/ranges.names.d.ts +31 -0
- package/dist/ranges.names.js +65 -0
- package/dist/react-entry.d.ts +2 -0
- package/dist/react-entry.js +2 -0
- package/dist/react.d.ts +53 -0
- package/dist/react.js +58 -0
- package/dist/replay-entry.d.ts +5 -0
- package/dist/replay-entry.js +4 -0
- package/dist/replay.control.d.ts +47 -0
- package/dist/replay.control.js +184 -0
- package/dist/replay.d.ts +170 -0
- package/dist/replay.dom.d.ts +21 -0
- package/dist/replay.dom.js +388 -0
- package/dist/replay.js +579 -0
- package/dist/replay.types.d.ts +152 -0
- package/dist/replay.types.js +1 -0
- package/dist/restyle.d.ts +21 -0
- package/dist/restyle.js +70 -0
- package/dist/road.d.ts +26 -0
- package/dist/road.draw.d.ts +6 -0
- package/dist/road.draw.js +269 -0
- package/dist/road.js +59 -0
- package/dist/road.model.d.ts +63 -0
- package/dist/road.model.js +215 -0
- package/dist/road.style.d.ts +7 -0
- package/dist/road.style.js +26 -0
- package/dist/road.types.d.ts +122 -0
- package/dist/road.types.js +1 -0
- package/dist/scene-entry.d.ts +7 -0
- package/dist/scene-entry.js +5 -0
- package/dist/scene.css.d.ts +44 -0
- package/dist/scene.css.js +296 -0
- package/dist/scene.d.ts +27 -0
- package/dist/scene.fit.d.ts +12 -0
- package/dist/scene.fit.js +18 -0
- package/dist/scene.flat.d.ts +38 -0
- package/dist/scene.flat.js +167 -0
- package/dist/scene.js +420 -0
- package/dist/scene.path.d.ts +40 -0
- package/dist/scene.path.js +357 -0
- package/dist/scene.types.d.ts +172 -0
- package/dist/scene.types.js +1 -0
- package/dist/scene.xml.d.ts +31 -0
- package/dist/scene.xml.js +81 -0
- package/dist/score.d.ts +70 -0
- package/dist/score.js +212 -0
- package/dist/sets.board.d.ts +22 -0
- package/dist/sets.board.js +89 -0
- package/dist/sheet.d.ts +18 -0
- package/dist/sheet.js +38 -0
- package/dist/special.d.ts +44 -0
- package/dist/special.js +204 -0
- package/dist/special.style.d.ts +8 -0
- package/dist/special.style.js +36 -0
- package/dist/strings.d.ts +581 -0
- package/dist/strings.js +411 -0
- package/dist/style.d.ts +35 -0
- package/dist/style.js +177 -0
- package/dist/surfaces/baseball.d.ts +33 -0
- package/dist/surfaces/baseball.js +208 -0
- package/dist/surfaces/baseball.walls.d.ts +16 -0
- package/dist/surfaces/baseball.walls.js +150 -0
- package/dist/surfaces/basketball.d.ts +8 -0
- package/dist/surfaces/basketball.js +199 -0
- package/dist/surfaces/curling.d.ts +23 -0
- package/dist/surfaces/curling.js +128 -0
- package/dist/surfaces/field.d.ts +12 -0
- package/dist/surfaces/field.js +163 -0
- package/dist/surfaces/football.d.ts +12 -0
- package/dist/surfaces/football.js +208 -0
- package/dist/surfaces/hockey.d.ts +10 -0
- package/dist/surfaces/hockey.js +166 -0
- package/dist/surfaces/net.d.ts +7 -0
- package/dist/surfaces/net.js +151 -0
- package/dist/surfaces/soccer-providers.d.ts +124 -0
- package/dist/surfaces/soccer-providers.js +334 -0
- package/dist/surfaces/soccer-spec.d.ts +138 -0
- package/dist/surfaces/soccer-spec.js +175 -0
- package/dist/surfaces/soccer.d.ts +25 -0
- package/dist/surfaces/soccer.js +270 -0
- package/dist/surfaces/surface.d.ts +180 -0
- package/dist/surfaces/surface.js +49 -0
- package/dist/team.common.d.ts +75 -0
- package/dist/team.common.js +97 -0
- package/dist/team.formation.d.ts +24 -0
- package/dist/team.formation.js +121 -0
- package/dist/team.geometry.d.ts +66 -0
- package/dist/team.geometry.js +304 -0
- package/dist/team.layers.d.ts +16 -0
- package/dist/team.layers.js +32 -0
- package/dist/team.motion.d.ts +9 -0
- package/dist/team.motion.js +325 -0
- package/dist/team.network.d.ts +43 -0
- package/dist/team.network.js +215 -0
- package/dist/team.shape.d.ts +12 -0
- package/dist/team.shape.js +217 -0
- package/dist/team.types.d.ts +189 -0
- package/dist/team.types.js +1 -0
- package/dist/text.d.ts +31 -0
- package/dist/text.js +88 -0
- package/dist/themes.d.ts +14 -0
- package/dist/themes.js +24 -0
- package/dist/types.d.ts +565 -0
- package/dist/types.js +1 -0
- package/dist/units.d.ts +45 -0
- package/dist/units.js +90 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/package.json +234 -4
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ScoreOptions, SurfaceOptions } from "./types.ts";
|
|
2
|
+
/** The drawing as the object React's `dangerouslySetInnerHTML` takes. */
|
|
3
|
+
export declare function kyogijoHtml(options: SurfaceOptions | ScoreOptions): {
|
|
4
|
+
__html: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Props for a `div` (or any element) that holds a drawing, to spread onto it: no component, no dependency on React.
|
|
8
|
+
* With `orientation: "auto"` and no `aspect`, the drawing is wide; use `createKyogijo` for a container that is measured.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { kyogijoProps } from "@johnmorrisdotca/kyogijo-stadiums/react";
|
|
12
|
+
* const props = kyogijoProps({ sport: "nba", away: { name: "Harbour City Gulls", score: 108 }, home: { name: "Prairie Ridge Bison", score: 112 }, status: "final" });
|
|
13
|
+
* console.log(props["data-kyogijo"], props.dangerouslySetInnerHTML.__html.startsWith("<svg"));
|
|
14
|
+
* // nba true
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function kyogijoProps(options: SurfaceOptions | ScoreOptions): {
|
|
18
|
+
dangerouslySetInnerHTML: {
|
|
19
|
+
__html: string;
|
|
20
|
+
};
|
|
21
|
+
"data-kyogijo": string;
|
|
22
|
+
"data-orientation": "landscape" | "portrait";
|
|
23
|
+
};
|
|
24
|
+
/** The part of React the component uses; pass the `React` you have, and nothing here imports it. */
|
|
25
|
+
export interface ReactLike {
|
|
26
|
+
createElement(type: string, props: Record<string, unknown> | null, ...children: unknown[]): unknown;
|
|
27
|
+
useRef<T>(initial: T): {
|
|
28
|
+
current: T;
|
|
29
|
+
};
|
|
30
|
+
useState<S>(initial: S): [S, (next: S) => void];
|
|
31
|
+
useEffect(effect: () => void | (() => void), deps?: unknown[]): void;
|
|
32
|
+
}
|
|
33
|
+
/** The props of the component `createKyogijo` makes: the options, and the usual `className` and `style` of its `div`. */
|
|
34
|
+
export type KyogijoProps = (SurfaceOptions | ScoreOptions) & {
|
|
35
|
+
containerClassName?: string;
|
|
36
|
+
containerStyle?: Record<string, unknown>;
|
|
37
|
+
breakpoint?: number;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* A React component made from the `React` you give it. It draws the options, and with `orientation: "auto"` measures its
|
|
41
|
+
* own box and lays the drawing out tall or wide as the box changes.
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { createKyogijo } from "@johnmorrisdotca/kyogijo-stadiums/react";
|
|
45
|
+
* // With React: `const Kyogijo = createKyogijo(React);` and then `<Kyogijo sport="nhl" orientation="auto" />`.
|
|
46
|
+
* // Here a stand-in for React, to show what comes out:
|
|
47
|
+
* const Kyogijo = createKyogijo({ createElement: (type, props) => ({ type, props }), useRef: (initial) => ({ current: initial }), useState: (initial) => [initial, () => {}], useEffect: () => {} });
|
|
48
|
+
* const element = Kyogijo({ sport: "nhl" }) as { type: string };
|
|
49
|
+
* console.log(element.type);
|
|
50
|
+
* // div
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function createKyogijo(React: ReactLike): (props: KyogijoProps) => unknown;
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { drawKyogijo, isPortrait } from "./draw.js";
|
|
2
|
+
import { containerAspect } from "./mount.js";
|
|
3
|
+
/** The drawing as the object React's `dangerouslySetInnerHTML` takes. */
|
|
4
|
+
export function kyogijoHtml(options) {
|
|
5
|
+
return { __html: drawKyogijo(options) };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Props for a `div` (or any element) that holds a drawing, to spread onto it: no component, no dependency on React.
|
|
9
|
+
* With `orientation: "auto"` and no `aspect`, the drawing is wide; use `createKyogijo` for a container that is measured.
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { kyogijoProps } from "@johnmorrisdotca/kyogijo-stadiums/react";
|
|
13
|
+
* const props = kyogijoProps({ sport: "nba", away: { name: "Harbour City Gulls", score: 108 }, home: { name: "Prairie Ridge Bison", score: 112 }, status: "final" });
|
|
14
|
+
* console.log(props["data-kyogijo"], props.dangerouslySetInnerHTML.__html.startsWith("<svg"));
|
|
15
|
+
* // nba true
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function kyogijoProps(options) {
|
|
19
|
+
return { dangerouslySetInnerHTML: kyogijoHtml(options), "data-kyogijo": options.sport, "data-orientation": isPortrait(options) ? "portrait" : "landscape" };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A React component made from the `React` you give it. It draws the options, and with `orientation: "auto"` measures its
|
|
23
|
+
* own box and lays the drawing out tall or wide as the box changes.
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { createKyogijo } from "@johnmorrisdotca/kyogijo-stadiums/react";
|
|
27
|
+
* // With React: `const Kyogijo = createKyogijo(React);` and then `<Kyogijo sport="nhl" orientation="auto" />`.
|
|
28
|
+
* // Here a stand-in for React, to show what comes out:
|
|
29
|
+
* const Kyogijo = createKyogijo({ createElement: (type, props) => ({ type, props }), useRef: (initial) => ({ current: initial }), useState: (initial) => [initial, () => {}], useEffect: () => {} });
|
|
30
|
+
* const element = Kyogijo({ sport: "nhl" }) as { type: string };
|
|
31
|
+
* console.log(element.type);
|
|
32
|
+
* // div
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function createKyogijo(React) {
|
|
36
|
+
return function Kyogijo(props) {
|
|
37
|
+
const { containerClassName, containerStyle, breakpoint, ...options } = props;
|
|
38
|
+
const ref = React.useRef(null);
|
|
39
|
+
const [aspect, setAspect] = React.useState(undefined);
|
|
40
|
+
const auto = options.orientation === "auto" && options.aspect === undefined;
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
if (!auto || ref.current === null || typeof ResizeObserver === "undefined")
|
|
43
|
+
return undefined;
|
|
44
|
+
const host = ref.current;
|
|
45
|
+
const measure = () => {
|
|
46
|
+
const next = containerAspect(host, breakpoint);
|
|
47
|
+
if (next !== undefined)
|
|
48
|
+
setAspect(next < 1 ? 0.75 : 1.5);
|
|
49
|
+
};
|
|
50
|
+
measure();
|
|
51
|
+
const observer = new ResizeObserver(measure);
|
|
52
|
+
observer.observe(host);
|
|
53
|
+
return () => observer.disconnect();
|
|
54
|
+
}, [auto, breakpoint]);
|
|
55
|
+
const drawn = { ...options, aspect: options.aspect ?? aspect };
|
|
56
|
+
return React.createElement("div", { ref, className: containerClassName, style: containerStyle, ...kyogijoProps(drawn) });
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { activeEvents, describeEvent, drawFrame, eventsBetween, interpolate, possession, replayClock, replayEvents, replayInfo, replayLayers, replaySnapshot, replaySummary, replayTable, replayTimes, trails } from "./replay.ts";
|
|
2
|
+
export type { ReplaySnapshot } from "./replay.ts";
|
|
3
|
+
export { REPLAY_SPEEDS, REPLAY_SPEED_RANGE, createReplay } from "./replay.control.ts";
|
|
4
|
+
export type { ReplayController } from "./replay.control.ts";
|
|
5
|
+
export type { ActiveEvent, Possession, ReplayChange, ReplayEvent, ReplayEventKind, ReplayFrame, ReplayLook, ReplayObject, ReplayReason, ReplaySettings, ReplayState, ReplayTeam, ReplayTimeline, ReplayTrail, } from "./replay.types.ts";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Replay: tracking data over time on a surface. The frame, the clock and the pure functions between them; the controls and the animation
|
|
2
|
+
// are in the mount (`mountKyogijo(...).replay(...)`) and in `<kyogijo-field>`.
|
|
3
|
+
export { activeEvents, describeEvent, drawFrame, eventsBetween, interpolate, possession, replayClock, replayEvents, replayInfo, replayLayers, replaySnapshot, replaySummary, replayTable, replayTimes, trails } from "./replay.js";
|
|
4
|
+
export { REPLAY_SPEEDS, REPLAY_SPEED_RANGE, createReplay } from "./replay.control.js";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ReplayChange, ReplaySettings, ReplayState, ReplayTimeline } from "./replay.types.ts";
|
|
2
|
+
/** The speeds the controls offer. Any speed from the least to the greatest is allowed. */
|
|
3
|
+
export declare const REPLAY_SPEEDS: readonly number[];
|
|
4
|
+
/** The slowest and the fastest speed of play. */
|
|
5
|
+
export declare const REPLAY_SPEED_RANGE: readonly [number, number];
|
|
6
|
+
/** What `createReplay` gives back. */
|
|
7
|
+
export interface ReplayController {
|
|
8
|
+
/** A copy of the state now. */
|
|
9
|
+
state(): Readonly<ReplayState>;
|
|
10
|
+
/** Start playing, from the start if it stopped at the end. In step mode, play moves one step and never plays by itself. */
|
|
11
|
+
play(): void;
|
|
12
|
+
pause(): void;
|
|
13
|
+
toggle(): void;
|
|
14
|
+
/** Go to a time, in seconds on the timeline's clock; held to the first and last moments. */
|
|
15
|
+
seek(t: number): void;
|
|
16
|
+
/** Pause and go to the next frame (1) or the one before (-1). In step mode, move `stepSeconds`. */
|
|
17
|
+
step(direction: 1 | -1): void;
|
|
18
|
+
/** Move by seconds, backward or forward. */
|
|
19
|
+
jump(seconds: number): void;
|
|
20
|
+
/** 0.25 to 4. */
|
|
21
|
+
setSpeed(speed: number): void;
|
|
22
|
+
setLoop(loop: boolean): void;
|
|
23
|
+
/** `step` for a reader who prefers reduced motion: playing stops, and play steps. */
|
|
24
|
+
setMotion(motion: "smooth" | "step"): void;
|
|
25
|
+
/** Tell the clock that seconds went by: while playing, the time moves by that many seconds times the speed. */
|
|
26
|
+
advance(seconds: number): void;
|
|
27
|
+
/** Be told of every change. Returns a function that stops it. */
|
|
28
|
+
subscribe(listener: (change: ReplayChange) => void): () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The controller of a replay: a state machine over a timeline's clock. It plays, pauses, seeks, steps by a frame, changes speed, loops, and says which
|
|
32
|
+
* events went by in each move so that they can be announced. It never reads a clock or the page: `advance(seconds)` is how time passes.
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { createReplay } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
36
|
+
* const frames = [0, 1, 2, 3, 4].map((t) => ({ t, objects: [{ id: "ball", team: "ball" as const, x: t * 10, y: 0 }] }));
|
|
37
|
+
* const replay = createReplay({ frames, events: [{ t: 2, kind: "goal" }] }, { speed: 2 });
|
|
38
|
+
* replay.play();
|
|
39
|
+
* replay.advance(1.5);
|
|
40
|
+
* console.log(replay.state().t, replay.state().playing);
|
|
41
|
+
* replay.advance(5);
|
|
42
|
+
* console.log(replay.state().t, replay.state().playing, replay.state().ended);
|
|
43
|
+
* // 3 true
|
|
44
|
+
* // 4 false true
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function createReplay(timeline: ReplayTimeline, settings?: ReplaySettings): ReplayController;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// The clock of a replay as a state machine: play, pause, seek, step, speed, loop, and what went by in each move. It knows nothing of the
|
|
2
|
+
// browser: the caller feeds it the seconds that passed (`advance`), which a test does with numbers and the page does from
|
|
3
|
+
// `requestAnimationFrame`. replay.dom.ts is the page's side.
|
|
4
|
+
import { eventsBetween, replayInfo, replayTimes } from "./replay.js";
|
|
5
|
+
/** The speeds the controls offer. Any speed from the least to the greatest is allowed. */
|
|
6
|
+
export const REPLAY_SPEEDS = [0.25, 0.5, 1, 2, 4];
|
|
7
|
+
/** The slowest and the fastest speed of play. */
|
|
8
|
+
export const REPLAY_SPEED_RANGE = [0.25, 4];
|
|
9
|
+
const EPS = 1e-9;
|
|
10
|
+
const clamp = (value, least, greatest) => Math.min(greatest, Math.max(least, value));
|
|
11
|
+
const isNum = (value) => typeof value === "number" && Number.isFinite(value);
|
|
12
|
+
/**
|
|
13
|
+
* The controller of a replay: a state machine over a timeline's clock. It plays, pauses, seeks, steps by a frame, changes speed, loops, and says which
|
|
14
|
+
* events went by in each move so that they can be announced. It never reads a clock or the page: `advance(seconds)` is how time passes.
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { createReplay } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
18
|
+
* const frames = [0, 1, 2, 3, 4].map((t) => ({ t, objects: [{ id: "ball", team: "ball" as const, x: t * 10, y: 0 }] }));
|
|
19
|
+
* const replay = createReplay({ frames, events: [{ t: 2, kind: "goal" }] }, { speed: 2 });
|
|
20
|
+
* replay.play();
|
|
21
|
+
* replay.advance(1.5);
|
|
22
|
+
* console.log(replay.state().t, replay.state().playing);
|
|
23
|
+
* replay.advance(5);
|
|
24
|
+
* console.log(replay.state().t, replay.state().playing, replay.state().ended);
|
|
25
|
+
* // 3 true
|
|
26
|
+
* // 4 false true
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function createReplay(timeline, settings = {}) {
|
|
30
|
+
const info = replayInfo(timeline);
|
|
31
|
+
const times = replayTimes(timeline);
|
|
32
|
+
const stepSeconds = isNum(settings.stepSeconds) && settings.stepSeconds > 0 ? settings.stepSeconds : 1;
|
|
33
|
+
const state = {
|
|
34
|
+
t: clamp(info.start + (isNum(settings.start) ? settings.start : 0), info.start, info.end),
|
|
35
|
+
start: info.start,
|
|
36
|
+
end: info.end,
|
|
37
|
+
playing: false,
|
|
38
|
+
ended: false,
|
|
39
|
+
speed: isNum(settings.speed) ? clamp(settings.speed, REPLAY_SPEED_RANGE[0], REPLAY_SPEED_RANGE[1]) : 1,
|
|
40
|
+
loop: settings.loop === true,
|
|
41
|
+
motion: settings.motion === "step" ? "step" : "smooth",
|
|
42
|
+
};
|
|
43
|
+
const listeners = new Set();
|
|
44
|
+
const tell = (reason, crossed = []) => {
|
|
45
|
+
const change = { state: { ...state }, reason, crossed };
|
|
46
|
+
for (const listener of [...listeners])
|
|
47
|
+
listener(change);
|
|
48
|
+
};
|
|
49
|
+
const over = (from, to) => (to > from ? eventsBetween(timeline, from, to) : []);
|
|
50
|
+
/** The first frame time after `t`, or the end. */
|
|
51
|
+
const after = (t) => {
|
|
52
|
+
let lo = 0;
|
|
53
|
+
let hi = times.length;
|
|
54
|
+
while (lo < hi) {
|
|
55
|
+
const mid = (lo + hi) >> 1;
|
|
56
|
+
if (times[mid] <= t + EPS)
|
|
57
|
+
lo = mid + 1;
|
|
58
|
+
else
|
|
59
|
+
hi = mid;
|
|
60
|
+
}
|
|
61
|
+
return lo < times.length ? times[lo] : state.end;
|
|
62
|
+
};
|
|
63
|
+
/** The last frame time before `t`, or the start. */
|
|
64
|
+
const before = (t) => {
|
|
65
|
+
let lo = 0;
|
|
66
|
+
let hi = times.length;
|
|
67
|
+
while (lo < hi) {
|
|
68
|
+
const mid = (lo + hi) >> 1;
|
|
69
|
+
if (times[mid] < t - EPS)
|
|
70
|
+
lo = mid + 1;
|
|
71
|
+
else
|
|
72
|
+
hi = mid;
|
|
73
|
+
}
|
|
74
|
+
return lo > 0 ? times[lo - 1] : state.start;
|
|
75
|
+
};
|
|
76
|
+
const controller = {
|
|
77
|
+
state: () => ({ ...state }),
|
|
78
|
+
play() {
|
|
79
|
+
if (state.motion === "step") {
|
|
80
|
+
controller.step(1);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (state.playing)
|
|
84
|
+
return;
|
|
85
|
+
if (state.t >= state.end - EPS && state.end > state.start)
|
|
86
|
+
state.t = state.start;
|
|
87
|
+
state.playing = true;
|
|
88
|
+
state.ended = false;
|
|
89
|
+
tell("play");
|
|
90
|
+
},
|
|
91
|
+
pause() {
|
|
92
|
+
if (!state.playing)
|
|
93
|
+
return;
|
|
94
|
+
state.playing = false;
|
|
95
|
+
tell("pause");
|
|
96
|
+
},
|
|
97
|
+
toggle() {
|
|
98
|
+
if (state.playing)
|
|
99
|
+
controller.pause();
|
|
100
|
+
else
|
|
101
|
+
controller.play();
|
|
102
|
+
},
|
|
103
|
+
seek(t) {
|
|
104
|
+
if (!isNum(t))
|
|
105
|
+
return;
|
|
106
|
+
state.t = clamp(t, state.start, state.end);
|
|
107
|
+
state.ended = false;
|
|
108
|
+
tell("seek");
|
|
109
|
+
},
|
|
110
|
+
step(direction) {
|
|
111
|
+
const was = state.playing;
|
|
112
|
+
state.playing = false;
|
|
113
|
+
const from = state.t;
|
|
114
|
+
let to;
|
|
115
|
+
if (state.motion === "step")
|
|
116
|
+
to = clamp(from + direction * stepSeconds, state.start, state.end);
|
|
117
|
+
else
|
|
118
|
+
to = direction > 0 ? after(from) : before(from);
|
|
119
|
+
if (to === from && !was)
|
|
120
|
+
return;
|
|
121
|
+
state.t = to;
|
|
122
|
+
state.ended = false;
|
|
123
|
+
tell("step", direction > 0 ? over(from, to) : []);
|
|
124
|
+
},
|
|
125
|
+
jump(seconds) {
|
|
126
|
+
if (isNum(seconds))
|
|
127
|
+
controller.seek(state.t + seconds);
|
|
128
|
+
},
|
|
129
|
+
setSpeed(speed) {
|
|
130
|
+
if (!isNum(speed))
|
|
131
|
+
return;
|
|
132
|
+
const next = clamp(speed, REPLAY_SPEED_RANGE[0], REPLAY_SPEED_RANGE[1]);
|
|
133
|
+
if (next === state.speed)
|
|
134
|
+
return;
|
|
135
|
+
state.speed = next;
|
|
136
|
+
tell("speed");
|
|
137
|
+
},
|
|
138
|
+
setLoop(loop) {
|
|
139
|
+
if (state.loop === loop)
|
|
140
|
+
return;
|
|
141
|
+
state.loop = loop;
|
|
142
|
+
tell("loop");
|
|
143
|
+
},
|
|
144
|
+
setMotion(motion) {
|
|
145
|
+
if (state.motion === motion)
|
|
146
|
+
return;
|
|
147
|
+
state.motion = motion;
|
|
148
|
+
state.playing = false;
|
|
149
|
+
tell("motion");
|
|
150
|
+
},
|
|
151
|
+
advance(seconds) {
|
|
152
|
+
if (!state.playing || state.motion === "step" || !isNum(seconds) || seconds <= 0)
|
|
153
|
+
return;
|
|
154
|
+
const from = state.t;
|
|
155
|
+
const to = from + seconds * state.speed;
|
|
156
|
+
if (to < state.end - EPS || (state.loop && state.end > state.start && to < state.end + EPS)) {
|
|
157
|
+
state.t = to;
|
|
158
|
+
tell("tick", over(from, to));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (state.loop && state.end > state.start) {
|
|
162
|
+
// Past the end: the rest of the clock goes round from the start, however many times it fits.
|
|
163
|
+
const length = state.end - state.start;
|
|
164
|
+
const wrapped = (to - state.start) % length;
|
|
165
|
+
state.t = state.start + wrapped;
|
|
166
|
+
// Everything from `from` to the end went by, and then everything from the start to where the clock is now.
|
|
167
|
+
const crossed = [...over(from, state.end), ...eventsBetween(timeline, state.start - 1, state.start + wrapped)];
|
|
168
|
+
tell("tick", crossed);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
state.t = state.end;
|
|
172
|
+
state.playing = false;
|
|
173
|
+
state.ended = true;
|
|
174
|
+
tell("tick", over(from, state.end));
|
|
175
|
+
},
|
|
176
|
+
subscribe(listener) {
|
|
177
|
+
listeners.add(listener);
|
|
178
|
+
return () => {
|
|
179
|
+
listeners.delete(listener);
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
return controller;
|
|
184
|
+
}
|
package/dist/replay.d.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { Layer } from "./layers.types.ts";
|
|
2
|
+
import type { ActiveEvent, Possession, ReplayEvent, ReplayLook, ReplayObject, ReplayTeam, ReplayTimeline, ReplayTrail } from "./replay.types.ts";
|
|
3
|
+
import { type KyogijoWords } from "./strings.ts";
|
|
4
|
+
import type { Language, ScoreOptions, SurfaceOptions } from "./types.ts";
|
|
5
|
+
type P = [number, number];
|
|
6
|
+
/** Seconds as a clock, `0:12` or `1:05:09`. */
|
|
7
|
+
export declare function replayClock(seconds: number): string;
|
|
8
|
+
/** Seconds as it is said aloud, in the words of the language: `0:12` in English and `12秒` in Japanese, where a clock would be read as a time of day. */
|
|
9
|
+
export declare function replaySpoken(seconds: number, w: KyogijoWords["replay"]): string;
|
|
10
|
+
/** The first and last moments of a timeline, how long it is, how many frames and objects it has, and the usual gap between frames, all in seconds. */
|
|
11
|
+
export declare function replayInfo(timeline: ReplayTimeline): {
|
|
12
|
+
start: number;
|
|
13
|
+
end: number;
|
|
14
|
+
duration: number;
|
|
15
|
+
frames: number;
|
|
16
|
+
objects: number;
|
|
17
|
+
events: number;
|
|
18
|
+
step: number;
|
|
19
|
+
};
|
|
20
|
+
/** The times of the frames, and of the events, in order: the moments a step can land on. */
|
|
21
|
+
export declare function replayTimes(timeline: ReplayTimeline): readonly number[];
|
|
22
|
+
/** The events of a timeline, in time order. */
|
|
23
|
+
export declare function replayEvents(timeline: ReplayTimeline): readonly ReplayEvent[];
|
|
24
|
+
/**
|
|
25
|
+
* Where everything is at a time: each object of the frame at or before `t` placed between that frame and the next, in a straight line or, with
|
|
26
|
+
* `smooth`, along a curve through the frames. An object in both frames moves; one only in the earlier frame stays put until the next; one only in
|
|
27
|
+
* the later frame appears when its frame comes. `t` is held to the first and last moments. The objects keep the order of their first appearance.
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { interpolate } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
31
|
+
* import type { ReplayTimeline } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
32
|
+
* const timeline: ReplayTimeline = { frames: [
|
|
33
|
+
* { t: 0, objects: [{ id: "ball", team: "ball", x: 100, y: 40 }] },
|
|
34
|
+
* { t: 2, objects: [{ id: "ball", team: "ball", x: 140, y: 20 }] },
|
|
35
|
+
* ] };
|
|
36
|
+
* console.log(interpolate(timeline, 0.5).map((o) => `${o.id} ${o.x} ${o.y}`).join());
|
|
37
|
+
* // ball 110 35
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function interpolate(timeline: ReplayTimeline, t: number, options?: {
|
|
41
|
+
smooth?: boolean | number;
|
|
42
|
+
}): ReplayObject[];
|
|
43
|
+
/**
|
|
44
|
+
* The path each object took over the last `seconds` before `t`, oldest place first and ending at its place at `t`: the frames in between, and the places at the two ends.
|
|
45
|
+
* Only objects that are there at `t` have a trail. `teams` and `ids` choose whose; all by default.
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { trails } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
49
|
+
* import type { ReplayTimeline } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
50
|
+
* const timeline: ReplayTimeline = { frames: [0, 1, 2, 3].map((t) => ({ t, objects: [{ id: "puck", team: "puck", x: t * 10, y: 0 }] })) };
|
|
51
|
+
* console.log(trails(timeline, 3, 2)[0].points.map((point) => point[0]).join());
|
|
52
|
+
* // 10,20,30
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function trails(timeline: ReplayTimeline, t: number, seconds: number, options?: {
|
|
56
|
+
teams?: readonly ReplayTeam[];
|
|
57
|
+
ids?: readonly string[];
|
|
58
|
+
smooth?: boolean | number;
|
|
59
|
+
}): ReplayTrail[];
|
|
60
|
+
/**
|
|
61
|
+
* Who has the ball at a time, when the data says: the `possession` of the latest frame at or before `t` that has one. `undefined` when no frame
|
|
62
|
+
* says, or when the latest says nobody does (`null`).
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* import { possession } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
66
|
+
* import type { ReplayTimeline } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
67
|
+
* const timeline: ReplayTimeline = { frames: [
|
|
68
|
+
* { t: 0, possession: "h7", objects: [{ id: "h7", team: "home", x: 1, y: 1 }, { id: "ball", team: "ball", x: 1, y: 1 }] },
|
|
69
|
+
* { t: 1, possession: null, objects: [{ id: "h7", team: "home", x: 2, y: 1 }, { id: "ball", team: "ball", x: 5, y: 1 }] },
|
|
70
|
+
* ] };
|
|
71
|
+
* console.log(possession(timeline, 0.5), possession(timeline, 1));
|
|
72
|
+
* // { holder: 'h7', team: 'home' } undefined
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare function possession(timeline: ReplayTimeline, t: number): Possession | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* The events that are on the surface at a time: from the moment of each until `hold` seconds after it ends (3 by default), with their places worked out.
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { activeEvents } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
81
|
+
* const ball = { id: "ball", team: "ball" as const, x: 10, y: 10 };
|
|
82
|
+
* const timeline = { frames: [{ t: 0, objects: [ball] }, { t: 10, objects: [ball] }], events: [{ t: 4, kind: "goal", team: "home" as const }] };
|
|
83
|
+
* console.log(activeEvents(timeline, 3).length, activeEvents(timeline, 5).map((a) => a.event.kind).join(), activeEvents(timeline, 9).length);
|
|
84
|
+
* // 0 goal 0
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare function activeEvents(timeline: ReplayTimeline, t: number, hold?: number, smooth?: boolean | number): ActiveEvent[];
|
|
88
|
+
/** The events with a time in `(from, to]`, for the live region: what went by while the clock moved from `from` to `to`. */
|
|
89
|
+
export declare function eventsBetween(timeline: ReplayTimeline, from: number, to: number): ReplayEvent[];
|
|
90
|
+
/**
|
|
91
|
+
* What is said of an event, for a live region and a tooltip: its `label`, else the word for its kind and its team, then the time.
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* import { describeEvent } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
95
|
+
* console.log(describeEvent({ t: 72, kind: "goal", team: "home" }));
|
|
96
|
+
* console.log(describeEvent({ t: 72, kind: "goal", team: "home" }, "ja"));
|
|
97
|
+
* // Goal, home, 1:12
|
|
98
|
+
* // ホームのゴール、1分12秒
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export declare function describeEvent(event: ReplayEvent, language?: Language, start?: number): string;
|
|
102
|
+
/** The same frame of a timeline always draws the same layers: this is what a frame is, before it is drawn. */
|
|
103
|
+
export interface ReplaySnapshot {
|
|
104
|
+
t: number;
|
|
105
|
+
objects: ReplayObject[];
|
|
106
|
+
trails: ReplayTrail[];
|
|
107
|
+
events: ActiveEvent[];
|
|
108
|
+
}
|
|
109
|
+
/** What is on the surface at a time: the objects, the trails behind the ones `look.trailOf` names, and the events. */
|
|
110
|
+
export declare function replaySnapshot(timeline: ReplayTimeline, t: number, look?: ReplayLook): ReplaySnapshot;
|
|
111
|
+
/** What a layer of the frame holds: for each mark its key, and where it is in the timeline's frame, so that the browser can move it without drawing again. */
|
|
112
|
+
export interface ReplayGroup {
|
|
113
|
+
/** The layer's id, `replay-players`. */
|
|
114
|
+
id: string;
|
|
115
|
+
layer: Layer;
|
|
116
|
+
/** Whether the marks move with the clock (the objects, their numbers and trails); an event's marks stay where they are put. */
|
|
117
|
+
moving: boolean;
|
|
118
|
+
kind: "points" | "text" | "lines";
|
|
119
|
+
keys: string[];
|
|
120
|
+
/** Where each mark is, in the timeline's frame: a place for a point or a text, the places of a path for a line. */
|
|
121
|
+
coords: (P | P[])[];
|
|
122
|
+
}
|
|
123
|
+
/** The groups of a frame, in the order they are drawn: trails, event lines, event marks, officials, players, their numbers, then the ball and the puck on top. */
|
|
124
|
+
export declare function replayGroups(timeline: ReplayTimeline, snap: ReplaySnapshot, look?: ReplayLook, language?: Language): ReplayGroup[];
|
|
125
|
+
/** The data layers of one frame, to put in a drawing's `layers` (after your own): the trails, the events' marks, the players with their numbers, the ball. */
|
|
126
|
+
export declare function replayLayers(timeline: ReplayTimeline, t: number, look?: ReplayLook, language?: Language): Layer[];
|
|
127
|
+
/** The sentence a replay adds to the drawing's description: its length, what it tracks and how many events it holds. It does not change with the time. */
|
|
128
|
+
export declare function replaySummary(timeline: ReplayTimeline, language?: Language): string;
|
|
129
|
+
/** A function that puts places in a timeline's frame on the surface of a drawing, in feet. */
|
|
130
|
+
export declare function replayPlacer(options: SurfaceOptions | ScoreOptions, timeline: ReplayTimeline): (points: readonly P[]) => P[];
|
|
131
|
+
/**
|
|
132
|
+
* One frame of a replay as an SVG string: the drawing `drawKyogijo` makes of `options`, with the players, their numbers, the ball and its trail, and
|
|
133
|
+
* the events that are on the surface at `t`, laid on it as data layers. The same options, timeline and time always give the same string. Without
|
|
134
|
+
* an `id` the drawing's ids come from the options and the timeline, not from the time, so that every frame of a replay has the same ids.
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* import { drawFrame } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
138
|
+
* import type { ReplayTimeline } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
139
|
+
* const timeline: ReplayTimeline = {
|
|
140
|
+
* from: "nhl-api",
|
|
141
|
+
* frames: [0, 1, 2].map((t) => ({ t, objects: [
|
|
142
|
+
* { id: "h1", team: "home", number: 9, x: 10 + t * 12, y: 5 },
|
|
143
|
+
* { id: "a1", team: "away", number: 4, x: 40 - t * 5, y: -8 },
|
|
144
|
+
* { id: "puck", team: "puck", x: 10 + t * 12, y: 5 },
|
|
145
|
+
* ] })),
|
|
146
|
+
* events: [{ t: 2, kind: "goal", team: "home", x: 34, y: 5 }],
|
|
147
|
+
* };
|
|
148
|
+
* const svg = drawFrame({ sport: "nhl" }, timeline, 1.5);
|
|
149
|
+
* console.log(svg.startsWith("<svg"), svg === drawFrame({ sport: "nhl" }, timeline, 1.5), svg.includes("Shirt numbers"));
|
|
150
|
+
* // true true true
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export declare function drawFrame(options: SurfaceOptions | ScoreOptions, timeline: ReplayTimeline, t: number, look?: ReplayLook): string;
|
|
154
|
+
/** The prefix of the ids in a replay's drawing when the options give none: a hash of the options and of the timeline's size, not of the time. */
|
|
155
|
+
export declare const replayId: (options: SurfaceOptions | ScoreOptions, timeline: ReplayTimeline) => string;
|
|
156
|
+
/**
|
|
157
|
+
* The events of a timeline as an HTML table, for a reader who cannot see the drawing: the time, the kind, the team and what is said of it. Every cell is escaped.
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* import { replayTable } from "@johnmorrisdotca/kyogijo-stadiums/replay";
|
|
161
|
+
* const html = replayTable({ frames: [{ t: 0, objects: [] }], events: [{ t: 12, kind: "goal", team: "home", label: "Goal, Rivera" }] });
|
|
162
|
+
* console.log(html.includes("<td>0:12</td>"), html.includes("Goal, Rivera"));
|
|
163
|
+
* // true true
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export declare function replayTable(timeline: ReplayTimeline, options?: {
|
|
167
|
+
language?: Language;
|
|
168
|
+
className?: string;
|
|
169
|
+
}): string;
|
|
170
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ReplayController } from "./replay.control.ts";
|
|
2
|
+
import type { ReplaySettings, ReplayTimeline } from "./replay.types.ts";
|
|
3
|
+
import type { ScoreOptions, SurfaceOptions } from "./types.ts";
|
|
4
|
+
/** The controls' stylesheet: written once beside the controls, scoped to them, in the page's own colours. */
|
|
5
|
+
export declare const REPLAY_STYLE: string;
|
|
6
|
+
/** A replay attached to a container: the controller, the stage the drawing goes in, and how to draw it again. */
|
|
7
|
+
export interface ReplayView {
|
|
8
|
+
controller: ReplayController;
|
|
9
|
+
/** The element the drawing is written into. */
|
|
10
|
+
stage: HTMLElement;
|
|
11
|
+
/** Draw the surface and the frame the clock is at, with new options (a theme that changed, a score that moved). */
|
|
12
|
+
draw(options: SurfaceOptions | ScoreOptions): void;
|
|
13
|
+
/** Stop the clock and the listeners, and empty the container. */
|
|
14
|
+
destroy(): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Attach a replay to a container: the stage with the drawing, the controls under it, the keyboard and the live region. The drawing is written once
|
|
18
|
+
* and then only the marks that move are moved, on `requestAnimationFrame`; a mark that comes or goes (an object that enters, an event that
|
|
19
|
+
* begins) redraws the replay's own layers, never the surface. With `prefers-reduced-motion` nothing plays by itself and play steps instead.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createReplayView(host: HTMLElement, timeline: ReplayTimeline, settings: ReplaySettings, initial: SurfaceOptions | ScoreOptions): ReplayView;
|