@sportsdataverse/sdvplot 0.0.0-stage → 0.2.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.
Files changed (245) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +109 -0
  3. package/README.md +984 -2
  4. package/dist/_web-D7Aa5Rd8.d.ts +69 -0
  5. package/dist/aaf-GJ3SH34T.js +13 -0
  6. package/dist/aaf-HCYN5T6Y.js +37 -0
  7. package/dist/aaf-ZAE5KS2Y.js +13 -0
  8. package/dist/ahl-E66MDVCU.js +66 -0
  9. package/dist/ahl-NPQQWZEV.js +249 -0
  10. package/dist/ahl-QRDU73XX.js +309 -0
  11. package/dist/axis-CraWQRUJ.d.ts +49 -0
  12. package/dist/bins.d.ts +174 -0
  13. package/dist/bins.js +4 -0
  14. package/dist/bins.js.map +1 -0
  15. package/dist/cfb-F42SVS4X.js +5000 -0
  16. package/dist/cfb-P3SHEYRZ.js +692 -0
  17. package/dist/cfb-WXRZANLP.js +10226 -0
  18. package/dist/chartjs-surface.d.ts +42 -0
  19. package/dist/chartjs-surface.js +65 -0
  20. package/dist/chartjs-surface.js.map +1 -0
  21. package/dist/chartjs.d.ts +162 -0
  22. package/dist/chartjs.js +342 -0
  23. package/dist/chartjs.js.map +1 -0
  24. package/dist/chunk-4C3GX6QO.js +92 -0
  25. package/dist/chunk-4C3GX6QO.js.map +1 -0
  26. package/dist/chunk-57WFSI4Q.js +128 -0
  27. package/dist/chunk-57WFSI4Q.js.map +1 -0
  28. package/dist/chunk-7ULOCCFL.js +313 -0
  29. package/dist/chunk-7ULOCCFL.js.map +1 -0
  30. package/dist/chunk-AMXASQHT.js +120 -0
  31. package/dist/chunk-AMXASQHT.js.map +1 -0
  32. package/dist/chunk-B2MP37SR.js +175 -0
  33. package/dist/chunk-B2MP37SR.js.map +1 -0
  34. package/dist/chunk-C2CDY5OG.js +137 -0
  35. package/dist/chunk-C2CDY5OG.js.map +1 -0
  36. package/dist/chunk-DYMUVE6K.js +127 -0
  37. package/dist/chunk-DYMUVE6K.js.map +1 -0
  38. package/dist/chunk-E7G7VSLV.js +43 -0
  39. package/dist/chunk-E7G7VSLV.js.map +1 -0
  40. package/dist/chunk-H2C3FMMA.js +300 -0
  41. package/dist/chunk-H2C3FMMA.js.map +1 -0
  42. package/dist/chunk-J4P4HDBF.js +175 -0
  43. package/dist/chunk-J4P4HDBF.js.map +1 -0
  44. package/dist/chunk-J6R2LEJ7.js +58 -0
  45. package/dist/chunk-J6R2LEJ7.js.map +1 -0
  46. package/dist/chunk-M3XD2OSN.js +132 -0
  47. package/dist/chunk-M3XD2OSN.js.map +1 -0
  48. package/dist/chunk-OIILARXI.js +30 -0
  49. package/dist/chunk-OIILARXI.js.map +1 -0
  50. package/dist/chunk-RPVVJY74.js +170 -0
  51. package/dist/chunk-RPVVJY74.js.map +1 -0
  52. package/dist/chunk-UL5M6KDE.js +205 -0
  53. package/dist/chunk-UL5M6KDE.js.map +1 -0
  54. package/dist/chunk-WQT4IVLX.js +10 -0
  55. package/dist/chunk-WQT4IVLX.js.map +1 -0
  56. package/dist/chunk-ZAEQXFJM.js +556 -0
  57. package/dist/chunk-ZAEQXFJM.js.map +1 -0
  58. package/dist/cricket-KPCYG2HL.js +493 -0
  59. package/dist/cricket-NDXLE25B.js +116 -0
  60. package/dist/cricket-YUUF7P6M.js +160 -0
  61. package/dist/cytoscape.d.ts +188 -0
  62. package/dist/cytoscape.js +219 -0
  63. package/dist/cytoscape.js.map +1 -0
  64. package/dist/d3.d.ts +234 -0
  65. package/dist/d3.js +198 -0
  66. package/dist/d3.js.map +1 -0
  67. package/dist/deckgl.d.ts +232 -0
  68. package/dist/deckgl.js +197 -0
  69. package/dist/deckgl.js.map +1 -0
  70. package/dist/echarts.d.ts +121 -0
  71. package/dist/echarts.js +228 -0
  72. package/dist/echarts.js.map +1 -0
  73. package/dist/echl-3CR4RGFC.js +241 -0
  74. package/dist/echl-NPC32C23.js +107 -0
  75. package/dist/echl-PI33DGJC.js +64 -0
  76. package/dist/export.d.ts +130 -0
  77. package/dist/export.js +258 -0
  78. package/dist/export.js.map +1 -0
  79. package/dist/g2.d.ts +251 -0
  80. package/dist/g2.js +102 -0
  81. package/dist/g2.js.map +1 -0
  82. package/dist/headshots-B2J_LOO8.d.ts +40 -0
  83. package/dist/index.d.ts +183 -0
  84. package/dist/index.js +9 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/interact.d.ts +567 -0
  87. package/dist/interact.js +809 -0
  88. package/dist/interact.js.map +1 -0
  89. package/dist/lightweight-charts.d.ts +217 -0
  90. package/dist/lightweight-charts.js +155 -0
  91. package/dist/lightweight-charts.js.map +1 -0
  92. package/dist/maplibre.d.ts +271 -0
  93. package/dist/maplibre.js +175 -0
  94. package/dist/maplibre.js.map +1 -0
  95. package/dist/marks-DH-tQIP-.d.ts +75 -0
  96. package/dist/mbb-3TRLVW3H.js +3619 -0
  97. package/dist/mbb-DQUHCHZP.js +5111 -0
  98. package/dist/mbb-PRAIO2P5.js +371 -0
  99. package/dist/milb-6IQ6NCEW.js +291 -0
  100. package/dist/milb-EYY5MD4T.js +1752 -0
  101. package/dist/milb-EYZ4SZLI.js +797 -0
  102. package/dist/mlb-4PBUJSVQ.js +35 -0
  103. package/dist/mlb-FHPY3GQJ.js +701 -0
  104. package/dist/mlb-REVGL3N2.js +665 -0
  105. package/dist/mui.d.ts +338 -0
  106. package/dist/mui.js +184 -0
  107. package/dist/mui.js.map +1 -0
  108. package/dist/nba-ATT775GS.js +485 -0
  109. package/dist/nba-LKM4UHVU.js +482 -0
  110. package/dist/nba-YX7PXM3R.js +35 -0
  111. package/dist/nbagl-3WGZCZ4S.js +37 -0
  112. package/dist/nbagl-LP4XJRAL.js +229 -0
  113. package/dist/nbagl-VTTOU7LN.js +499 -0
  114. package/dist/ncaa_baseball-UV75LNVR.js +2670 -0
  115. package/dist/ncaa_baseball-VD5J5C72.js +419 -0
  116. package/dist/ncaa_baseball-YRBS32D6.js +4592 -0
  117. package/dist/ncaa_mhockey-IMYHS7QS.js +1033 -0
  118. package/dist/ncaa_mhockey-TXTKWHE3.js +115 -0
  119. package/dist/ncaa_mhockey-U3MFW5VT.js +663 -0
  120. package/dist/ncaa_softball-6WR6KS64.js +420 -0
  121. package/dist/ncaa_softball-RZCTIE56.js +2654 -0
  122. package/dist/ncaa_softball-VOD4PVGY.js +4599 -0
  123. package/dist/ncaa_whockey-6XXGUTBK.js +607 -0
  124. package/dist/ncaa_whockey-AKKYKY67.js +53 -0
  125. package/dist/ncaa_whockey-KBEKXFBB.js +293 -0
  126. package/dist/nfl-BDB2HYAR.js +625 -0
  127. package/dist/nfl-EHYHDLJD.js +37 -0
  128. package/dist/nfl-VF4NJCHY.js +514 -0
  129. package/dist/nfl_gsis-UY64JO37.js +4 -0
  130. package/dist/nhl-6WPHME7H.js +511 -0
  131. package/dist/nhl-EMIJFZHY.js +884 -0
  132. package/dist/nhl-ISFUKRFU.js +37 -0
  133. package/dist/nivo.d.ts +193 -0
  134. package/dist/nivo.js +8 -0
  135. package/dist/nivo.js.map +1 -0
  136. package/dist/ohl-2FEM554G.js +113 -0
  137. package/dist/ohl-C5Q4W6JB.js +32 -0
  138. package/dist/ohl-TQ4J46VC.js +66 -0
  139. package/dist/perspective.d.ts +198 -0
  140. package/dist/perspective.js +171 -0
  141. package/dist/perspective.js.map +1 -0
  142. package/dist/phf-H7POU2KW.js +32 -0
  143. package/dist/phf-K5IFMZUM.js +13 -0
  144. package/dist/phf-TWJI3BOW.js +20 -0
  145. package/dist/placement-UWkqUzpa.d.ts +32 -0
  146. package/dist/plot.d.ts +451 -0
  147. package/dist/plot.js +712 -0
  148. package/dist/plot.js.map +1 -0
  149. package/dist/plotly.d.ts +129 -0
  150. package/dist/plotly.js +360 -0
  151. package/dist/plotly.js.map +1 -0
  152. package/dist/pwhl-OX3BO4JI.js +53 -0
  153. package/dist/pwhl-W44OC3C6.js +17 -0
  154. package/dist/pwhl-ZJGG3H7W.js +23 -0
  155. package/dist/qmjhl-5HISEHLL.js +35 -0
  156. package/dist/qmjhl-DA3UHKE5.js +125 -0
  157. package/dist/qmjhl-YG4BOQPF.js +614 -0
  158. package/dist/react.d.ts +377 -0
  159. package/dist/react.js +522 -0
  160. package/dist/react.js.map +1 -0
  161. package/dist/recharts.d.ts +162 -0
  162. package/dist/recharts.js +8 -0
  163. package/dist/recharts.js.map +1 -0
  164. package/dist/resolve-CQW-jzvr.d.ts +28 -0
  165. package/dist/selection-D4T3PkRt.d.ts +140 -0
  166. package/dist/shadcn.d.ts +83 -0
  167. package/dist/shadcn.js +88 -0
  168. package/dist/shadcn.js.map +1 -0
  169. package/dist/shots.d.ts +364 -0
  170. package/dist/shots.js +86 -0
  171. package/dist/shots.js.map +1 -0
  172. package/dist/soccer-7BH3ZLVL.js +7898 -0
  173. package/dist/soccer-MRU25OGE.js +2636 -0
  174. package/dist/soccer-PF4IPPVA.js +12342 -0
  175. package/dist/surface-TR7YFJW3.js +4 -0
  176. package/dist/surface-TR7YFJW3.js.map +1 -0
  177. package/dist/surfaces-MIG7HOFU.js +6 -0
  178. package/dist/surfaces-MIG7HOFU.js.map +1 -0
  179. package/dist/surfaces-W-odWLpT.d.ts +47 -0
  180. package/dist/svelte/HeadshotMark.svelte +25 -0
  181. package/dist/svelte/HeadshotMark.svelte.d.ts +10 -0
  182. package/dist/svelte/HeadshotMark.svelte.d.ts.map +1 -0
  183. package/dist/svelte/LogoMark.svelte +25 -0
  184. package/dist/svelte/LogoMark.svelte.d.ts +10 -0
  185. package/dist/svelte/LogoMark.svelte.d.ts.map +1 -0
  186. package/dist/svelte/Marks.svelte +25 -0
  187. package/dist/svelte/Marks.svelte.d.ts +10 -0
  188. package/dist/svelte/Marks.svelte.d.ts.map +1 -0
  189. package/dist/svelte/Surface.svelte +29 -0
  190. package/dist/svelte/Surface.svelte.d.ts +9 -0
  191. package/dist/svelte/Surface.svelte.d.ts.map +1 -0
  192. package/dist/svelte/SurfaceBackdrop.svelte +26 -0
  193. package/dist/svelte/SurfaceBackdrop.svelte.d.ts +11 -0
  194. package/dist/svelte/SurfaceBackdrop.svelte.d.ts.map +1 -0
  195. package/dist/svelte/index.d.ts +13 -0
  196. package/dist/svelte/index.d.ts.map +1 -0
  197. package/dist/svelte/index.js +11 -0
  198. package/dist/svelte-core.d.ts +139 -0
  199. package/dist/svelte-core.js +123 -0
  200. package/dist/svelte-core.js.map +1 -0
  201. package/dist/tanstack.d.ts +240 -0
  202. package/dist/tanstack.js +110 -0
  203. package/dist/tanstack.js.map +1 -0
  204. package/dist/testing.d.ts +75 -0
  205. package/dist/testing.js +239 -0
  206. package/dist/testing.js.map +1 -0
  207. package/dist/three.d.ts +223 -0
  208. package/dist/three.js +50 -0
  209. package/dist/three.js.map +1 -0
  210. package/dist/tiers-BN4md-GB.d.ts +65 -0
  211. package/dist/types-C7n6gJF3.d.ts +62 -0
  212. package/dist/ufl-7VLZTLTT.js +143 -0
  213. package/dist/ufl-CCMBLPSW.js +100 -0
  214. package/dist/ufl-F2BJRXME.js +16 -0
  215. package/dist/unovis.d.ts +127 -0
  216. package/dist/unovis.js +108 -0
  217. package/dist/unovis.js.map +1 -0
  218. package/dist/uplot.d.ts +120 -0
  219. package/dist/uplot.js +110 -0
  220. package/dist/uplot.js.map +1 -0
  221. package/dist/usfl-4CR5RMZJ.js +32 -0
  222. package/dist/usfl-LD7HP2YK.js +14 -0
  223. package/dist/usfl-VU4YSJQD.js +19 -0
  224. package/dist/ushl-CPG2LB4L.js +73 -0
  225. package/dist/ushl-PQL6HJAD.js +88 -0
  226. package/dist/ushl-ZT2ATPHK.js +22 -0
  227. package/dist/vega.d.ts +85 -0
  228. package/dist/vega.js +362 -0
  229. package/dist/vega.js.map +1 -0
  230. package/dist/victory.d.ts +107 -0
  231. package/dist/victory.js +38 -0
  232. package/dist/victory.js.map +1 -0
  233. package/dist/wbb-3KHCDYTK.js +5087 -0
  234. package/dist/wbb-BMX53Q3Q.js +369 -0
  235. package/dist/wbb-QNRN2CJJ.js +3620 -0
  236. package/dist/whl-4ATYZWUB.js +97 -0
  237. package/dist/whl-RVFPL6MH.js +79 -0
  238. package/dist/whl-Y7ASKYMM.js +28 -0
  239. package/dist/wnba-FWX5SFVI.js +232 -0
  240. package/dist/wnba-GX6HZR4B.js +220 -0
  241. package/dist/wnba-NTMWIPP6.js +20 -0
  242. package/dist/xfl-43R2JMJK.js +30 -0
  243. package/dist/xfl-H3BXQPZZ.js +16 -0
  244. package/dist/xfl-XON7A7FI.js +69 -0
  245. package/package.json +366 -3
@@ -0,0 +1,127 @@
1
+ import { E as EspnHeadshotLeague } from './headshots-B2J_LOO8.js';
2
+ import { W as Which, S as SeasonInput, I as IdSystem, H as HeadshotIdSystem, V as Variant, L as League } from './types-C7n6gJF3.js';
3
+ import './resolve-CQW-jzvr.js';
4
+
5
+ /** `teamColorPalette` / `teamColorScale` options. */
6
+ interface UnovisColorOptions {
7
+ /** "primary" (default) or "secondary" colour. */
8
+ which?: Which;
9
+ /** The season the teams are resolved for (a number or string). */
10
+ season?: SeasonInput;
11
+ /** How the team values are read. Default "auto". */
12
+ idSystem?: IdSystem;
13
+ /** The colour of an unresolved team. Default "#808080". */
14
+ fallback?: string;
15
+ /**
16
+ * The chart's background. Given, a team colour under 3:1 contrast against it is swapped for the team's other
17
+ * colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A
18
+ * colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or
19
+ * the nearest colour to its own that is distinct and still reads; failing that it is kept, with one warning.
20
+ */
21
+ background?: string;
22
+ }
23
+ /**
24
+ * One colour per team, in order: an XY component's `color` (one per `y` accessor), or anything else that takes
25
+ * colours by position. With `background`, every colour keeps 3:1 contrast against it (dark mode) and aims to stay
26
+ * distinct from the others. `teamColorScale` gives the same colours keyed by team, for accessors.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
31
+ * import { teamColorPalette } from "@sportsdataverse/sdvplot/unovis";
32
+ *
33
+ * await loadLeague("nfl");
34
+ * // new Line({ x, y: [kc, phi], color: <this> })
35
+ * teamColorPalette("nfl", ["KC", "PHI"], { background: "#111827" });
36
+ * ```
37
+ */
38
+ declare function teamColorPalette(league: League, teams: readonly unknown[], o?: UnovisColorOptions): string[];
39
+ /** A team's colour: call it from a Unovis colour accessor with the team value the datum holds. */
40
+ interface UnovisTeamColorScale<T = unknown> {
41
+ /** The colour of `team`: its own for a team of the domain (by any value naming it), else `fallback`. */
42
+ (team: unknown): string;
43
+ /** The team values exactly as given (numbers stay numbers), each once and in order. */
44
+ readonly domain: readonly T[];
45
+ /** Their colours, in the same order. */
46
+ readonly range: readonly string[];
47
+ }
48
+ /**
49
+ * Team colours for Unovis's colour accessors: `color(d.team)` from a Graph's `nodeFill`, `nodeStroke` or
50
+ * `linkStroke`, a Sankey's `nodeColor` or `linkColor`, a Chord's `nodeColor`. Give every team the chart draws, so
51
+ * the colours are worked out together: with `background` they read on it (dark mode) and stay distinct. The domain
52
+ * keeps the values as the data holds them (12 and "12" are both kept); the colours are the resolved team's, so 12,
53
+ * "12" and "KC" draw in one colour. A value outside the domain gets `fallback`, with one warning.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
58
+ * import { teamColorScale } from "@sportsdataverse/sdvplot/unovis";
59
+ *
60
+ * await loadLeague("nfl");
61
+ * const color = teamColorScale("nfl", ["KC", "PHI"]);
62
+ * // new Sankey({ linkColor: (l) => color(l.team), ... })
63
+ * [color("KC"), color(21), color.range];
64
+ * ```
65
+ */
66
+ declare function teamColorScale<T>(league: League, teams: readonly T[], o?: UnovisColorOptions): UnovisTeamColorScale<T>;
67
+ /** `logoIcons` options. */
68
+ interface UnovisLogoOptions {
69
+ /** The season the teams are resolved for (a number or string). */
70
+ season?: SeasonInput;
71
+ /** Logo variant, e.g. "dark". Default "default". */
72
+ variant?: Variant;
73
+ /** How the team values are read. Default "auto". */
74
+ idSystem?: IdSystem;
75
+ }
76
+ /** `headshotIcons` options. */
77
+ interface UnovisHeadshotOptions {
78
+ /** ESPN athlete ids, or nflverse gsis ids (needs `loadGsis()` first). Default "espn". */
79
+ idSystem?: HeadshotIdSystem;
80
+ }
81
+ /** Images for a Graph's node icons: call it from `nodeIcon` with the team (or player) the node holds. */
82
+ interface UnovisIcons<T = unknown> {
83
+ /** `#<symbol id>` of the image of `value` (by any value naming the same team or player), else undefined. */
84
+ (value: unknown): string | undefined;
85
+ /** The values that have an image, as given (numbers stay numbers), each once and in order. */
86
+ readonly domain: readonly T[];
87
+ /** Their `#<symbol id>`s, in the same order. */
88
+ readonly range: readonly string[];
89
+ /** One `<symbol>` per image: the chart container's `svgDefs` (join two sets' with `+`). */
90
+ readonly svgDefs: string;
91
+ }
92
+ /**
93
+ * Team logos for a Unovis Graph's nodes: `nodeIcon: (n) => logos(n.team)`, with
94
+ * `svgDefs: logos.svgDefs` on the container. Unovis draws each icon as a `<use>` of the logo's `<symbol>`, `nodeIconSize` px across, the logo
95
+ * fitted inside, uncut; a node's fill shows round it. A team with no logo has no icon, with one warning. Every value
96
+ * naming a team finds its logo (12, "12" and "KC").
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
101
+ * import { logoIcons } from "@sportsdataverse/sdvplot/unovis";
102
+ *
103
+ * await loadLeague("nfl");
104
+ * const logos = logoIcons("nfl", ["KC", "LV"], { variant: "dark" });
105
+ * // new SingleContainer(el, { component: new Graph({ nodeIcon: (n) => logos(n.team), nodeIconSize: 28 }),
106
+ * // svgDefs: logos.svgDefs }, data)
107
+ * [logos("KC"), logos.range];
108
+ * ```
109
+ */
110
+ declare function logoIcons<T>(league: League, teams: readonly T[], o?: UnovisLogoOptions): UnovisIcons<T>;
111
+ /**
112
+ * ESPN player headshots for a Unovis Graph's nodes, as `logoIcons`: `nodeIcon: (n) => heads(n.player)`, with the
113
+ * container's `svgDefs: heads.svgDefs`. A gsis id with no headshot has no icon, with one warning; an ESPN id's URL is
114
+ * built without checking the image exists, so an id ESPN has no photo for keeps an empty icon, with no warning.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * import { headshotIcons } from "@sportsdataverse/sdvplot/unovis";
119
+ *
120
+ * // Patrick Mahomes and Travis Kelce, by ESPN athlete id
121
+ * const heads = headshotIcons("nfl", [3139477, 15847]);
122
+ * [heads(3139477), heads.svgDefs.length > 0];
123
+ * ```
124
+ */
125
+ declare function headshotIcons<T>(league: EspnHeadshotLeague, players: readonly T[], o?: UnovisHeadshotOptions): UnovisIcons<T>;
126
+
127
+ export { type UnovisColorOptions, type UnovisHeadshotOptions, type UnovisIcons, type UnovisLogoOptions, type UnovisTeamColorScale, headshotIcons, logoIcons, teamColorPalette, teamColorScale };
package/dist/unovis.js ADDED
@@ -0,0 +1,108 @@
1
+ import { contentId } from './chunk-WQT4IVLX.js';
2
+ import { colorPalette, imageSource, aspect } from './chunk-UL5M6KDE.js';
3
+ import { placeSync } from './chunk-7ULOCCFL.js';
4
+ import { resolveSync, normValue } from './chunk-ZAEQXFJM.js';
5
+ import './chunk-J6R2LEJ7.js';
6
+ import { warn } from './chunk-E7G7VSLV.js';
7
+
8
+ // src/unovis.ts
9
+ function teamColorPalette(league, teams, o = {}) {
10
+ return colorPalette(league, teams, o);
11
+ }
12
+ var keyOf = (v) => `${typeof v}:${String(v)}`;
13
+ function distinct(values) {
14
+ const seen = /* @__PURE__ */ new Map();
15
+ for (const v of values) if (!seen.has(keyOf(v))) seen.set(keyOf(v), v);
16
+ return [...seen.values()];
17
+ }
18
+ var shown = (v) => typeof v === "string" ? JSON.stringify(v) : String(v);
19
+ function teamColorScale(league, teams, o = {}) {
20
+ const domain = distinct(teams);
21
+ const ro = {
22
+ ...o.season === void 0 ? {} : { season: o.season },
23
+ ...o.idSystem === void 0 ? {} : { idSystem: o.idSystem }
24
+ };
25
+ const fallback = o.fallback ?? "#808080";
26
+ const ids = resolveSync(domain, league, ro);
27
+ const known = [...new Set(ids.filter((id) => id !== void 0))];
28
+ const palette = colorPalette(league, known, {
29
+ ...ro,
30
+ idSystem: "team_id",
31
+ ...o.which === void 0 ? {} : { which: o.which },
32
+ ...o.background === void 0 ? {} : { background: o.background },
33
+ fallback
34
+ });
35
+ const byTeam = new Map(known.map((id, j) => [id, palette[j]]));
36
+ const memo = new Map(domain.map((t, i) => [keyOf(t), byTeam.get(ids[i]) ?? fallback]));
37
+ const scale = (team) => {
38
+ const k = keyOf(team);
39
+ let c = memo.get(k);
40
+ if (c === void 0) {
41
+ const id = resolveSync(team, league, ro);
42
+ c = id === void 0 ? void 0 : byTeam.get(id);
43
+ if (c === void 0)
44
+ warn(
45
+ `unovis:${league}:color:${k}`,
46
+ `teamColorScale: ${shown(team)} is not one of its teams; drawn in ${fallback}`
47
+ );
48
+ c ??= fallback;
49
+ memo.set(k, c);
50
+ }
51
+ return c;
52
+ };
53
+ return Object.assign(scale, { domain, range: domain.map((t) => memo.get(keyOf(t))) });
54
+ }
55
+ var escapeAttr = (s) => s.replace(/[&<>"]/g, (c) => `&#${c.charCodeAt(0)};`);
56
+ var n = (v) => String(Math.round(v * 1e4) / 1e4);
57
+ function icons(kind, league, values, o) {
58
+ const given = distinct(values);
59
+ const at = given.map(() => 0);
60
+ const placed = placeSync(at, at, given, {
61
+ league,
62
+ kind,
63
+ ...o.season === void 0 ? {} : { season: o.season },
64
+ ...o.variant === void 0 ? {} : { variant: o.variant },
65
+ ...o.idSystem === void 0 ? {} : { idSystem: o.idSystem }
66
+ });
67
+ const idOf = (v) => kind === "headshot" ? o.idSystem === "gsis" ? String(v).trim() : normValue(v) ?? void 0 : resolveSync(v, league, {
68
+ ...o.season === void 0 ? {} : { season: o.season },
69
+ ...o.idSystem === void 0 ? {} : { idSystem: o.idSystem }
70
+ });
71
+ const byId = /* @__PURE__ */ new Map();
72
+ let svgDefs = "";
73
+ for (const p of placed) {
74
+ if (byId.has(p.id)) continue;
75
+ const href = imageSource(p);
76
+ const id = contentId(`sdv-${kind}`, href);
77
+ const w = 100 * aspect(p);
78
+ if (!svgDefs.includes(`id="${id}"`))
79
+ svgDefs += `<symbol id="${id}" viewBox="0 0 ${n(w)} 100" preserveAspectRatio="xMidYMid meet"><image href="${escapeAttr(href)}" width="${n(w)}" height="100" preserveAspectRatio="xMidYMid meet"/></symbol>`;
80
+ byId.set(p.id, `#${id}`);
81
+ }
82
+ const memo = new Map(
83
+ placed.map((p) => [keyOf(given[p.index]), byId.get(p.id)])
84
+ );
85
+ const icon = (value) => {
86
+ const k = keyOf(value);
87
+ if (!memo.has(k)) {
88
+ const id = value === null || value === void 0 ? void 0 : idOf(value);
89
+ memo.set(k, id === void 0 ? void 0 : byId.get(id));
90
+ }
91
+ return memo.get(k);
92
+ };
93
+ return Object.assign(icon, {
94
+ domain: placed.map((p) => given[p.index]),
95
+ range: placed.map((p) => byId.get(p.id)),
96
+ svgDefs
97
+ });
98
+ }
99
+ function logoIcons(league, teams, o = {}) {
100
+ return icons("logo", league, teams, o);
101
+ }
102
+ function headshotIcons(league, players, o = {}) {
103
+ return icons("headshot", league, players, o);
104
+ }
105
+
106
+ export { headshotIcons, logoIcons, teamColorPalette, teamColorScale };
107
+ //# sourceMappingURL=unovis.js.map
108
+ //# sourceMappingURL=unovis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/unovis.ts"],"names":[],"mappings":"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","file":"unovis.js","sourcesContent":["/**\n * The Unovis 1.7 adapter: accessor helpers in Unovis's own idiom, for `@unovis/ts` (plain JavaScript, Svelte, any\n * framework) and `@unovis/react`. Team colours as a function a colour accessor calls (`teamColorScale`: a Graph's\n * `nodeFill` / `nodeStroke` / `linkStroke`, a Sankey's `nodeColor` / `linkColor`, a Chord's `nodeColor`), or as a list\n * (`teamColorPalette`, for an XY component's `color`). Logos and headshots for a Graph's nodes (`logoIcons`,\n * `headshotIcons`): Unovis draws a node icon that starts with `#` as an SVG `<use>` of that id, and the icons' `svgDefs`\n * (for the container's `svgDefs`) hold one `<symbol>` per image. A Sankey's node icon is text only, so a Sankey takes\n * team colours, not logos. Pure: `@unovis/*` is never imported. Call after `loadLeague(league)` / `preloadAll()`.\n */\nimport { aspect, colorPalette, imageSource } from \"./_web.js\";\nimport { contentId } from \"./content-id.js\";\nimport { warn } from \"./errors.js\";\nimport type { EspnHeadshotLeague } from \"./headshots.js\";\nimport { normValue } from \"./normalize.js\";\nimport { type Kind, placeSync } from \"./placement.js\";\nimport { type Value, resolveSync } from \"./resolve.js\";\nimport type { HeadshotIdSystem, IdSystem, League, SeasonInput, Variant, Which } from \"./types.js\";\n\n/** `teamColorPalette` / `teamColorScale` options. */\nexport interface UnovisColorOptions {\n /** \"primary\" (default) or \"secondary\" colour. */\n which?: Which;\n /** The season the teams are resolved for (a number or string). */\n season?: SeasonInput;\n /** How the team values are read. Default \"auto\". */\n idSystem?: IdSystem;\n /** The colour of an unresolved team. Default \"#808080\". */\n fallback?: string;\n /**\n * The chart's background. Given, a team colour under 3:1 contrast against it is swapped for the team's other\n * colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A\n * colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or\n * the nearest colour to its own that is distinct and still reads; failing that it is kept, with one warning.\n */\n background?: string;\n}\n\n/**\n * One colour per team, in order: an XY component's `color` (one per `y` accessor), or anything else that takes\n * colours by position. With `background`, every colour keeps 3:1 contrast against it (dark mode) and aims to stay\n * distinct from the others. `teamColorScale` gives the same colours keyed by team, for accessors.\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamColorPalette } from \"@sportsdataverse/sdvplot/unovis\";\n *\n * await loadLeague(\"nfl\");\n * // new Line({ x, y: [kc, phi], color: <this> })\n * teamColorPalette(\"nfl\", [\"KC\", \"PHI\"], { background: \"#111827\" });\n * ```\n */\nexport function teamColorPalette(\n league: League,\n teams: readonly unknown[],\n o: UnovisColorOptions = {},\n): string[] {\n return colorPalette(league, teams, o);\n}\n\n/** A value's key as the data holds it: 12 and \"12\" are two keys, each kept. */\nconst keyOf = (v: unknown): string => `${typeof v}:${String(v)}`;\nfunction distinct<T>(values: readonly T[]): T[] {\n const seen = new Map<string, T>();\n for (const v of values) if (!seen.has(keyOf(v))) seen.set(keyOf(v), v);\n return [...seen.values()];\n}\nconst shown = (v: unknown): string => (typeof v === \"string\" ? JSON.stringify(v) : String(v));\n\n/** A team's colour: call it from a Unovis colour accessor with the team value the datum holds. */\nexport interface UnovisTeamColorScale<T = unknown> {\n /** The colour of `team`: its own for a team of the domain (by any value naming it), else `fallback`. */\n (team: unknown): string;\n /** The team values exactly as given (numbers stay numbers), each once and in order. */\n readonly domain: readonly T[];\n /** Their colours, in the same order. */\n readonly range: readonly string[];\n}\n/**\n * Team colours for Unovis's colour accessors: `color(d.team)` from a Graph's `nodeFill`, `nodeStroke` or\n * `linkStroke`, a Sankey's `nodeColor` or `linkColor`, a Chord's `nodeColor`. Give every team the chart draws, so\n * the colours are worked out together: with `background` they read on it (dark mode) and stay distinct. The domain\n * keeps the values as the data holds them (12 and \"12\" are both kept); the colours are the resolved team's, so 12,\n * \"12\" and \"KC\" draw in one colour. A value outside the domain gets `fallback`, with one warning.\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamColorScale } from \"@sportsdataverse/sdvplot/unovis\";\n *\n * await loadLeague(\"nfl\");\n * const color = teamColorScale(\"nfl\", [\"KC\", \"PHI\"]);\n * // new Sankey({ linkColor: (l) => color(l.team), ... })\n * [color(\"KC\"), color(21), color.range];\n * ```\n */\nexport function teamColorScale<T>(\n league: League,\n teams: readonly T[],\n o: UnovisColorOptions = {},\n): UnovisTeamColorScale<T> {\n const domain = distinct(teams);\n const ro = {\n ...(o.season === undefined ? {} : { season: o.season }),\n ...(o.idSystem === undefined ? {} : { idSystem: o.idSystem }),\n };\n const fallback = o.fallback ?? \"#808080\";\n const ids = resolveSync(domain as readonly Value[], league, ro);\n // keyed by the resolved team: a team named twice (12 and \"KC\") is one team, with one colour\n const known = [...new Set(ids.filter((id) => id !== undefined))];\n const palette = colorPalette(league, known, {\n ...ro,\n idSystem: \"team_id\",\n ...(o.which === undefined ? {} : { which: o.which }),\n ...(o.background === undefined ? {} : { background: o.background }),\n fallback,\n });\n const byTeam = new Map<string, string>(known.map((id, j) => [id, palette[j] as string]));\n const memo = new Map(domain.map((t, i) => [keyOf(t), byTeam.get(ids[i] as string) ?? fallback]));\n const scale = (team: unknown): string => {\n const k = keyOf(team);\n let c = memo.get(k);\n if (c === undefined) {\n const id = resolveSync(team as Value, league, ro);\n c = id === undefined ? undefined : byTeam.get(id);\n if (c === undefined)\n warn(\n `unovis:${league}:color:${k}`,\n `teamColorScale: ${shown(team)} is not one of its teams; drawn in ${fallback}`,\n );\n c ??= fallback;\n memo.set(k, c);\n }\n return c;\n };\n return Object.assign(scale, { domain, range: domain.map((t) => memo.get(keyOf(t)) as string) });\n}\n\n/** `logoIcons` options. */\nexport interface UnovisLogoOptions {\n /** The season the teams are resolved for (a number or string). */\n season?: SeasonInput;\n /** Logo variant, e.g. \"dark\". Default \"default\". */\n variant?: Variant;\n /** How the team values are read. Default \"auto\". */\n idSystem?: IdSystem;\n}\n/** `headshotIcons` options. */\nexport interface UnovisHeadshotOptions {\n /** ESPN athlete ids, or nflverse gsis ids (needs `loadGsis()` first). Default \"espn\". */\n idSystem?: HeadshotIdSystem;\n}\n/** Images for a Graph's node icons: call it from `nodeIcon` with the team (or player) the node holds. */\nexport interface UnovisIcons<T = unknown> {\n /** `#<symbol id>` of the image of `value` (by any value naming the same team or player), else undefined. */\n (value: unknown): string | undefined;\n /** The values that have an image, as given (numbers stay numbers), each once and in order. */\n readonly domain: readonly T[];\n /** Their `#<symbol id>`s, in the same order. */\n readonly range: readonly string[];\n /** One `<symbol>` per image: the chart container's `svgDefs` (join two sets' with `+`). */\n readonly svgDefs: string;\n}\n\nconst escapeAttr = (s: string): string => s.replace(/[&<>\"]/g, (c) => `&#${c.charCodeAt(0)};`);\nconst n = (v: number): string => String(Math.round(v * 1e4) / 1e4);\n\nfunction icons<T>(\n kind: Kind,\n league: League,\n values: readonly T[],\n o: { season?: SeasonInput; variant?: Variant; idSystem?: IdSystem | HeadshotIdSystem },\n): UnovisIcons<T> {\n const given = distinct(values);\n const at = given.map(() => 0); // a node's place is Unovis's layout: placeSync only pairs each value with its image\n const placed = placeSync(at, at, given as readonly Value[], {\n league,\n kind,\n ...(o.season === undefined ? {} : { season: o.season }),\n ...(o.variant === undefined ? {} : { variant: o.variant }),\n ...(o.idSystem === undefined ? {} : { idSystem: o.idSystem }),\n });\n // a node's value -> the id its image is keyed by: the resolved team, or the player id as placeSync normalises it\n const idOf = (v: unknown): string | undefined =>\n kind === \"headshot\"\n ? o.idSystem === \"gsis\"\n ? String(v).trim()\n : (normValue(v) ?? undefined)\n : resolveSync(v as Value, league, {\n ...(o.season === undefined ? {} : { season: o.season }),\n ...(o.idSystem === undefined ? {} : { idSystem: o.idSystem as IdSystem }),\n });\n const byId = new Map<string, string>();\n let svgDefs = \"\";\n for (const p of placed) {\n if (byId.has(p.id)) continue;\n const href = imageSource(p);\n const id = contentId(`sdv-${kind}`, href);\n // the symbol's box is the image's own aspect: a `<use>` of it fits the image, uncut, in nodeIconSize\n const w = 100 * aspect(p);\n if (!svgDefs.includes(`id=\"${id}\"`))\n svgDefs += `<symbol id=\"${id}\" viewBox=\"0 0 ${n(w)} 100\" preserveAspectRatio=\"xMidYMid meet\"><image href=\"${escapeAttr(href)}\" width=\"${n(w)}\" height=\"100\" preserveAspectRatio=\"xMidYMid meet\"/></symbol>`;\n byId.set(p.id, `#${id}`);\n }\n const memo = new Map<string, string | undefined>(\n placed.map((p) => [keyOf(given[p.index]), byId.get(p.id)]),\n );\n const icon = (value: unknown): string | undefined => {\n const k = keyOf(value);\n if (!memo.has(k)) {\n const id = value === null || value === undefined ? undefined : idOf(value);\n memo.set(k, id === undefined ? undefined : byId.get(id));\n }\n return memo.get(k);\n };\n return Object.assign(icon, {\n domain: placed.map((p) => given[p.index] as T),\n range: placed.map((p) => byId.get(p.id) as string),\n svgDefs,\n });\n}\n\n/**\n * Team logos for a Unovis Graph's nodes: `nodeIcon: (n) => logos(n.team)`, with\n * `svgDefs: logos.svgDefs` on the container. Unovis draws each icon as a `<use>` of the logo's `<symbol>`, `nodeIconSize` px across, the logo\n * fitted inside, uncut; a node's fill shows round it. A team with no logo has no icon, with one warning. Every value\n * naming a team finds its logo (12, \"12\" and \"KC\").\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { logoIcons } from \"@sportsdataverse/sdvplot/unovis\";\n *\n * await loadLeague(\"nfl\");\n * const logos = logoIcons(\"nfl\", [\"KC\", \"LV\"], { variant: \"dark\" });\n * // new SingleContainer(el, { component: new Graph({ nodeIcon: (n) => logos(n.team), nodeIconSize: 28 }),\n * // svgDefs: logos.svgDefs }, data)\n * [logos(\"KC\"), logos.range];\n * ```\n */\nexport function logoIcons<T>(league: League, teams: readonly T[], o: UnovisLogoOptions = {}): UnovisIcons<T> {\n return icons(\"logo\", league, teams, o);\n}\n\n/**\n * ESPN player headshots for a Unovis Graph's nodes, as `logoIcons`: `nodeIcon: (n) => heads(n.player)`, with the\n * container's `svgDefs: heads.svgDefs`. A gsis id with no headshot has no icon, with one warning; an ESPN id's URL is\n * built without checking the image exists, so an id ESPN has no photo for keeps an empty icon, with no warning.\n *\n * @example\n * ```ts\n * import { headshotIcons } from \"@sportsdataverse/sdvplot/unovis\";\n *\n * // Patrick Mahomes and Travis Kelce, by ESPN athlete id\n * const heads = headshotIcons(\"nfl\", [3139477, 15847]);\n * [heads(3139477), heads.svgDefs.length > 0];\n * ```\n */\nexport function headshotIcons<T>(\n league: EspnHeadshotLeague,\n players: readonly T[],\n o: UnovisHeadshotOptions = {},\n): UnovisIcons<T> {\n return icons(\"headshot\", league, players, o);\n}\n"]}
@@ -0,0 +1,120 @@
1
+ import { M as MarkOptions, a as DrawnMark, R as Row } from './_web-D7Aa5Rd8.js';
2
+ import { L as League, S as SeasonInput, W as Which, I as IdSystem } from './types-C7n6gJF3.js';
3
+
4
+ /**
5
+ * The uPlot adapter: team colours for each series' `stroke` / `fill`, and team logos drawn on uPlot's canvas by a
6
+ * plugin (its `draw` hook), at points in data units. Pure: uplot is never imported (the types here are structural,
7
+ * read from uplot 1.6.31 and later), so the options can be built anywhere, a server included; only `new uPlot(...)`
8
+ * needs a browser. Call after `loadLeague(league)` / `preloadAll()`.
9
+ */
10
+
11
+ /** The subset of a uPlot chart this adapter reads: `new uPlot(...)` is one. */
12
+ interface UPlotLike {
13
+ /** The canvas' 2D context. */
14
+ readonly ctx: CanvasRenderingContext2D;
15
+ /** The plot area in canvas pixels. */
16
+ readonly bbox: {
17
+ left: number;
18
+ top: number;
19
+ width: number;
20
+ height: number;
21
+ };
22
+ /** The chart's data: x values first, then one array per series. */
23
+ readonly data: readonly ArrayLike<number | null | undefined>[];
24
+ /** A value on scale `scaleKey` as a position (canvas pixels with `canvasPixels`). */
25
+ valToPos(val: number, scaleKey: string, canvasPixels?: boolean): number;
26
+ /** Redraws the chart (`rebuildPaths: false` reuses the series paths). */
27
+ redraw(rebuildPaths?: boolean, recalcAxes?: boolean): void;
28
+ }
29
+ /** A uPlot plugin: put it in the options' `plugins`. */
30
+ interface UPlotPlugin {
31
+ /** `init` registers the chart (for redraws as images land), `draw` paints the logos, `destroy` forgets the chart. */
32
+ hooks: {
33
+ init: (u: UPlotLike) => void;
34
+ draw: (u: UPlotLike) => void;
35
+ destroy: (u: UPlotLike) => void;
36
+ };
37
+ }
38
+ /** `logoPlugin` options: the spec adapters' mark options, less `embed`, plus the y scale. */
39
+ interface UPlotLogoOptions extends Omit<MarkOptions, "embed"> {
40
+ /** The scale key the `y` values are on. Default "y". (`x` is on uPlot's "x" scale; a time scale counts seconds.) */
41
+ scale?: string;
42
+ }
43
+ /**
44
+ * Team logos on a uPlot chart: a plugin whose `draw` hook paints each row's logo centred on its `x` / `y` (data units,
45
+ * placed with uPlot's own `valToPos`), `height` of the plot area tall (a fraction, as in the spec adapters), over the
46
+ * series. The images start loading when the chart starts (uPlot's `init` hook, before its first draw), and the
47
+ * chart redraws as each one lands; building the plugin fetches nothing. A team with no logo draws nothing and warns
48
+ * once, as `sdvplot/echarts` does; an image that fails to load is never drawn and warns once; a point outside the plot
49
+ * area (after a zoom) is not drawn over the axes.
50
+ *
51
+ * `rows` can also be a function of the chart, read at every draw: give it `u.data` and the logos follow live data
52
+ * (`u.setData(...)`), such as a logo at each line's newest point.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
57
+ * import { logoPlugin } from "@sportsdataverse/sdvplot/uplot";
58
+ *
59
+ * await loadLeague("nfl");
60
+ * // the 2024 Chiefs and Bills: points for (x) against points against (y)
61
+ * const rows = [
62
+ * { team: "KC", pf: 385, pa: 326 },
63
+ * { team: "BUF", pf: 525, pa: 368 },
64
+ * ];
65
+ * const plugin = logoPlugin(rows, { x: "pf", y: "pa", team: "team", league: "nfl", height: 0.15 });
66
+ * // in the browser: new uPlot({ width: 640, height: 320, series, plugins: [plugin] }, data, element)
67
+ * Object.keys(plugin.hooks);
68
+ * ```
69
+ */
70
+ declare function logoPlugin(rows: readonly Row[] | ((u: UPlotLike) => readonly Row[]), o: UPlotLogoOptions): UPlotPlugin;
71
+ /** Test hook: [teamId, x, y, height, url] per logo the chart's `logoPlugin`s last drew, `height` a fraction of the
72
+ * plot area. */
73
+ declare function drawnMarks(u: UPlotLike): DrawnMark[];
74
+ /** `withTeamSeries` options. */
75
+ interface UPlotSeriesOptions {
76
+ /** Name of the row column holding the team (abbreviation, name or id; see `idSystem`). */
77
+ team: string;
78
+ /** The league the teams belong to, e.g. "nfl". */
79
+ league: League;
80
+ /** The season the teams are resolved (and coloured) for. */
81
+ season?: SeasonInput;
82
+ /** "primary" (default) or "secondary". */
83
+ which?: Which;
84
+ /** How the `team` values are read. Default "auto". */
85
+ idSystem?: IdSystem;
86
+ /** The colour of an unresolved team. Default "#808080". */
87
+ fallback?: string;
88
+ /**
89
+ * The chart's background. Given, a team colour under 3:1 contrast against it is swapped for the team's other
90
+ * colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A
91
+ * colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or
92
+ * the nearest colour to its own (lightness, hue or chroma stepped) that is distinct and still reads; failing that it
93
+ * is kept, with one warning.
94
+ */
95
+ background?: string;
96
+ /** Also fill the area under each line in its colour, at this opacity in [0, 1]. Default: no fill. */
97
+ fill?: number;
98
+ }
99
+ /**
100
+ * Team colours for a uPlot chart's series: row `i`'s team strokes `series[i + 1]` (series 0 is uPlot's x), and with
101
+ * `fill` also fills the area under it. The rest of each series is kept and the options are copied, never changed. With
102
+ * `background`, every colour keeps 3:1 contrast against it (dark mode) and aims to stay distinct from the others (when
103
+ * it cannot, it keeps the readable colour and warns once).
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
108
+ * import { withTeamSeries } from "@sportsdataverse/sdvplot/uplot";
109
+ *
110
+ * await loadLeague("nfl");
111
+ * withTeamSeries(
112
+ * { width: 640, height: 320, series: [{}, { label: "Kansas City" }, { label: "Buffalo" }] },
113
+ * [{ team: "KC" }, { team: "BUF" }],
114
+ * { team: "team", league: "nfl", background: "#181a1b" },
115
+ * );
116
+ * ```
117
+ */
118
+ declare function withTeamSeries<F extends object>(opts: F, rows: readonly Row[], o: UPlotSeriesOptions): F;
119
+
120
+ export { DrawnMark, MarkOptions, Row, type UPlotLike, type UPlotLogoOptions, type UPlotPlugin, type UPlotSeriesOptions, drawnMarks, logoPlugin, withTeamSeries };
package/dist/uplot.js ADDED
@@ -0,0 +1,110 @@
1
+ import { aspect, colorPalette, markPlacements } from './chunk-UL5M6KDE.js';
2
+ import { checkHeight, checkAlpha } from './chunk-7ULOCCFL.js';
3
+ import './chunk-ZAEQXFJM.js';
4
+ import { hex6 } from './chunk-J6R2LEJ7.js';
5
+ import { UnsupportedTargetError, InputError, warn } from './chunk-E7G7VSLV.js';
6
+
7
+ // src/uplot.ts
8
+ var drawn = /* @__PURE__ */ new WeakMap();
9
+ function logoPlugin(rows, o) {
10
+ const h = checkHeight(o.height ?? 0.1);
11
+ const a = checkAlpha(o.alpha ?? 1);
12
+ const yScale = o.scale ?? "y";
13
+ let placed;
14
+ const placements = (rs) => {
15
+ if (placed?.rows !== rs) placed = { rows: rs, ps: markPlacements(rs, "logo", o) };
16
+ return placed.ps;
17
+ };
18
+ const token = {};
19
+ const charts = /* @__PURE__ */ new Set();
20
+ const images = /* @__PURE__ */ new Map();
21
+ const load = (url) => {
22
+ if (images.has(url) || typeof Image === "undefined") return images.get(url);
23
+ const img = new Image();
24
+ img.crossOrigin = "anonymous";
25
+ images.set(url, img);
26
+ img.onload = () => {
27
+ for (const u of charts) u.redraw(false);
28
+ };
29
+ img.onerror = () => {
30
+ images.set(url, null);
31
+ warn(`uplot:image:${url}`, `could not load ${url}, so it is not drawn`);
32
+ };
33
+ img.src = url;
34
+ return img;
35
+ };
36
+ const preload = () => {
37
+ if (typeof rows !== "function") for (const p of placements(rows)) load(p.url);
38
+ };
39
+ if (typeof rows !== "function") placements(rows);
40
+ return {
41
+ hooks: {
42
+ init(u) {
43
+ charts.add(u);
44
+ preload();
45
+ },
46
+ destroy(u) {
47
+ charts.delete(u);
48
+ },
49
+ draw(u) {
50
+ const { ctx, bbox } = u;
51
+ const out = [];
52
+ const ph = h * bbox.height;
53
+ ctx.save();
54
+ ctx.globalAlpha = a;
55
+ for (const p of placements(typeof rows === "function" ? rows(u) : rows)) {
56
+ const img = load(p.url);
57
+ if (!img?.complete || img.naturalWidth === 0) continue;
58
+ const cx = u.valToPos(Number(p.x), "x", true);
59
+ const cy = u.valToPos(Number(p.y), yScale, true);
60
+ const inside = cx >= bbox.left && cx <= bbox.left + bbox.width && cy >= bbox.top && cy <= bbox.top + bbox.height;
61
+ if (!inside) continue;
62
+ const pw = ph * aspect(p);
63
+ ctx.drawImage(img, cx - pw / 2, cy - ph / 2, pw, ph);
64
+ out.push([p.id, p.x, p.y, h, p.url]);
65
+ }
66
+ ctx.restore();
67
+ const byPlugin = drawn.get(u) ?? /* @__PURE__ */ new Map();
68
+ byPlugin.set(token, out);
69
+ drawn.set(u, byPlugin);
70
+ }
71
+ }
72
+ };
73
+ }
74
+ function drawnMarks(u) {
75
+ return [...drawn.get(u)?.values() ?? []].flat();
76
+ }
77
+ var rgba = (hex, alpha) => {
78
+ const n = Number.parseInt(hex.slice(1), 16);
79
+ return `rgba(${n >> 16}, ${n >> 8 & 255}, ${n & 255}, ${alpha})`;
80
+ };
81
+ function withTeamSeries(opts, rows, o) {
82
+ const series = opts?.series;
83
+ if (typeof opts !== "object" || opts === null || !Array.isArray(series))
84
+ throw new UnsupportedTargetError("sdvplot/uplot colours a uPlot options object with a `series` array");
85
+ if (rows.length > series.length - 1)
86
+ throw new InputError(
87
+ `${rows.length} rows for ${series.length - 1} data series: row i colours series[i + 1] (series[0] is x)`
88
+ );
89
+ const fill = o.fill === void 0 ? void 0 : checkAlpha(o.fill);
90
+ const teams = rows.map((r) => r[o.team]);
91
+ if (rows.length > 0 && !rows.some((r) => o.team in r))
92
+ throw new InputError(`team column ${JSON.stringify(o.team)} is not in rows`);
93
+ const strokes = colorPalette(o.league, teams, {
94
+ ...o.season === void 0 ? {} : { season: o.season },
95
+ ...o.idSystem === void 0 ? {} : { idSystem: o.idSystem },
96
+ ...o.which === void 0 ? {} : { which: o.which },
97
+ ...o.fallback === void 0 ? {} : { fallback: o.fallback },
98
+ ...o.background === void 0 ? {} : { background: o.background }
99
+ }).map((c) => hex6(c, { dropAlpha: true }));
100
+ const out = series.map((s, i) => {
101
+ const stroke = strokes[i - 1];
102
+ if (stroke === void 0) return s;
103
+ return { ...s, stroke, ...fill === void 0 ? {} : { fill: rgba(stroke, fill) } };
104
+ });
105
+ return { ...opts, series: out };
106
+ }
107
+
108
+ export { drawnMarks, logoPlugin, withTeamSeries };
109
+ //# sourceMappingURL=uplot.js.map
110
+ //# sourceMappingURL=uplot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/uplot.ts"],"names":[],"mappings":"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","file":"uplot.js","sourcesContent":["/**\n * The uPlot adapter: team colours for each series' `stroke` / `fill`, and team logos drawn on uPlot's canvas by a\n * plugin (its `draw` hook), at points in data units. Pure: uplot is never imported (the types here are structural,\n * read from uplot 1.6.31 and later), so the options can be built anywhere, a server included; only `new uPlot(...)`\n * needs a browser. Call after `loadLeague(league)` / `preloadAll()`.\n */\nimport {\n type MarkOptions,\n type Row,\n aspect,\n checkAlpha,\n checkHeight,\n colorPalette,\n markPlacements,\n} from \"./_web.js\";\nimport type { DrawnMark } from \"./_web.js\";\nimport { hex6 } from \"./contrast.js\";\nimport { InputError, UnsupportedTargetError, warn } from \"./errors.js\";\nimport type { Placement } from \"./placement.js\";\nimport type { IdSystem, League, SeasonInput, Which } from \"./types.js\";\nexport type { DrawnMark, MarkOptions, Row } from \"./_web.js\";\n\n/** The subset of a uPlot chart this adapter reads: `new uPlot(...)` is one. */\nexport interface UPlotLike {\n /** The canvas' 2D context. */\n readonly ctx: CanvasRenderingContext2D;\n /** The plot area in canvas pixels. */\n readonly bbox: { left: number; top: number; width: number; height: number };\n /** The chart's data: x values first, then one array per series. */\n readonly data: readonly ArrayLike<number | null | undefined>[];\n /** A value on scale `scaleKey` as a position (canvas pixels with `canvasPixels`). */\n valToPos(val: number, scaleKey: string, canvasPixels?: boolean): number;\n /** Redraws the chart (`rebuildPaths: false` reuses the series paths). */\n redraw(rebuildPaths?: boolean, recalcAxes?: boolean): void;\n}\n/** A uPlot plugin: put it in the options' `plugins`. */\nexport interface UPlotPlugin {\n /** `init` registers the chart (for redraws as images land), `draw` paints the logos, `destroy` forgets the chart. */\n hooks: {\n init: (u: UPlotLike) => void;\n draw: (u: UPlotLike) => void;\n destroy: (u: UPlotLike) => void;\n };\n}\n\n/** `logoPlugin` options: the spec adapters' mark options, less `embed`, plus the y scale. */\nexport interface UPlotLogoOptions extends Omit<MarkOptions, \"embed\"> {\n /** The scale key the `y` values are on. Default \"y\". (`x` is on uPlot's \"x\" scale; a time scale counts seconds.) */\n scale?: string;\n}\n\n// ponytail: a WeakMap per chart of what each plugin last drew, so drawnMarks reads what reached the canvas\nconst drawn = new WeakMap<object, Map<object, DrawnMark[]>>();\n\n/**\n * Team logos on a uPlot chart: a plugin whose `draw` hook paints each row's logo centred on its `x` / `y` (data units,\n * placed with uPlot's own `valToPos`), `height` of the plot area tall (a fraction, as in the spec adapters), over the\n * series. The images start loading when the chart starts (uPlot's `init` hook, before its first draw), and the\n * chart redraws as each one lands; building the plugin fetches nothing. A team with no logo draws nothing and warns\n * once, as `sdvplot/echarts` does; an image that fails to load is never drawn and warns once; a point outside the plot\n * area (after a zoom) is not drawn over the axes.\n *\n * `rows` can also be a function of the chart, read at every draw: give it `u.data` and the logos follow live data\n * (`u.setData(...)`), such as a logo at each line's newest point.\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { logoPlugin } from \"@sportsdataverse/sdvplot/uplot\";\n *\n * await loadLeague(\"nfl\");\n * // the 2024 Chiefs and Bills: points for (x) against points against (y)\n * const rows = [\n * { team: \"KC\", pf: 385, pa: 326 },\n * { team: \"BUF\", pf: 525, pa: 368 },\n * ];\n * const plugin = logoPlugin(rows, { x: \"pf\", y: \"pa\", team: \"team\", league: \"nfl\", height: 0.15 });\n * // in the browser: new uPlot({ width: 640, height: 320, series, plugins: [plugin] }, data, element)\n * Object.keys(plugin.hooks);\n * ```\n */\nexport function logoPlugin(\n rows: readonly Row[] | ((u: UPlotLike) => readonly Row[]),\n o: UPlotLogoOptions,\n): UPlotPlugin {\n const h = checkHeight(o.height ?? 0.1);\n const a = checkAlpha(o.alpha ?? 1);\n const yScale = o.scale ?? \"y\";\n // ponytail: one cached placement per rows identity; a rows function returning a fresh array re-resolves its teams\n // every draw, cheap for a few end logos (memoise by team if a feed ever draws hundreds)\n let placed: { rows: readonly Row[]; ps: Placement[] } | undefined;\n const placements = (rs: readonly Row[]): Placement[] => {\n if (placed?.rows !== rs) placed = { rows: rs, ps: markPlacements(rs, \"logo\", o) };\n return placed.ps;\n };\n const token = {}; // this plugin's key in `drawn`\n const charts = new Set<UPlotLike>();\n const images = new Map<string, HTMLImageElement | null>(); // null: it failed to load\n const load = (url: string): HTMLImageElement | null | undefined => {\n if (images.has(url) || typeof Image === \"undefined\") return images.get(url);\n const img = new Image();\n img.crossOrigin = \"anonymous\"; // keeps the canvas exportable\n images.set(url, img);\n img.onload = () => {\n for (const u of charts) u.redraw(false);\n };\n img.onerror = () => {\n images.set(url, null);\n warn(`uplot:image:${url}`, `could not load ${url}, so it is not drawn`);\n };\n img.src = url;\n return img;\n };\n const preload = (): void => {\n if (typeof rows !== \"function\") for (const p of placements(rows)) load(p.url);\n };\n if (typeof rows !== \"function\") placements(rows); // validates the rows now, when the options are built\n return {\n hooks: {\n init(u) {\n charts.add(u);\n preload();\n },\n destroy(u) {\n charts.delete(u);\n },\n draw(u) {\n const { ctx, bbox } = u;\n const out: DrawnMark[] = [];\n const ph = h * bbox.height;\n ctx.save();\n ctx.globalAlpha = a;\n for (const p of placements(typeof rows === \"function\" ? rows(u) : rows)) {\n const img = load(p.url);\n if (!img?.complete || img.naturalWidth === 0) continue;\n const cx = u.valToPos(Number(p.x), \"x\", true);\n const cy = u.valToPos(Number(p.y), yScale, true);\n const inside =\n cx >= bbox.left && cx <= bbox.left + bbox.width && cy >= bbox.top && cy <= bbox.top + bbox.height;\n if (!inside) continue; // also drops NaN\n const pw = ph * aspect(p);\n ctx.drawImage(img, cx - pw / 2, cy - ph / 2, pw, ph);\n out.push([p.id, p.x, p.y, h, p.url]);\n }\n ctx.restore();\n const byPlugin = drawn.get(u) ?? new Map<object, DrawnMark[]>();\n byPlugin.set(token, out);\n drawn.set(u, byPlugin);\n },\n },\n };\n}\n\n/** Test hook: [teamId, x, y, height, url] per logo the chart's `logoPlugin`s last drew, `height` a fraction of the\n * plot area. */\nexport function drawnMarks(u: UPlotLike): DrawnMark[] {\n return [...(drawn.get(u)?.values() ?? [])].flat();\n}\n\n/** `withTeamSeries` options. */\nexport interface UPlotSeriesOptions {\n /** Name of the row column holding the team (abbreviation, name or id; see `idSystem`). */\n team: string;\n /** The league the teams belong to, e.g. \"nfl\". */\n league: League;\n /** The season the teams are resolved (and coloured) for. */\n season?: SeasonInput;\n /** \"primary\" (default) or \"secondary\". */\n which?: Which;\n /** How the `team` values are read. Default \"auto\". */\n idSystem?: IdSystem;\n /** The colour of an unresolved team. Default \"#808080\". */\n fallback?: string;\n /**\n * The chart's background. Given, a team colour under 3:1 contrast against it is swapped for the team's other\n * colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A\n * colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or\n * the nearest colour to its own (lightness, hue or chroma stepped) that is distinct and still reads; failing that it\n * is kept, with one warning.\n */\n background?: string;\n /** Also fill the area under each line in its colour, at this opacity in [0, 1]. Default: no fill. */\n fill?: number;\n}\nconst rgba = (hex: string, alpha: number): string => {\n const n = Number.parseInt(hex.slice(1), 16);\n return `rgba(${n >> 16}, ${(n >> 8) & 255}, ${n & 255}, ${alpha})`;\n};\n\n/**\n * Team colours for a uPlot chart's series: row `i`'s team strokes `series[i + 1]` (series 0 is uPlot's x), and with\n * `fill` also fills the area under it. The rest of each series is kept and the options are copied, never changed. With\n * `background`, every colour keeps 3:1 contrast against it (dark mode) and aims to stay distinct from the others (when\n * it cannot, it keeps the readable colour and warns once).\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { withTeamSeries } from \"@sportsdataverse/sdvplot/uplot\";\n *\n * await loadLeague(\"nfl\");\n * withTeamSeries(\n * { width: 640, height: 320, series: [{}, { label: \"Kansas City\" }, { label: \"Buffalo\" }] },\n * [{ team: \"KC\" }, { team: \"BUF\" }],\n * { team: \"team\", league: \"nfl\", background: \"#181a1b\" },\n * );\n * ```\n */\nexport function withTeamSeries<F extends object>(opts: F, rows: readonly Row[], o: UPlotSeriesOptions): F {\n const series = (opts as { series?: unknown } | null)?.series;\n if (typeof opts !== \"object\" || opts === null || !Array.isArray(series))\n throw new UnsupportedTargetError(\"sdvplot/uplot colours a uPlot options object with a `series` array\");\n if (rows.length > series.length - 1)\n throw new InputError(\n `${rows.length} rows for ${series.length - 1} data series: row i colours series[i + 1] (series[0] is x)`,\n );\n const fill = o.fill === undefined ? undefined : checkAlpha(o.fill);\n const teams = rows.map((r) => r[o.team]);\n if (rows.length > 0 && !rows.some((r) => o.team in r))\n throw new InputError(`team column ${JSON.stringify(o.team)} is not in rows`);\n // the shared palette (over the resolved teams), as #rrggbb for the fill's rgba\n const strokes = colorPalette(o.league, teams, {\n ...(o.season === undefined ? {} : { season: o.season }),\n ...(o.idSystem === undefined ? {} : { idSystem: o.idSystem }),\n ...(o.which === undefined ? {} : { which: o.which }),\n ...(o.fallback === undefined ? {} : { fallback: o.fallback }),\n ...(o.background === undefined ? {} : { background: o.background }),\n }).map((c) => hex6(c, { dropAlpha: true }));\n const out = series.map((s: unknown, i) => {\n const stroke = strokes[i - 1];\n if (stroke === undefined) return s;\n return { ...(s as object), stroke, ...(fill === undefined ? {} : { fill: rgba(stroke, fill) }) };\n });\n return { ...opts, series: out };\n}\n"]}
@@ -0,0 +1,32 @@
1
+ // src/data/aliases/usfl.ts
2
+ var aliases = [
3
+ { "id_system": "mark", "value": "fox:birmingham-stallions", "team_id": "birmingham-stallions", "valid_from": null, "valid_to": null },
4
+ { "id_system": "mark", "value": "fox:houston-gamblers", "team_id": "houston-gamblers", "valid_from": null, "valid_to": null },
5
+ { "id_system": "mark", "value": "fox:memphis-showboats", "team_id": "memphis-showboats", "valid_from": null, "valid_to": null },
6
+ { "id_system": "mark", "value": "fox:michigan-panthers", "team_id": "michigan-panthers", "valid_from": null, "valid_to": null },
7
+ { "id_system": "mark", "value": "fox:new-jersey-generals", "team_id": "new-jersey-generals", "valid_from": null, "valid_to": null },
8
+ { "id_system": "mark", "value": "fox:new-orleans-breakers", "team_id": "new-orleans-breakers", "valid_from": null, "valid_to": null },
9
+ { "id_system": "mark", "value": "fox:philadelphia-stars", "team_id": "philadelphia-stars", "valid_from": null, "valid_to": null },
10
+ { "id_system": "mark", "value": "fox:pittsburgh-maulers", "team_id": "pittsburgh-maulers", "valid_from": null, "valid_to": null },
11
+ { "id_system": "mark", "value": "fox:tampa-bay-bandits", "team_id": "tampa-bay-bandits", "valid_from": null, "valid_to": null },
12
+ { "id_system": "name", "value": "Birmingham Stallions", "team_id": "birmingham-stallions", "valid_from": null, "valid_to": null },
13
+ { "id_system": "name", "value": "Houston Gamblers", "team_id": "houston-gamblers", "valid_from": null, "valid_to": null },
14
+ { "id_system": "name", "value": "Memphis Showboats", "team_id": "memphis-showboats", "valid_from": null, "valid_to": null },
15
+ { "id_system": "name", "value": "Michigan Panthers", "team_id": "michigan-panthers", "valid_from": null, "valid_to": null },
16
+ { "id_system": "name", "value": "New Jersey Generals", "team_id": "new-jersey-generals", "valid_from": null, "valid_to": null },
17
+ { "id_system": "name", "value": "New Orleans Breakers", "team_id": "new-orleans-breakers", "valid_from": null, "valid_to": null },
18
+ { "id_system": "name", "value": "Philadelphia Stars", "team_id": "philadelphia-stars", "valid_from": null, "valid_to": null },
19
+ { "id_system": "name", "value": "Pittsburgh Maulers", "team_id": "pittsburgh-maulers", "valid_from": null, "valid_to": null },
20
+ { "id_system": "name", "value": "Tampa Bay Bandits", "team_id": "tampa-bay-bandits", "valid_from": null, "valid_to": null },
21
+ { "id_system": "team_id", "value": "birmingham-stallions", "team_id": "birmingham-stallions", "valid_from": null, "valid_to": null },
22
+ { "id_system": "team_id", "value": "houston-gamblers", "team_id": "houston-gamblers", "valid_from": null, "valid_to": null },
23
+ { "id_system": "team_id", "value": "memphis-showboats", "team_id": "memphis-showboats", "valid_from": null, "valid_to": null },
24
+ { "id_system": "team_id", "value": "michigan-panthers", "team_id": "michigan-panthers", "valid_from": null, "valid_to": null },
25
+ { "id_system": "team_id", "value": "new-jersey-generals", "team_id": "new-jersey-generals", "valid_from": null, "valid_to": null },
26
+ { "id_system": "team_id", "value": "new-orleans-breakers", "team_id": "new-orleans-breakers", "valid_from": null, "valid_to": null },
27
+ { "id_system": "team_id", "value": "philadelphia-stars", "team_id": "philadelphia-stars", "valid_from": null, "valid_to": null },
28
+ { "id_system": "team_id", "value": "pittsburgh-maulers", "team_id": "pittsburgh-maulers", "valid_from": null, "valid_to": null },
29
+ { "id_system": "team_id", "value": "tampa-bay-bandits", "team_id": "tampa-bay-bandits", "valid_from": null, "valid_to": null }
30
+ ];
31
+
32
+ export { aliases };
@@ -0,0 +1,14 @@
1
+ // src/data/teams/usfl.ts
2
+ var teams = [
3
+ { "league": "usfl", "team_id": "birmingham-stallions", "abbr": null, "name": "Birmingham Stallions", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#a32035", "color_secondary": "#ceb795", "color_source": "logo" },
4
+ { "league": "usfl", "team_id": "houston-gamblers", "abbr": null, "name": "Houston Gamblers", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#ea0029", "color_secondary": "#000000", "color_source": "logo" },
5
+ { "league": "usfl", "team_id": "memphis-showboats", "abbr": null, "name": "Memphis Showboats", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#12284c", "color_secondary": "#ffb71c", "color_source": "logo" },
6
+ { "league": "usfl", "team_id": "michigan-panthers", "abbr": null, "name": "Michigan Panthers", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#702e3e", "color_secondary": "#c6b784", "color_source": "logo" },
7
+ { "league": "usfl", "team_id": "new-jersey-generals", "abbr": null, "name": "New Jersey Generals", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#001a41", "color_secondary": "#cb9f54", "color_source": "logo" },
8
+ { "league": "usfl", "team_id": "new-orleans-breakers", "abbr": null, "name": "New Orleans Breakers", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#4298cc", "color_secondary": "#003595", "color_source": "logo" },
9
+ { "league": "usfl", "team_id": "philadelphia-stars", "abbr": null, "name": "Philadelphia Stars", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#c10230", "color_secondary": "#fba02d", "color_source": "logo" },
10
+ { "league": "usfl", "team_id": "pittsburgh-maulers", "abbr": null, "name": "Pittsburgh Maulers", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#ffb71b", "color_secondary": "#000000", "color_source": "logo" },
11
+ { "league": "usfl", "team_id": "tampa-bay-bandits", "abbr": null, "name": "Tampa Bay Bandits", "short_name": null, "location": null, "program": "pro", "conference_id": null, "conference": null, "color_primary": "#c10230", "color_secondary": "#000000", "color_source": "logo" }
12
+ ];
13
+
14
+ export { teams };
@@ -0,0 +1,19 @@
1
+ // src/data/marks/usfl.ts
2
+ var marks = [
3
+ { "team_id": "tampa-bay-bandits", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "2440865ff13ecaffcc45ed16431f83a4bd429b37f836eeee9053cdd807354d05", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
4
+ { "team_id": "philadelphia-stars", "mark_type": "logo", "variant": "alternate", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "4f796ada74fd249cf196a6fac977630d1d5bfbb744cadf3100d5ebbfacd25582", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
5
+ { "team_id": "birmingham-stallions", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "4fe31310c59a8bd5df2bcbc5548f1d78dc5d87d519c5a22c2cece5f01777b6b8", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
6
+ { "team_id": "philadelphia-stars", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "5214cb1a8f10eaac4f7baa3a9cc6e36663a60ab768c7d04ba7e837b6ffa753b5", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
7
+ { "team_id": "new-orleans-breakers", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "5665151bd9551ef7d7a83d129639653cc9adcb9456343cd424f4487407760739", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
8
+ { "team_id": "new-orleans-breakers", "mark_type": "logo", "variant": "alternate", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "5c45ab13ea22476b52ce7793da485e6000c3610c0dc3d98162e3cb8e681d95be", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
9
+ { "team_id": "houston-gamblers", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "69fffa26b1e0a94ce9608b9cf5ae7b73bb0abf4c51f920fb99fe5c2ba8e94c40", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
10
+ { "team_id": "new-jersey-generals", "mark_type": "logo", "variant": "alternate", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "9e28a94988b21ab3cca96f8cec540c9d27f559b8d16e1ddd2b60bfe881441e5d", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
11
+ { "team_id": "michigan-panthers", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "b9575fa9a603fc4ff31baec4803bee500a978e1fd06f91be44da07caab2f4aa9", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
12
+ { "team_id": "memphis-showboats", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "c925fa79e4ac6d372d98a8f8920bb15de22f374bc5b244b56d7f559d38961aa0", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
13
+ { "team_id": "houston-gamblers", "mark_type": "logo", "variant": "alternate", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "cb0a8ad787c5f05f7d69bacdf3bf634056c309636b453925121ec9e6acde87ab", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
14
+ { "team_id": "pittsburgh-maulers", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "e0af9b27a604e33ff8fcf7038ddfaaaa555e02d6ac747b40a7eb864147d25c4f", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
15
+ { "team_id": "memphis-showboats", "mark_type": "logo", "variant": "alternate", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "f573b5cc5b15673a25b9e623beacc82da39e3028962bc422ee38482dc5d14a0a", "ext": "png", "width": 800, "height": 800, "source_rank": 1 },
16
+ { "team_id": "new-jersey-generals", "mark_type": "logo", "variant": "default", "valid_from": null, "valid_to": null, "source": "fox", "first_seen": "2026-09-30", "sha256": "fb6b19fee5a8099537c0dcb7a2a791814a9cb020d4a8eb72e159d89ee12e0454", "ext": "png", "width": 800, "height": 800, "source_rank": 1 }
17
+ ];
18
+
19
+ export { marks };