@sportsdataverse/sdvplot 0.1.0 → 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 (135) hide show
  1. package/NOTICE.md +15 -0
  2. package/README.md +84 -8
  3. package/dist/chartjs-surface.d.ts +2 -2
  4. package/dist/chartjs-surface.js +2 -2
  5. package/dist/chartjs-surface.js.map +1 -1
  6. package/dist/chartjs.d.ts +32 -2
  7. package/dist/chartjs.js +7 -4
  8. package/dist/chartjs.js.map +1 -1
  9. package/dist/chunk-57WFSI4Q.js +128 -0
  10. package/dist/chunk-57WFSI4Q.js.map +1 -0
  11. package/dist/{chunk-KKH6ABMA.js → chunk-7ULOCCFL.js} +94 -4
  12. package/dist/chunk-7ULOCCFL.js.map +1 -0
  13. package/dist/chunk-AMXASQHT.js +120 -0
  14. package/dist/chunk-AMXASQHT.js.map +1 -0
  15. package/dist/chunk-B2MP37SR.js +175 -0
  16. package/dist/chunk-B2MP37SR.js.map +1 -0
  17. package/dist/{chunk-NLPH2VZT.js → chunk-DYMUVE6K.js} +4 -4
  18. package/dist/{chunk-NLPH2VZT.js.map → chunk-DYMUVE6K.js.map} +1 -1
  19. package/dist/{chunk-QY65DUEF.js → chunk-H2C3FMMA.js} +4 -10
  20. package/dist/chunk-H2C3FMMA.js.map +1 -0
  21. package/dist/{chunk-JJFTD4VB.js → chunk-J4P4HDBF.js} +4 -4
  22. package/dist/{chunk-JJFTD4VB.js.map → chunk-J4P4HDBF.js.map} +1 -1
  23. package/dist/chunk-M3XD2OSN.js +132 -0
  24. package/dist/chunk-M3XD2OSN.js.map +1 -0
  25. package/dist/{chunk-OKEE4AH6.js → chunk-OIILARXI.js} +3 -3
  26. package/dist/{chunk-OKEE4AH6.js.map → chunk-OIILARXI.js.map} +1 -1
  27. package/dist/chunk-RPVVJY74.js +170 -0
  28. package/dist/chunk-RPVVJY74.js.map +1 -0
  29. package/dist/chunk-UL5M6KDE.js +205 -0
  30. package/dist/chunk-UL5M6KDE.js.map +1 -0
  31. package/dist/chunk-WQT4IVLX.js +10 -0
  32. package/dist/chunk-WQT4IVLX.js.map +1 -0
  33. package/dist/{chunk-TAXO3VXH.js → chunk-ZAEQXFJM.js} +3 -3
  34. package/dist/{chunk-TAXO3VXH.js.map → chunk-ZAEQXFJM.js.map} +1 -1
  35. package/dist/cytoscape.d.ts +188 -0
  36. package/dist/cytoscape.js +219 -0
  37. package/dist/cytoscape.js.map +1 -0
  38. package/dist/d3.d.ts +3 -3
  39. package/dist/d3.js +6 -6
  40. package/dist/d3.js.map +1 -1
  41. package/dist/deckgl.d.ts +232 -0
  42. package/dist/deckgl.js +197 -0
  43. package/dist/deckgl.js.map +1 -0
  44. package/dist/echarts.js +5 -5
  45. package/dist/g2.d.ts +251 -0
  46. package/dist/g2.js +102 -0
  47. package/dist/g2.js.map +1 -0
  48. package/dist/index.d.ts +2 -1
  49. package/dist/index.js +4 -5
  50. package/dist/lightweight-charts.d.ts +217 -0
  51. package/dist/lightweight-charts.js +155 -0
  52. package/dist/lightweight-charts.js.map +1 -0
  53. package/dist/maplibre.d.ts +271 -0
  54. package/dist/maplibre.js +175 -0
  55. package/dist/maplibre.js.map +1 -0
  56. package/dist/mui.d.ts +338 -0
  57. package/dist/mui.js +184 -0
  58. package/dist/mui.js.map +1 -0
  59. package/dist/nivo.d.ts +193 -0
  60. package/dist/nivo.js +8 -0
  61. package/dist/nivo.js.map +1 -0
  62. package/dist/perspective.d.ts +198 -0
  63. package/dist/perspective.js +171 -0
  64. package/dist/perspective.js.map +1 -0
  65. package/dist/placement-UWkqUzpa.d.ts +32 -0
  66. package/dist/plot.d.ts +7 -5
  67. package/dist/plot.js +9 -8
  68. package/dist/plot.js.map +1 -1
  69. package/dist/plotly.js +5 -5
  70. package/dist/react.d.ts +279 -3
  71. package/dist/react.js +364 -6
  72. package/dist/react.js.map +1 -1
  73. package/dist/recharts.d.ts +162 -0
  74. package/dist/recharts.js +8 -0
  75. package/dist/recharts.js.map +1 -0
  76. package/dist/shadcn.d.ts +83 -0
  77. package/dist/shadcn.js +88 -0
  78. package/dist/shadcn.js.map +1 -0
  79. package/dist/shots.js +3 -2
  80. package/dist/shots.js.map +1 -1
  81. package/dist/surface-TR7YFJW3.js +4 -0
  82. package/dist/surface-TR7YFJW3.js.map +1 -0
  83. package/dist/surfaces-MIG7HOFU.js +6 -0
  84. package/dist/surfaces-MIG7HOFU.js.map +1 -0
  85. package/dist/surfaces-W-odWLpT.d.ts +47 -0
  86. package/dist/svelte/HeadshotMark.svelte +25 -0
  87. package/dist/svelte/HeadshotMark.svelte.d.ts +10 -0
  88. package/dist/svelte/HeadshotMark.svelte.d.ts.map +1 -0
  89. package/dist/svelte/LogoMark.svelte +25 -0
  90. package/dist/svelte/LogoMark.svelte.d.ts +10 -0
  91. package/dist/svelte/LogoMark.svelte.d.ts.map +1 -0
  92. package/dist/svelte/Marks.svelte +25 -0
  93. package/dist/svelte/Marks.svelte.d.ts +10 -0
  94. package/dist/svelte/Marks.svelte.d.ts.map +1 -0
  95. package/dist/svelte/Surface.svelte +29 -0
  96. package/dist/svelte/Surface.svelte.d.ts +9 -0
  97. package/dist/svelte/Surface.svelte.d.ts.map +1 -0
  98. package/dist/svelte/SurfaceBackdrop.svelte +26 -0
  99. package/dist/svelte/SurfaceBackdrop.svelte.d.ts +11 -0
  100. package/dist/svelte/SurfaceBackdrop.svelte.d.ts.map +1 -0
  101. package/dist/svelte/index.d.ts +13 -0
  102. package/dist/svelte/index.d.ts.map +1 -0
  103. package/dist/svelte/index.js +11 -0
  104. package/dist/svelte-core.d.ts +139 -0
  105. package/dist/svelte-core.js +123 -0
  106. package/dist/svelte-core.js.map +1 -0
  107. package/dist/tanstack.d.ts +240 -0
  108. package/dist/tanstack.js +110 -0
  109. package/dist/tanstack.js.map +1 -0
  110. package/dist/testing.js +4 -5
  111. package/dist/testing.js.map +1 -1
  112. package/dist/three.d.ts +223 -0
  113. package/dist/three.js +50 -0
  114. package/dist/three.js.map +1 -0
  115. package/dist/{tiers-B6pUBPcE.d.ts → tiers-BN4md-GB.d.ts} +2 -30
  116. package/dist/unovis.d.ts +127 -0
  117. package/dist/unovis.js +108 -0
  118. package/dist/unovis.js.map +1 -0
  119. package/dist/uplot.d.ts +120 -0
  120. package/dist/uplot.js +110 -0
  121. package/dist/uplot.js.map +1 -0
  122. package/dist/vega.js +5 -5
  123. package/dist/victory.d.ts +107 -0
  124. package/dist/victory.js +38 -0
  125. package/dist/victory.js.map +1 -0
  126. package/package.json +218 -6
  127. package/dist/chunk-KKH6ABMA.js.map +0 -1
  128. package/dist/chunk-QY65DUEF.js.map +0 -1
  129. package/dist/chunk-RMT2GMFH.js +0 -97
  130. package/dist/chunk-RMT2GMFH.js.map +0 -1
  131. package/dist/chunk-SEBO35DV.js +0 -76
  132. package/dist/chunk-SEBO35DV.js.map +0 -1
  133. package/dist/chunk-TDNBAEQB.js +0 -105
  134. package/dist/chunk-TDNBAEQB.js.map +0 -1
  135. package/dist/surfaces-ChaD9nei.d.ts +0 -38
@@ -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"]}
package/dist/vega.js CHANGED
@@ -1,8 +1,8 @@
1
- import { markPlacements, axisLetter, axisPlacements, aspect, imageSources, colorList } from './chunk-SEBO35DV.js';
2
- export { embedSources } from './chunk-SEBO35DV.js';
3
- import { checkHeight, checkAlpha, placedName } from './chunk-RMT2GMFH.js';
4
- import './chunk-KKH6ABMA.js';
5
- import './chunk-TAXO3VXH.js';
1
+ import { markPlacements, axisLetter, axisPlacements, aspect, imageSources, colorList } from './chunk-UL5M6KDE.js';
2
+ export { embedSources } from './chunk-UL5M6KDE.js';
3
+ import { checkHeight, checkAlpha, placedName } from './chunk-7ULOCCFL.js';
4
+ import './chunk-ZAEQXFJM.js';
5
+ import './chunk-J6R2LEJ7.js';
6
6
  import { InputError, UnsupportedTargetError } from './chunk-E7G7VSLV.js';
7
7
 
8
8
  // src/vega.ts
@@ -0,0 +1,107 @@
1
+ import { W as Which, S as SeasonInput, I as IdSystem, L as League } from './types-C7n6gJF3.js';
2
+ export { e as embedSources } from './_web-D7Aa5Rd8.js';
3
+
4
+ /** `teamColorPalette` options. */
5
+ interface VictoryColorOptions {
6
+ /** "primary" (default) or "secondary" colour. */
7
+ which?: Which;
8
+ /** The season the teams are resolved for (a number or string). */
9
+ season?: SeasonInput;
10
+ /** How the team values are read. Default "auto". */
11
+ idSystem?: IdSystem;
12
+ /** The colour of an unresolved team. Default "#808080". */
13
+ fallback?: string;
14
+ /**
15
+ * The chart's background. Given, a team colour under 3:1 contrast against it is swapped for the team's other
16
+ * colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A
17
+ * colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or
18
+ * the nearest colour to its own (lightness, hue or chroma stepped) that is distinct and still reads; failing that it
19
+ * is kept, with one warning.
20
+ */
21
+ background?: string;
22
+ }
23
+ /**
24
+ * One colour per team, in order: a `colorScale` for a `VictoryGroup`, `VictoryStack`, `VictoryPie` or
25
+ * `VictoryLegend`, or a series' `style.data.stroke` / `fill`. With `background`, every colour keeps 3:1 contrast
26
+ * against it (dark mode) and aims to stay distinct from the others (when it cannot, it keeps the readable colour and
27
+ * warns once). It has the shape of `sdvplot/echarts`'
28
+ * `teamColorPalette`; `teamTheme` puts the same colours into a Victory theme.
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
33
+ * import { teamColorPalette } from "@sportsdataverse/sdvplot/victory";
34
+ *
35
+ * await loadLeague("nfl");
36
+ * teamColorPalette("nfl", ["KC", "LAC", "DEN", "LV"], { background: "#181a1b" });
37
+ * ```
38
+ */
39
+ declare function teamColorPalette(league: League, teams: readonly unknown[], o?: VictoryColorOptions): string[];
40
+ /** `teamTheme` options: the teams, in the order the chart draws them, and an optional theme to build on. */
41
+ interface TeamThemeOptions<T extends object = Record<never, never>> extends VictoryColorOptions {
42
+ /** The league the teams belong to, e.g. "nfl". */
43
+ league: League;
44
+ /** Every team the chart draws, in order: a group's or stack's i-th child takes the i-th colour. */
45
+ teams: readonly unknown[];
46
+ /**
47
+ * The theme to build on, e.g. `VictoryTheme.clean`; its axes, fonts and every other key are kept. Default none: the
48
+ * result then holds only the colours, and Victory draws everything else unstyled.
49
+ */
50
+ base?: T;
51
+ }
52
+ type Scale = {
53
+ colorScale: string[];
54
+ };
55
+ type Painted<P extends string> = {
56
+ style: {
57
+ data: {
58
+ [K in P]: string;
59
+ };
60
+ };
61
+ };
62
+ /** What `teamTheme` writes into the theme. */
63
+ interface TeamThemeColors {
64
+ group: Scale;
65
+ stack: Scale;
66
+ pie: Scale;
67
+ legend: Scale;
68
+ /** A lone series takes the first team's colour. */
69
+ line: Painted<"stroke">;
70
+ area: Painted<"fill">;
71
+ bar: Painted<"fill">;
72
+ scatter: Painted<"fill">;
73
+ }
74
+ /**
75
+ * A Victory theme from team colours (`teamColorPalette`): the palette as the `colorScale` of every group, stack, pie
76
+ * and legend, so each child of a `VictoryGroup` is drawn in its team's colour, and the first team's colour for a lone
77
+ * line, area, bar or scatter. Built over `base` (a Victory theme), whose other keys and styles are kept. Pass it as a
78
+ * `VictoryChart`'s `theme`. With `background`, every colour keeps 3:1 contrast against it and aims to stay distinct from
79
+ * the others (else the readable colour and one warning); the chart's own background and axis ink are the base theme's to set.
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
84
+ * import { teamTheme } from "@sportsdataverse/sdvplot/victory";
85
+ * import { VictoryBar, VictoryChart, VictoryGroup, VictoryTheme } from "victory";
86
+ *
87
+ * await loadLeague("nfl");
88
+ * const rows = [
89
+ * { team: "KC", pf: 385 },
90
+ * { team: "BUF", pf: 525 },
91
+ * ];
92
+ * // each of the group's bars in its team's colour
93
+ * <VictoryChart
94
+ * theme={teamTheme({ league: "nfl", teams: rows.map((r) => r.team), base: VictoryTheme.clean })}
95
+ * domainPadding={60}
96
+ * >
97
+ * <VictoryGroup>
98
+ * {rows.map((r) => (
99
+ * <VictoryBar key={r.team} data={[r]} x="team" y="pf" />
100
+ * ))}
101
+ * </VictoryGroup>
102
+ * </VictoryChart>;
103
+ * ```
104
+ */
105
+ declare function teamTheme<T extends object = Record<never, never>>(o: TeamThemeOptions<T>): T & TeamThemeColors;
106
+
107
+ export { type TeamThemeColors, type TeamThemeOptions, type VictoryColorOptions, teamColorPalette, teamTheme };
@@ -0,0 +1,38 @@
1
+ import { colorPalette } from './chunk-UL5M6KDE.js';
2
+ export { embedSources } from './chunk-UL5M6KDE.js';
3
+ import './chunk-7ULOCCFL.js';
4
+ import './chunk-ZAEQXFJM.js';
5
+ import './chunk-J6R2LEJ7.js';
6
+ import { InputError } from './chunk-E7G7VSLV.js';
7
+
8
+ // src/victory.ts
9
+ function teamColorPalette(league, teams, o = {}) {
10
+ return colorPalette(league, teams, o);
11
+ }
12
+ function teamTheme(o) {
13
+ const { league, teams, base, ...co } = o;
14
+ if (teams.length === 0) throw new InputError("teamTheme needs at least one team");
15
+ const colors = teamColorPalette(league, teams, co);
16
+ const first = colors[0];
17
+ const b = base ?? {};
18
+ const scale = (k) => ({ ...b[k], colorScale: colors });
19
+ const paint = (k, prop) => ({
20
+ ...b[k],
21
+ style: { ...b[k]?.style, data: { ...b[k]?.style?.data, [prop]: first } }
22
+ });
23
+ return {
24
+ ...b,
25
+ group: scale("group"),
26
+ stack: scale("stack"),
27
+ pie: scale("pie"),
28
+ legend: scale("legend"),
29
+ line: paint("line", "stroke"),
30
+ area: paint("area", "fill"),
31
+ bar: paint("bar", "fill"),
32
+ scatter: paint("scatter", "fill")
33
+ };
34
+ }
35
+
36
+ export { teamColorPalette, teamTheme };
37
+ //# sourceMappingURL=victory.js.map
38
+ //# sourceMappingURL=victory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/victory.ts"],"names":[],"mappings":";;;;;;;;AA8CO,SAAS,gBAAA,CACd,MAAA,EACA,KAAA,EACA,CAAA,GAAyB,EAAC,EAChB;AACV,EAAA,OAAO,YAAA,CAAa,MAAA,EAAQ,KAAA,EAAO,CAAC,CAAA;AACtC;AA4DO,SAAS,UACd,CAAA,EACqB;AACrB,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,GAAG,IAAG,GAAI,CAAA;AACvC,EAAA,IAAI,MAAM,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,WAAW,mCAAmC,CAAA;AAChF,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,MAAA,EAAQ,KAAA,EAAO,EAAE,CAAA;AACjD,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AAEtB,EAAA,MAAM,CAAA,GAAK,QAAQ,EAAC;AACpB,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,MAAsB,EAAE,GAAG,CAAA,CAAE,CAAC,CAAA,EAAG,UAAA,EAAY,MAAA,EAAO,CAAA;AACnE,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAW,IAAA,MAAoC;AAAA,IAC5D,GAAG,EAAE,CAAC,CAAA;AAAA,IACN,OAAO,EAAE,GAAG,EAAE,CAAC,CAAA,EAAG,OAAO,IAAA,EAAM,EAAE,GAAG,CAAA,CAAE,CAAC,GAAG,KAAA,EAAO,IAAA,EAAM,CAAC,IAAI,GAAG,OAAM;AAAE,GACzE,CAAA;AACA,EAAA,OAAO;AAAA,IACL,GAAG,CAAA;AAAA,IACH,KAAA,EAAO,MAAM,OAAO,CAAA;AAAA,IACpB,KAAA,EAAO,MAAM,OAAO,CAAA;AAAA,IACpB,GAAA,EAAK,MAAM,KAAK,CAAA;AAAA,IAChB,MAAA,EAAQ,MAAM,QAAQ,CAAA;AAAA,IACtB,IAAA,EAAM,KAAA,CAAM,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAC5B,IAAA,EAAM,KAAA,CAAM,MAAA,EAAQ,MAAM,CAAA;AAAA,IAC1B,GAAA,EAAK,KAAA,CAAM,KAAA,EAAO,MAAM,CAAA;AAAA,IACxB,OAAA,EAAS,KAAA,CAAM,SAAA,EAAW,MAAM;AAAA,GAClC;AACF","file":"victory.js","sourcesContent":["/**\n * The Victory adapter: team colours as a Victory theme (`teamTheme`) or as a `colorScale` (`teamColorPalette`). Pure:\n * victory is never imported (the theme is a plain object, typed structurally and checked against victory 37.3's own\n * `VictoryThemeDefinition`). Call after `loadLeague(league)` / `preloadAll()`. The logos are components, `<LogoPoint>`\n * (a scatter's `dataComponent`) and `<LogoTick>` (an axis' `tickLabelComponent`), in `sdvplot/react`.\n */\nimport { colorPalette } from \"./_web.js\";\nimport { InputError } from \"./errors.js\";\nimport type { IdSystem, League, SeasonInput, Which } from \"./types.js\";\nexport { embedSources } from \"./_web.js\"; // public: build `<LogoPoint embed>` / `<LogoTick embed>` with it\n\n/** `teamColorPalette` options. */\nexport interface VictoryColorOptions {\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 (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}\n/**\n * One colour per team, in order: a `colorScale` for a `VictoryGroup`, `VictoryStack`, `VictoryPie` or\n * `VictoryLegend`, or a series' `style.data.stroke` / `fill`. With `background`, every colour keeps 3:1 contrast\n * against it (dark mode) and aims to stay distinct from the others (when it cannot, it keeps the readable colour and\n * warns once). It has the shape of `sdvplot/echarts`'\n * `teamColorPalette`; `teamTheme` puts the same colours into a Victory theme.\n *\n * @example\n * ```tsx\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamColorPalette } from \"@sportsdataverse/sdvplot/victory\";\n *\n * await loadLeague(\"nfl\");\n * teamColorPalette(\"nfl\", [\"KC\", \"LAC\", \"DEN\", \"LV\"], { background: \"#181a1b\" });\n * ```\n */\nexport function teamColorPalette(\n league: League,\n teams: readonly unknown[],\n o: VictoryColorOptions = {},\n): string[] {\n return colorPalette(league, teams, o);\n}\n\n/** `teamTheme` options: the teams, in the order the chart draws them, and an optional theme to build on. */\nexport interface TeamThemeOptions<T extends object = Record<never, never>> extends VictoryColorOptions {\n /** The league the teams belong to, e.g. \"nfl\". */\n league: League;\n /** Every team the chart draws, in order: a group's or stack's i-th child takes the i-th colour. */\n teams: readonly unknown[];\n /**\n * The theme to build on, e.g. `VictoryTheme.clean`; its axes, fonts and every other key are kept. Default none: the\n * result then holds only the colours, and Victory draws everything else unstyled.\n */\n base?: T;\n}\ntype Scale = { colorScale: string[] };\ntype Painted<P extends string> = { style: { data: { [K in P]: string } } };\n/** What `teamTheme` writes into the theme. */\nexport interface TeamThemeColors {\n group: Scale;\n stack: Scale;\n pie: Scale;\n legend: Scale;\n /** A lone series takes the first team's colour. */\n line: Painted<\"stroke\">;\n area: Painted<\"fill\">;\n bar: Painted<\"fill\">;\n scatter: Painted<\"fill\">;\n}\n\n/**\n * A Victory theme from team colours (`teamColorPalette`): the palette as the `colorScale` of every group, stack, pie\n * and legend, so each child of a `VictoryGroup` is drawn in its team's colour, and the first team's colour for a lone\n * line, area, bar or scatter. Built over `base` (a Victory theme), whose other keys and styles are kept. Pass it as a\n * `VictoryChart`'s `theme`. With `background`, every colour keeps 3:1 contrast against it and aims to stay distinct from\n * the others (else the readable colour and one warning); the chart's own background and axis ink are the base theme's to set.\n *\n * @example\n * ```tsx\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamTheme } from \"@sportsdataverse/sdvplot/victory\";\n * import { VictoryBar, VictoryChart, VictoryGroup, VictoryTheme } from \"victory\";\n *\n * await loadLeague(\"nfl\");\n * const rows = [\n * { team: \"KC\", pf: 385 },\n * { team: \"BUF\", pf: 525 },\n * ];\n * // each of the group's bars in its team's colour\n * <VictoryChart\n * theme={teamTheme({ league: \"nfl\", teams: rows.map((r) => r.team), base: VictoryTheme.clean })}\n * domainPadding={60}\n * >\n * <VictoryGroup>\n * {rows.map((r) => (\n * <VictoryBar key={r.team} data={[r]} x=\"team\" y=\"pf\" />\n * ))}\n * </VictoryGroup>\n * </VictoryChart>;\n * ```\n */\nexport function teamTheme<T extends object = Record<never, never>>(\n o: TeamThemeOptions<T>,\n): T & TeamThemeColors {\n const { league, teams, base, ...co } = o;\n if (teams.length === 0) throw new InputError(\"teamTheme needs at least one team\");\n const colors = teamColorPalette(league, teams, co);\n const first = colors[0] as string;\n type Piece = { style?: { data?: object } };\n const b = (base ?? {}) as Record<string, Piece | undefined>;\n const scale = (k: string): Scale => ({ ...b[k], colorScale: colors });\n const paint = (k: string, prop: \"stroke\" | \"fill\"): Piece => ({\n ...b[k],\n style: { ...b[k]?.style, data: { ...b[k]?.style?.data, [prop]: first } },\n });\n return {\n ...b,\n group: scale(\"group\"),\n stack: scale(\"stack\"),\n pie: scale(\"pie\"),\n legend: scale(\"legend\"),\n line: paint(\"line\", \"stroke\"),\n area: paint(\"area\", \"fill\"),\n bar: paint(\"bar\", \"fill\"),\n scatter: paint(\"scatter\", \"fill\"),\n } as T & TeamThemeColors;\n}\n"]}