@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
package/NOTICE.md CHANGED
@@ -17,6 +17,11 @@
17
17
  (Copyright 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University, Apache License 2.0);
18
18
  `sizeCells` ports `quantile` from **d3-array** 3.2.4 (Copyright 2010-2023 Mike Bostock, ISC). The ISC permission
19
19
  notice and ColorBrewer's licence notice follow this list verbatim.
20
+ - `@sportsdataverse/sdvplot/lightweight-charts` works with **TradingView Lightweight Charts™** (Apache License 2.0), an
21
+ optional peer it never imports or redistributes. Lightweight Charts' licence asks every page that shows one of its
22
+ charts for TradingView's attribution notice (below, verbatim from its NOTICE file) and a link to
23
+ https://www.tradingview.com/. `withAttribution` keeps the library's attribution logo, that link, on by default;
24
+ `attributionNotice` puts the notice (`TRADINGVIEW_NOTICE`) on the page.
20
25
 
21
26
  ## d3-hexbin
22
27
 
@@ -92,3 +97,13 @@ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
92
97
  CONDITIONS OF ANY KIND, either express or implied. See the License for the
93
98
  specific language governing permissions and limitations under the License.
94
99
  ```
100
+
101
+ ## TradingView Lightweight Charts (Apache License 2.0)
102
+
103
+ The `NOTICE` file of tradingview/lightweight-charts at tag v5.2.1
104
+ (https://github.com/tradingview/lightweight-charts/blob/v5.2.1/NOTICE), verbatim:
105
+
106
+ ```text
107
+ TradingView Lightweight Charts™
108
+ Copyright (с) 2025 TradingView, Inc. https://www.tradingview.com/
109
+ ```
package/README.md CHANGED
@@ -32,13 +32,21 @@ pnpm add @sportsdataverse/sdvplot
32
32
  yarn add @sportsdataverse/sdvplot
33
33
  ```
34
34
 
35
- ESM only, Node >= 20.18.1. The core and the `bins`, `testing`, `plotly`, `vega` and `echarts` subpaths need no
36
- peer. The others use optional peers, which npm and pnpm do not install for you, so add the ones for the subpaths you
37
- import: `react` >= 18 for `/react`, `@observablehq/plot` >= 0.6.16 for `/plot`, `d3` >= 7 for `/d3` and `/interact`,
38
- `chart.js` >= 4.4 for `/chartjs` and `/chartjs/surface`, and `@resvg/resvg-js` for `/export`'s `toPNG`.
35
+ ESM only, Node >= 20.18.1. The core and the `bins`, `testing`, `plotly`, `vega`, `echarts`, `uplot`, `victory`,
36
+ `cytoscape`, `lightweight-charts`, `g2`, `tanstack`, `maplibre`, `unovis` and `perspective` subpaths need no peer. The others use optional peers, which npm and pnpm do not
37
+ install for you, so add the ones for the subpaths you import: `react` >= 18 for `/react` (with `victory` >= 37.3.6
38
+ for `<LogoPoint>` and `<LogoTick>`), `/recharts` and `/shadcn` (with `recharts` >= 3.8 to draw; `/shadcn` configures
39
+ shadcn/ui's copy-paste `chart.tsx`, which is not a package), `/mui` (with `@mui/x-charts` >= 9.15.0 to draw) and `/nivo` (with `@nivo/core` and the chart's `@nivo/*`
40
+ package >= 0.99 to draw; `<LogoBump>` loads `@nivo/bump`), `@observablehq/plot` >= 0.6.16 for
41
+ `/plot`, `d3` >= 7 for `/d3` and `/interact`, `chart.js` >= 4.4 for `/chartjs` and `/chartjs/surface`, `svelte` >=
42
+ 5.57 and `layerchart` >= 2.5.1 for `/svelte`, `@sportsdataverse/sporty` for `/deckgl` (draw its props with
43
+ `@deck.gl/core` and `@deck.gl/layers` >= 9.4) and for `/three` (draw its buffers with `three` >= 0.186.1; `/react`'s
44
+ `<Surface3D>` and `<Trajectory>` also need `@react-three/fiber` >= 9.8.1), and `@resvg/resvg-js` for `/export`'s
45
+ `toPNG`.
39
46
 
40
47
  `/plot`, `/d3`, `/shots` and `/chartjs/surface` also need `@sportsdataverse/sporty`, whether or not you draw a
41
- surface: they import it when they load, and fail to load without it. No other subpath imports sporty. For a Plot chart:
48
+ surface: they import it when they load, and fail to load without it. No other subpath imports sporty when it loads
49
+ (`/react`'s `<SurfaceBackdrop>` loads it, with recharts, when it first renders). For a Plot chart:
42
50
 
43
51
  ```sh
44
52
  npm install @sportsdataverse/sdvplot @sportsdataverse/sporty @observablehq/plot
@@ -111,12 +119,12 @@ The backgrounds default to `#ffffff` (light) and `#181a1b` (dark); pass `theme:
111
119
  | Import | Contents |
112
120
  | --- | --- |
113
121
  | `@sportsdataverse/sdvplot` | `resolve`, `suggest`, `teams`, `rowsFrom`, `palette`, `teamColors`, `matchupColors`, `logoUrl`, `marks` (`full: true` fetches the whole manifest lazily), `selectMark`, `selectMarkSync`, `place`, `placeSync`, `prepareTiers`, `headshotUrl`, `loadGsis`, contrast helpers (`hex6`, `luminance`, `contrast`, `onColor`, `mix`, `solid`), the selection store `createSelection` with `focusIds`, `toId`, `sameIds`, `sameCursor` (see [Linked interactivity](#linked-interactivity)), `versions`, errors, types |
114
- | `@sportsdataverse/sdvplot/react` | `TeamLogo`, `Wordmark`, `Headshot`, `useTeamColors`, `useResolve`, `useSelection` (re-renders on every change of a selection store) (React >= 18, optional peer) |
115
- | `@sportsdataverse/sdvplot/plot` | Observable Plot marks and scales: `logos`, `wordmarks`, `headshots`, `axisLogos`, `teamColor`/`teamFill`, `meanLines`/`medianLines`, `titleImage`, `teamTiers`, `surface`, shot-chart marks `shotCells`, `shotZones`, `shootingSignature`, `linkIds` (stamps any mark's link ids; the image marks take an `id` option) (needs `@observablehq/plot` and `@sportsdataverse/sporty` installed to import) |
122
+ | `@sportsdataverse/sdvplot/react` | `TeamLogo`, `Wordmark`, `Headshot`, `useTeamColors`, `useResolve`, `useSelection` (re-renders on every change of a selection store), `SurfaceBackdrop` (a court, field or rink under a Recharts chart; loads `recharts` and `@sportsdataverse/sporty` when it renders), `LogoBump` (a nivo bump chart with team colours and end logos; loads `@nivo/bump` when it renders), `LogoPoint` and `LogoTick` (team logos as a Victory scatter's points and an axis' tick labels) (React >= 18, optional peer) |
123
+ | `@sportsdataverse/sdvplot/plot` | Observable Plot marks and scales: `logos`, `wordmarks`, `headshots`, `axisLogos`, `teamColor`/`teamFill`, `meanLines`/`medianLines`, `titleImage`, `teamTiers`, `surface` (any of the 59 keys in `SURFACES`, ten sports: team leagues paint the surface, lacrosse, tennis, volleyball and curling keys draw it plain), shot-chart marks `shotCells`, `shotZones`, `shootingSignature`, `linkIds` (stamps any mark's link ids; the image marks take an `id` option) (needs `@observablehq/plot` and `@sportsdataverse/sporty` installed to import) |
116
124
  | `@sportsdataverse/sdvplot/d3` | `appendLogos`, `appendWordmarks`, `appendHeadshots` (circular faces: `clip`, `ring`, `placeholder`), `teamColorScale`, `appendSurface`, shot-chart `appendLegend` and `appendSignature` (needs `d3` and `@sportsdataverse/sporty` installed to import) |
117
125
  | `@sportsdataverse/sdvplot/bins` | Dependency-free x/y binning for any data: `hexbin` and `hexagonPath` (a d3-hexbin port), `squarebin` and `squarePath`, `binner` (hexagons, squares, or equal-area squares from one options object), `cellPath`, `cellPoints` |
118
126
  | `@sportsdataverse/sdvplot/shots` | Shot-chart data and colour, no Plot or d3: the `./bins` binners, `diffScale`, `binShots`, `leagueIndex`, `cellsVsLeague`, `cellsVsDistance`, `shrunkDiff`, `LEAGUE_PRIOR_ATTEMPTS`, `sizeCells`, `statsByZone`, `fgPctByDistance`, `vsLeague`, `statsBySide`, `signaturePoints` (needs `@sportsdataverse/sporty` installed to import; `./bins` has the binners without it) |
119
- | `@sportsdataverse/sdvplot/chartjs` | Chart.js 4: `logoPoints`, `wordmarkPoints`, `headshotPoints`, `pointImages`, `axisLogos`, `logoWatermarks`, `teamColor`/`teamFill` (optional peer `chart.js` >= 4.4; no sporty needed) |
127
+ | `@sportsdataverse/sdvplot/chartjs` | Chart.js 4: `logoPoints`, `wordmarkPoints`, `headshotPoints`, `pointImages`, `axisLogos`, `logoWatermarks`, `teamColor`/`teamFill`, `teamColorPalette` (with `background`: 3:1 contrast and distinct colours for dark mode); works as is through react-chartjs-2 (optional peer `chart.js` >= 4.4; no sporty needed) |
120
128
  | `@sportsdataverse/sdvplot/chartjs/surface` | Chart.js 4 court, field or rink background: `surface` (needs `@sportsdataverse/sporty` installed to import; optional peer `chart.js` >= 4.4) |
121
129
  | `@sportsdataverse/sdvplot/export` | Node only: `toPNG` (SVG to PNG; optional peer `@resvg/resvg-js`), `socialCard` (fixed-ratio framing, `gt_social_crop`), `svgSize`, `parseAspect`, `parseGravity`, `checkColor`, `canvasFor`, `offsetFor`, `peerMissing` |
122
130
  | `@sportsdataverse/sdvplot/interact` | Linked figures over a selection store: `brushFilter` (a d3-brush overlay behind the marks writes the brushed ids and region; on a figure with a Plot `tip`, the press that starts a brush also pins the tip showing at that moment), `highlight`, `linkSelection` (one figure or one sdvtables table per call: hover and selection both ways, and a brush filters a linked table; a Plot `tip` hovers through `hover: { id }`), `linkCursor` (the store's `cursor`, one shared hover value such as a shot distance, drawn and emitted through each figure's own scale as a rule, a band or a ring around the hoop; unrelated to sdvtables' keyboard `TableCursor`), `nearestHover` (the nearest mark of a d3 or other non-Plot figure within a radius writes `hover`), `tooltip` (an in-SVG tooltip box for non-Plot figures), `hasDom` (optional peer `d3`; inert without a DOM) |
@@ -124,6 +132,22 @@ The backgrounds default to `#ffffff` (light) and `#181a1b` (dark); pass `theme:
124
132
  | `@sportsdataverse/sdvplot/plotly` | `withLogos`, `withWordmarks`, `withHeadshots`, `withAxisLogos`, `teamColorway`, `embedSources` (no runtime dependency) |
125
133
  | `@sportsdataverse/sdvplot/vega` | `withLogos`, `withWordmarks`, `withHeadshots`, `logoLayer`, `withAxisLogos`, `teamColorScale`, `embedSources` (no runtime dependency) |
126
134
  | `@sportsdataverse/sdvplot/echarts` | `withLogos`, `withWordmarks`, `withHeadshots`, `withAxisLogos`, `teamColorPalette`, `embedSources` (no runtime dependency) |
135
+ | `@sportsdataverse/sdvplot/recharts` | Recharts render props: `logoDot`, `headshotDot` (a series' `dot` / `shape`), `logoTick` (an axis' `tick`), `teamColorPalette` (with `background`: 3:1 contrast for dark mode), `embedSources` (React >= 18; never imports recharts, an optional peer >= 3.8) |
136
+ | `@sportsdataverse/sdvplot/shadcn` | `teamChartConfig`: shadcn/ui's `ChartConfig` for teams, with CSS-safe `keys`, `theme` light and dark colours (3:1 on shadcn's backgrounds) and team logos as the legend and tooltip `icon` (React >= 18; shadcn's `chart.tsx` is copied into your app, not installed) |
137
+ | `@sportsdataverse/sdvplot/mui` | MUI X Charts: `teamColors` (a chart's `colors`, following MUI's light and dark mode with 3:1 contrast), `teamColorPalette`, `teamColorGetter` (a series' `colorGetter`, a colour per bar or point), `logoMarker` and `headshotMarker` (a scatter's `marker` slot), `logoMark` (a line's `mark` slot: logos at the ends of lines), `logoTickLabel` (an axis' `axisTickLabel` slot), `embedSources` (React >= 18; never imports MUI, `@mui/x-charts` >= 9.15.0 is an optional peer) |
138
+ | `@sportsdataverse/sdvplot/uplot` | `withTeamSeries` (series strokes and fills in team colours; with `background`, 3:1 contrast for dark mode), `logoPlugin` (a uPlot plugin painting team logos on the canvas at data points; rows can follow live data) (no runtime dependency; draw with `uplot` >= 1.6.31, an optional peer) |
139
+ | `@sportsdataverse/sdvplot/svelte` | Svelte 5 components for LayerChart charts: `LogoMark` (team logos or wordmarks at data points), `HeadshotMark`, `SurfaceBackdrop` (a team-painted court, field or rink in the chart's units), plus `teamColorPalette` (with `background`, 3:1 contrast for dark mode and distinct teams) and `embedSources` (optional peers `svelte` >= 5.57 and `layerchart` >= 2.5.1, loaded when a component renders; `SurfaceBackdrop` also needs `@sportsdataverse/sporty`) |
140
+ | `@sportsdataverse/sdvplot/nivo` | `teamColors` (a chart's `colors`; with `background` and `teams`: 3:1 contrast and distinct colours for dark mode), `logoLayer` (a custom layer of logos over a Bump, SwarmPlot or Chord), `logoNode` (logos as a SwarmPlot's or Bump's nodes), `embedSources` (React >= 18; never imports nivo, optional peers >= 0.99) |
141
+ | `@sportsdataverse/sdvplot/victory` | `teamTheme` (a Victory theme from team colours), `teamColorPalette` (a `colorScale`; with `background`: 3:1 contrast and distinct colours for dark mode), `embedSources` (no runtime dependency; draw with `victory` >= 37.3.6) |
142
+ | `@sportsdataverse/sdvplot/deckgl` | `logoIconLayer` (IconLayer props: team logos at points), `passArcLayer` (ArcLayer props in team colours; with `background`, 3:1 contrast and distinct), `surfaceLayer` (PolygonLayer props: a sporty surface in its own cartesian coordinates) (never imports deck.gl; `@deck.gl/core` and `@deck.gl/layers` >= 9.4 are optional peers) |
143
+ | `@sportsdataverse/sdvplot/cytoscape` | `passNetwork` (a passing network as Cytoscape elements and stylesheet: headshot or team-coloured initials nodes, directed edges as wide as their passes), `teamStylesheet` (team colours for nodes and edges; with `background`, 3:1 contrast and distinct) (never imports cytoscape; `cytoscape` >= 3.34.3 is an optional peer) |
144
+ | `@sportsdataverse/sdvplot/three` | Plain mesh buffers in world units for Three.js: `surfaceMesh` (a sporty surface as one triangle mesh at z = 0), `trajectoryTube` (a team-coloured tube along a 3D path), `teamColorPalette`, `statcastPitchPath` (a Statcast pitch's flight); `/react` draws them with `<Surface3D>` and `<Trajectory>` (never imports three; `three` >= 0.186.1 and `@react-three/fiber` >= 9.8.1 are optional peers) |
145
+ | `@sportsdataverse/sdvplot/g2` | G2 5 spec pieces, for G2 and for Ant Design Charts (`@ant-design/plots`) configs: `teamColorScale` (a `scale.color`; with `background`, 3:1 contrast for dark mode), `teamColorPalette`, `logoMark`, `wordmarkMark`, `headshotMark` (G2 `image` marks, sized in px, for a view's `children` or an Ant Design Charts config's `annotations`), `axisLogos` (logos as a horizontal band axis' labels, through G2's `labelRender`), `drawnMarks`, `embedSources` (no runtime dependency; draw with `@antv/g2` >= 5.4.8, an optional peer; `axisLogos` needs `@antv/component` >= 2.1.12, also an optional peer) |
146
+ | `@sportsdataverse/sdvplot/tanstack` | TanStack Charts: `teamColorScale` (the chart's `color` option, the team values kept as the data holds them; with `background`, 3:1 contrast for dark mode), `teamColorPalette`, `logoDots`, `wordmarkDots`, `headshotDots` (one `dot` mark per image, filled with an SVG pattern of it, sized in px), `withPatterns` (the chart's `renderSvg`, writing the patterns into its SVG), `drawnMarks`, `embedSources` (no runtime dependency; draw with `@tanstack/charts` >= 1.1.0, an optional peer, on its SVG renderer) |
147
+ | `@sportsdataverse/sdvplot/maplibre` | MapLibre GL JS style JSON: `logoSymbols` (a GeoJSON source and a `symbol` layer of team logos at longitude and latitude, numeric or string team ids), `addLogoImages` (loads each logo into a map once, `size` px tall), `routeLines` (a `line` layer of travel legs in team colours; with `background`, 3:1 contrast for dark mode), `basemap` (OpenFreeMap's keyless light or dark style, with its credit and background), `drawnMarks` (no runtime dependency; draw with `maplibre-gl` >= 6.14.0, an optional peer, which TypeScript also needs installed because the type declarations name its types; for deck.gl layers over the map, `/deckgl`'s props through `@deck.gl/mapbox` >= 9.4.0; see the [MapLibre guide](https://plot.sportsdataverse.org/guides/maplibre)) |
148
+ | `@sportsdataverse/sdvplot/unovis` | Unovis accessor helpers: `teamColorScale` (a team colour function for `nodeFill`, `nodeStroke`, `linkStroke`, `nodeColor` or `linkColor`, by any value naming the team; with `background`, 3:1 contrast for dark mode), `teamColorPalette`, `logoIcons`, `headshotIcons` (images for a Graph's `nodeIcon`, with the `<symbol>`s for the container's `svgDefs`) (no runtime dependency; draw with `@unovis/ts` >= 1.7.1, an optional peer; in React, `@unovis/react` together with `@unovis/ts` at the same version; guide: [Unovis](https://plot.sportsdataverse.org/guides/unovis)) |
149
+ | `@sportsdataverse/sdvplot/perspective` | Perspective viewer data, the same as sdvplot (Python)'s `sdvplot.perspective` builds: `perspectiveConfig` (a config for `viewer.restore()`: team colours on the Datagrid's team cells and on split charts' series, number formats, a logo column as links; with `mode: "dark"`, Pro Dark and 3:1 contrast; with `theme`, a registry table theme's fonts and sign colours on the Datagrid, from sdvtables' `tableThemeSpec`), `perspectiveLogoColumn` (rows with a logo URL column after the team) (no runtime dependency, and its type declarations name no Perspective type; draw with `@perspective-dev/viewer` >= 5.5.1, an optional peer, with `-datagrid`, `-charts`, `@perspective-dev/client` and `@perspective-dev/server` at the same version; guide: [Perspective](https://plot.sportsdataverse.org/guides/perspective)) |
150
+ | `@sportsdataverse/sdvplot/lightweight-charts` | `withAttribution` (TradingView's attribution logo on by default), `attributionNotice` (puts TradingView's notice, `TRADINGVIEW_NOTICE`, on the page under the chart), `teamSeriesOptions` (a line in team colours; prices read as probabilities or American odds), `logoMarkers` (a series primitive painting team logos at points) (no runtime dependency; draw with `lightweight-charts` >= 5.2.1, an optional peer, Apache-2.0 with an attribution notice) |
127
151
 
128
152
  ## **Observable Plot: Plot's own options, transforms and tips**
129
153
 
@@ -372,6 +396,43 @@ const rows = await getTeamRows();
372
396
  <canvas bind:this={canvas}></canvas>
373
397
  ```
374
398
 
399
+ In React, [react-chartjs-2](https://react-chartjs-2.js.org) (tested with react-chartjs-2 5.3.1) takes the same pieces as
400
+ props. They build `<img>` elements, which need a DOM, and a client component still renders once on the server (Next.js):
401
+ build them after mount, in an effect, as here, or load the chart component with `next/dynamic` and `{ ssr: false }`.
402
+
403
+ ```tsx
404
+ import { type ChartData, Chart as ChartJS, registerables } from "chart.js";
405
+ import { useEffect, useState } from "react";
406
+ import { Chart } from "react-chartjs-2";
407
+ import { logoPoints, pointImages } from "@sportsdataverse/sdvplot/chartjs";
408
+
409
+ ChartJS.register(...registerables); // global, once: Chart.js's controllers and scales; sdvplot's plugins stay per chart
410
+
411
+ // after `await loadLeague("nfl")`
412
+ export function TeamScatter({ rows }: { rows: { team: string; pf: number; pa: number }[] }) {
413
+ const [data, setData] = useState<ChartData<"scatter"> | null>(null);
414
+ useEffect(() => {
415
+ // in the browser only: the point styles are <img> elements
416
+ setData({
417
+ datasets: [
418
+ {
419
+ label: "teams", // react-chartjs-2 updates a dataset in place by its label: new rows bring new logos
420
+ data: rows.map((r) => ({ x: r.pf, y: r.pa })),
421
+ ...logoPoints(rows.map((r) => r.team), { league: "nfl", radius: 14 }),
422
+ },
423
+ ],
424
+ });
425
+ }, [rows]);
426
+ return data === null ? null : <Chart type="scatter" data={data} plugins={[pointImages]} />;
427
+ }
428
+ ```
429
+
430
+ react-chartjs-2 reads `plugins` only when it creates the chart. `pointImages` and `axisLogos` read the chart's data on
431
+ every update, so new rows or labels are drawn; `logoWatermarks(teams)` and `surface(league)` keep what they were built
432
+ with, so give `<Chart>` a `key` that changes with them (`key={teams.join()}`) to build a new chart (react-chartjs-2's `redraw` is
433
+ not the same: it rebuilds on every render). See the
434
+ [react-chartjs-2 guide](https://plot.sportsdataverse.org/guides/react-chartjs-2).
435
+
375
436
  The line charts below draw Super Bowl LIX (Kansas City at Philadelphia, 2025-02-09). `wp` is ESPN's win probability
376
437
  for Philadelphia, the home team, after each of the game's 186 plays, against minutes played:
377
438
  `[{ minute: 0, home_wp: 0.5846 }, …, { minute: 60, home_wp: 1 }]`. These are the repo's real `SUPER_BOWL_LIX_WP` rows
@@ -550,6 +611,21 @@ chart.destroy();
550
611
  - In Node an unknown team's text fallback is a circle (there is no canvas to letter it on); pass `fallback` for another
551
612
  style. A load that fails warns once and is skipped.
552
613
 
614
+ ## **Victory (React; React Native notes)**
615
+
616
+ `@sportsdataverse/sdvplot/victory` gives a Victory chart its team colours: `teamTheme({ league, teams, base })` is a
617
+ theme (pass it as a `VictoryChart`'s `theme`) whose group, stack, pie and legend `colorScale` is the teams' colours,
618
+ and `teamColorPalette(league, teams)` is the same colours as a list. `sdvplot/react` adds `<LogoPoint>` (a
619
+ `VictoryScatter`'s `dataComponent`: each point drawn as its team's logo, twice the scatter's `size` tall) and
620
+ `<LogoTick>` (a `VictoryAxis`' `tickLabelComponent`: each team label drawn as its logo, `size` px tall). The guide is
621
+ [Victory](https://plot.sportsdataverse.org/guides/victory).
622
+
623
+ React Native: these target Victory on the web, and none of them has been tried in React Native. `victory-native` 41
624
+ and later is a different library from `victory`, drawn with Skia, with no theme object and no `dataComponent`, so
625
+ `teamTheme`, `<LogoPoint>` and `<LogoTick>` (react-dom SVG) do not carry over. What does is the data: the colours
626
+ `teamColorPalette` returns are plain hex strings for a victory-native series' `color`, and `logoUrlSync` (core) gives
627
+ the logo URL to load as a Skia image.
628
+
553
629
  ## **Shot charts**
554
630
 
555
631
  `sdvplot/shots` computes the shot charts of both blazing-the-nets apps (`main` by default, the 2021 `master` through
@@ -1,6 +1,6 @@
1
1
  import { Scene } from '@sportsdataverse/sporty';
2
2
  import { Plugin } from 'chart.js';
3
- import { S as SurfaceSceneOptions } from './surfaces-ChaD9nei.js';
3
+ import { S as SurfaceSceneOptions } from './surfaces-W-odWLpT.js';
4
4
  import { L as League } from './types-C7n6gJF3.js';
5
5
  import './resolve-CQW-jzvr.js';
6
6
 
@@ -37,6 +37,6 @@ interface ChartSurface {
37
37
  * court. Throws `InputError` for a league without a surface, or for a scene whose bbox is empty (an `xlim` or `ylim` of
38
38
  * zero width) here, when it is built, not inside a Chart.js draw. A non-linear axis is left unpainted, with one warning.
39
39
  */
40
- declare function surface(league: League, o?: ChartSurfaceOptions): ChartSurface;
40
+ declare function surface(league: League | (string & {}), o?: ChartSurfaceOptions): ChartSurface;
41
41
 
42
42
  export { type ChartSurface, type ChartSurfaceOptions, type LinearScale, surface };
@@ -1,6 +1,6 @@
1
- import { surfaceScene } from './chunk-TDNBAEQB.js';
1
+ import { surfaceScene } from './chunk-57WFSI4Q.js';
2
+ import './chunk-ZAEQXFJM.js';
2
3
  import './chunk-J6R2LEJ7.js';
3
- import './chunk-TAXO3VXH.js';
4
4
  import { InputError, warn } from './chunk-E7G7VSLV.js';
5
5
  import { drawScene } from '@sportsdataverse/sporty/canvas';
6
6
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chartjs-surface.ts"],"names":[],"mappings":"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","file":"chartjs-surface.js","sourcesContent":["/**\n * Chart.js 4 court / field / rink background: `surface(league, o)` paints a team-painted sporty scene under the\n * datasets. Split from `sdvplot/chartjs` because it draws through `@sportsdataverse/sporty/canvas`, which the logo and\n * colour plugins do not need. sporty is an optional peer, but this entry imports it when it loads, so install it to use\n * `sdvplot/chartjs/surface`. `chart.js` is a type-only import (optional peer, 4.4 or later).\n */\nimport type { Scene } from \"@sportsdataverse/sporty\";\nimport { drawScene } from \"@sportsdataverse/sporty/canvas\";\nimport type { Chart, Plugin } from \"chart.js\";\nimport { InputError, warn } from \"./errors.js\";\nimport { type SurfaceSceneOptions, surfaceScene } from \"./surfaces.js\";\nimport type { League } from \"./types.js\";\n\nexport interface ChartSurfaceOptions extends SurfaceSceneOptions {\n /** The linear x scale's id (default `\"x\"`). */\n xAxisID?: string;\n /** The linear y scale's id (default `\"y\"`). */\n yAxisID?: string;\n}\nexport interface LinearScale {\n type: \"linear\";\n min: number;\n max: number;\n}\nexport interface ChartSurface {\n /** Paints the surface before the datasets (`beforeDatasetsDraw`), clipped to the chart area. */\n plugin: Plugin;\n /** Linear scales spanning the surface, for `options.scales` (keep both axes linear). */\n scales: { x: LinearScale; y: LinearScale };\n scene: Scene;\n}\n/**\n * A team-painted sporty surface as a Chart.js background: a shot chart is a scatter (a hexbin, a bubble chart) over a\n * court. Throws `InputError` for a league without a surface, or for a scene whose bbox is empty (an `xlim` or `ylim` of\n * zero width) here, when it is built, not inside a Chart.js draw. A non-linear axis is left unpainted, with one warning.\n */\nexport function surface(league: League, o: ChartSurfaceOptions = {}): ChartSurface {\n const { xAxisID = \"x\", yAxisID = \"y\", ...rest } = o;\n const scene = surfaceScene(league, rest);\n const [x0, y0, x1, y1] = scene.bbox;\n // drawScene would throw sporty's InputError on the first draw, inside Chart.js's render loop\n if (!(x1 > x0 && y1 > y0 && Number.isFinite(x1 - x0 + y1 - y0)))\n throw new InputError(\n `surface(\"${league}\"): the scene's bbox [${scene.bbox.join(\", \")}] is empty, so there is nothing to draw (check xlim / ylim)`,\n );\n return {\n plugin: {\n id: \"sdvplotSurface\",\n // Chart.js has no plugin priority: inline plugins run in array order, so a watermark listed first is painted over\n start: (chart) => {\n const ps = chart.config.plugins ?? [];\n const own = ps.findIndex((p) => p.id === \"sdvplotSurface\");\n const wm = ps.findIndex((p) => p.id === \"sdvplotLogoWatermarks\");\n if (wm !== -1 && (own === -1 || wm < own))\n warn(\n \"chartjs:surface:order\",\n \"logoWatermarks is listed before the surface plugin, so the court is painted over it; list court.plugin first\",\n );\n },\n beforeDatasetsDraw: (chart) => paintScene(chart, scene, xAxisID, yAxisID),\n },\n scales: { x: { type: \"linear\", min: x0, max: x1 }, y: { type: \"linear\", min: y0, max: y1 } },\n scene,\n };\n}\nfunction paintScene(chart: Chart, scene: Scene, xId: string, yId: string): void {\n const { ctx, chartArea: a } = chart;\n const xs = chart.scales[xId];\n const ys = chart.scales[yId];\n if (!a || xs === undefined || ys === undefined) return; // a draw before the first layout\n if (xs.type !== \"linear\" || ys.type !== \"linear\") {\n warn(\n `chartjs:surface:${xId}:${yId}`,\n `surface needs linear scales (pass court.scales); ${xId} is ${xs.type} and ${yId} is ${ys.type}, so it is not drawn`,\n );\n return;\n }\n const ox = xs.getPixelForValue(0);\n const oy = ys.getPixelForValue(0);\n const kx = xs.getPixelForValue(1) - ox; // px per scene unit; negative on a reversed axis\n const ky = ys.getPixelForValue(1) - oy; // negative: y points up\n const s = Math.abs(kx);\n if (!(s > 0 && Number.isFinite(s + ky))) return; // a zero-size chart area\n const [x0, , , y1] = scene.bbox;\n ctx.save();\n ctx.beginPath();\n ctx.rect(a.left, a.top, a.right - a.left, a.bottom - a.top);\n ctx.clip();\n // drawScene paints (x, y) at (s(x - x0), s(y1 - y)) and composes with the current transform (the chart's own\n // device-pixel-ratio transform stays under both): this map turns that into the chart's scales, axis by axis.\n ctx.transform(kx / s, 0, 0, -ky / s, ox + kx * x0, oy + ky * y1);\n drawScene(ctx, scene, { scale: s }); // strokes are 1/s scene units: one px wide\n ctx.restore();\n}\n"]}
1
+ {"version":3,"sources":["../src/chartjs-surface.ts"],"names":[],"mappings":";;;;;;AAoCO,SAAS,OAAA,CAAQ,MAAA,EAAgC,CAAA,GAAyB,EAAC,EAAiB;AACjG,EAAA,MAAM,EAAE,OAAA,GAAU,GAAA,EAAK,UAAU,GAAA,EAAK,GAAG,MAAK,GAAI,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,MAAA,EAAQ,IAAI,CAAA;AACvC,EAAA,MAAM,CAAC,EAAA,EAAI,EAAA,EAAI,EAAA,EAAI,EAAE,IAAI,KAAA,CAAM,IAAA;AAE/B,EAAA,IAAI,EAAE,EAAA,GAAK,EAAA,IAAM,EAAA,GAAK,EAAA,IAAM,OAAO,QAAA,CAAS,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAE,CAAA,CAAA;AAC3D,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,YAAY,MAAM,CAAA,sBAAA,EAAyB,MAAM,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA,2DAAA;AAAA,KAClE;AACF,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ;AAAA,MACN,EAAA,EAAI,gBAAA;AAAA;AAAA,MAEJ,KAAA,EAAO,CAAC,KAAA,KAAU;AAChB,QAAA,MAAM,EAAA,GAAK,KAAA,CAAM,MAAA,CAAO,OAAA,IAAW,EAAC;AACpC,QAAA,MAAM,MAAM,EAAA,CAAG,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,gBAAgB,CAAA;AACzD,QAAA,MAAM,KAAK,EAAA,CAAG,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,uBAAuB,CAAA;AAC/D,QAAA,IAAI,EAAA,KAAO,EAAA,KAAO,GAAA,KAAQ,EAAA,IAAM,EAAA,GAAK,GAAA,CAAA;AACnC,UAAA,IAAA;AAAA,YACE,uBAAA;AAAA,YACA;AAAA,WACF;AAAA,MACJ,CAAA;AAAA,MACA,oBAAoB,CAAC,KAAA,KAAU,WAAW,KAAA,EAAO,KAAA,EAAO,SAAS,OAAO;AAAA,KAC1E;AAAA,IACA,QAAQ,EAAE,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,KAAK,EAAA,EAAI,GAAA,EAAK,IAAG,EAAG,CAAA,EAAG,EAAE,IAAA,EAAM,QAAA,EAAU,KAAK,EAAA,EAAI,GAAA,EAAK,IAAG,EAAE;AAAA,IAC3F;AAAA,GACF;AACF;AACA,SAAS,UAAA,CAAW,KAAA,EAAc,KAAA,EAAc,GAAA,EAAa,GAAA,EAAmB;AAC9E,EAAA,MAAM,EAAE,GAAA,EAAK,SAAA,EAAW,CAAA,EAAE,GAAI,KAAA;AAC9B,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,MAAA,CAAO,GAAG,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,MAAA,CAAO,GAAG,CAAA;AAC3B,EAAA,IAAI,CAAC,CAAA,IAAK,EAAA,KAAO,MAAA,IAAa,OAAO,MAAA,EAAW;AAChD,EAAA,IAAI,EAAA,CAAG,IAAA,KAAS,QAAA,IAAY,EAAA,CAAG,SAAS,QAAA,EAAU;AAChD,IAAA,IAAA;AAAA,MACE,CAAA,gBAAA,EAAmB,GAAG,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA;AAAA,MAC7B,CAAA,iDAAA,EAAoD,GAAG,CAAA,IAAA,EAAO,EAAA,CAAG,IAAI,CAAA,KAAA,EAAQ,GAAG,CAAA,IAAA,EAAO,EAAA,CAAG,IAAI,CAAA,oBAAA;AAAA,KAChG;AACA,IAAA;AAAA,EACF;AACA,EAAA,MAAM,EAAA,GAAK,EAAA,CAAG,gBAAA,CAAiB,CAAC,CAAA;AAChC,EAAA,MAAM,EAAA,GAAK,EAAA,CAAG,gBAAA,CAAiB,CAAC,CAAA;AAChC,EAAA,MAAM,EAAA,GAAK,EAAA,CAAG,gBAAA,CAAiB,CAAC,CAAA,GAAI,EAAA;AACpC,EAAA,MAAM,EAAA,GAAK,EAAA,CAAG,gBAAA,CAAiB,CAAC,CAAA,GAAI,EAAA;AACpC,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,EAAE,CAAA;AACrB,EAAA,IAAI,EAAE,CAAA,GAAI,CAAA,IAAK,OAAO,QAAA,CAAS,CAAA,GAAI,EAAE,CAAA,CAAA,EAAI;AACzC,EAAA,MAAM,CAAC,EAAA,MAAQ,EAAE,IAAI,KAAA,CAAM,IAAA;AAC3B,EAAA,GAAA,CAAI,IAAA,EAAK;AACT,EAAA,GAAA,CAAI,SAAA,EAAU;AACd,EAAA,GAAA,CAAI,IAAA,CAAK,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,GAAA,EAAK,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,GAAG,CAAA;AAC1D,EAAA,GAAA,CAAI,IAAA,EAAK;AAGT,EAAA,GAAA,CAAI,SAAA,CAAU,EAAA,GAAK,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,KAAK,EAAE,CAAA;AAC/D,EAAA,SAAA,CAAU,GAAA,EAAK,KAAA,EAAO,EAAE,KAAA,EAAO,GAAG,CAAA;AAClC,EAAA,GAAA,CAAI,OAAA,EAAQ;AACd","file":"chartjs-surface.js","sourcesContent":["/**\n * Chart.js 4 court / field / rink background: `surface(league, o)` paints a team-painted sporty scene under the\n * datasets. Split from `sdvplot/chartjs` because it draws through `@sportsdataverse/sporty/canvas`, which the logo and\n * colour plugins do not need. sporty is an optional peer, but this entry imports it when it loads, so install it to use\n * `sdvplot/chartjs/surface`. `chart.js` is a type-only import (optional peer, 4.4 or later).\n */\nimport type { Scene } from \"@sportsdataverse/sporty\";\nimport { drawScene } from \"@sportsdataverse/sporty/canvas\";\nimport type { Chart, Plugin } from \"chart.js\";\nimport { InputError, warn } from \"./errors.js\";\nimport { type SurfaceSceneOptions, surfaceScene } from \"./surfaces.js\";\nimport type { League } from \"./types.js\";\n\nexport interface ChartSurfaceOptions extends SurfaceSceneOptions {\n /** The linear x scale's id (default `\"x\"`). */\n xAxisID?: string;\n /** The linear y scale's id (default `\"y\"`). */\n yAxisID?: string;\n}\nexport interface LinearScale {\n type: \"linear\";\n min: number;\n max: number;\n}\nexport interface ChartSurface {\n /** Paints the surface before the datasets (`beforeDatasetsDraw`), clipped to the chart area. */\n plugin: Plugin;\n /** Linear scales spanning the surface, for `options.scales` (keep both axes linear). */\n scales: { x: LinearScale; y: LinearScale };\n scene: Scene;\n}\n/**\n * A team-painted sporty surface as a Chart.js background: a shot chart is a scatter (a hexbin, a bubble chart) over a\n * court. Throws `InputError` for a league without a surface, or for a scene whose bbox is empty (an `xlim` or `ylim` of\n * zero width) here, when it is built, not inside a Chart.js draw. A non-linear axis is left unpainted, with one warning.\n */\nexport function surface(league: League | (string & {}), o: ChartSurfaceOptions = {}): ChartSurface {\n const { xAxisID = \"x\", yAxisID = \"y\", ...rest } = o;\n const scene = surfaceScene(league, rest);\n const [x0, y0, x1, y1] = scene.bbox;\n // drawScene would throw sporty's InputError on the first draw, inside Chart.js's render loop\n if (!(x1 > x0 && y1 > y0 && Number.isFinite(x1 - x0 + y1 - y0)))\n throw new InputError(\n `surface(\"${league}\"): the scene's bbox [${scene.bbox.join(\", \")}] is empty, so there is nothing to draw (check xlim / ylim)`,\n );\n return {\n plugin: {\n id: \"sdvplotSurface\",\n // Chart.js has no plugin priority: inline plugins run in array order, so a watermark listed first is painted over\n start: (chart) => {\n const ps = chart.config.plugins ?? [];\n const own = ps.findIndex((p) => p.id === \"sdvplotSurface\");\n const wm = ps.findIndex((p) => p.id === \"sdvplotLogoWatermarks\");\n if (wm !== -1 && (own === -1 || wm < own))\n warn(\n \"chartjs:surface:order\",\n \"logoWatermarks is listed before the surface plugin, so the court is painted over it; list court.plugin first\",\n );\n },\n beforeDatasetsDraw: (chart) => paintScene(chart, scene, xAxisID, yAxisID),\n },\n scales: { x: { type: \"linear\", min: x0, max: x1 }, y: { type: \"linear\", min: y0, max: y1 } },\n scene,\n };\n}\nfunction paintScene(chart: Chart, scene: Scene, xId: string, yId: string): void {\n const { ctx, chartArea: a } = chart;\n const xs = chart.scales[xId];\n const ys = chart.scales[yId];\n if (!a || xs === undefined || ys === undefined) return; // a draw before the first layout\n if (xs.type !== \"linear\" || ys.type !== \"linear\") {\n warn(\n `chartjs:surface:${xId}:${yId}`,\n `surface needs linear scales (pass court.scales); ${xId} is ${xs.type} and ${yId} is ${ys.type}, so it is not drawn`,\n );\n return;\n }\n const ox = xs.getPixelForValue(0);\n const oy = ys.getPixelForValue(0);\n const kx = xs.getPixelForValue(1) - ox; // px per scene unit; negative on a reversed axis\n const ky = ys.getPixelForValue(1) - oy; // negative: y points up\n const s = Math.abs(kx);\n if (!(s > 0 && Number.isFinite(s + ky))) return; // a zero-size chart area\n const [x0, , , y1] = scene.bbox;\n ctx.save();\n ctx.beginPath();\n ctx.rect(a.left, a.top, a.right - a.left, a.bottom - a.top);\n ctx.clip();\n // drawScene paints (x, y) at (s(x - x0), s(y1 - y)) and composes with the current transform (the chart's own\n // device-pixel-ratio transform stays under both): this map turns that into the chart's scales, axis by axis.\n ctx.transform(kx / s, 0, 0, -ky / s, ox + kx * x0, oy + ky * y1);\n drawScene(ctx, scene, { scale: s }); // strokes are 1/s scene units: one px wide\n ctx.restore();\n}\n"]}
package/dist/chartjs.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PointStyle, Plugin } from 'chart.js';
2
2
  import { E as EspnHeadshotLeague } from './headshots-B2J_LOO8.js';
3
3
  import { V as Value } from './resolve-CQW-jzvr.js';
4
- import { L as League, S as SeasonInput, V as Variant, I as IdSystem, H as HeadshotIdSystem, W as Which } from './types-C7n6gJF3.js';
4
+ import { L as League, S as SeasonInput, V as Variant, I as IdSystem, W as Which, H as HeadshotIdSystem } from './types-C7n6gJF3.js';
5
5
 
6
6
  /**
7
7
  * Chart.js 4 helpers: team logo / wordmark / headshot point styles, axis-tick logos, faint logo watermarks, team
@@ -80,6 +80,36 @@ interface TeamColorOptions {
80
80
  type ColorsFor<T> = T extends readonly Value[] ? string[] : string;
81
81
  /** Team colour(s) for `backgroundColor` / `borderColor`: one team gives one string, an array gives one per team. */
82
82
  declare function teamColor<T extends Value | readonly Value[]>(teams: T, league: League, o?: TeamColorOptions): ColorsFor<T>;
83
+ /** `teamColorPalette` options. */
84
+ interface ChartjsColorOptions {
85
+ which?: Which;
86
+ season?: SeasonInput;
87
+ idSystem?: IdSystem;
88
+ /** The colour of an unresolved team. Default "#808080". A hex colour when `background` is given. */
89
+ fallback?: string;
90
+ /**
91
+ * The chart's background, as an opaque hex colour (`#181a1b` or `#000`; a CSS colour name or `rgb()` throws).
92
+ * Given, a team colour under 3:1 contrast against it is swapped for the team's other
93
+ * colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A
94
+ * colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or
95
+ * the nearest colour to its own that is distinct and still reads; failing that it is kept, with one warning.
96
+ */
97
+ background?: string;
98
+ }
99
+ /**
100
+ * One colour per team, in order, for `backgroundColor` / `borderColor`. With `background`, every colour keeps 3:1
101
+ * contrast against it (dark mode) and stays distinct from the others, as every sdvplot adapter's `teamColorPalette`.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * import { loadLeague } from "@sportsdataverse/sdvplot";
106
+ * import { teamColorPalette } from "@sportsdataverse/sdvplot/chartjs";
107
+ *
108
+ * await loadLeague("nfl");
109
+ * teamColorPalette("nfl", ["KC", "LAC", "DEN", "LV"], { background: "#181a1b" });
110
+ * ```
111
+ */
112
+ declare function teamColorPalette(league: League, teams: readonly unknown[], o?: ChartjsColorOptions): string[];
83
113
  /** `teamColor` at 0.2 opacity by default: the fill under a radar or area dataset. */
84
114
  declare function teamFill<T extends Value | readonly Value[]>(teams: T, league: League, o?: TeamColorOptions): ColorsFor<T>;
85
115
  interface AxisLogoOptions {
@@ -129,4 +159,4 @@ interface WatermarkOptions {
129
159
  */
130
160
  declare function logoWatermarks(teams: readonly Value[], o: WatermarkOptions): Plugin;
131
161
 
132
- export { type AxisLogoOptions, type ColorsFor, type HeadshotPointOptions, type ImageLike, type PointOptions, type PointStyles, type TeamColorOptions, type WatermarkOptions, axisLogos, headshotPoints, logoPoints, logoWatermarks, pointImages, teamColor, teamFill, wordmarkPoints };
162
+ export { type AxisLogoOptions, type ChartjsColorOptions, type ColorsFor, type HeadshotPointOptions, type ImageLike, type PointOptions, type PointStyles, type TeamColorOptions, type WatermarkOptions, axisLogos, headshotPoints, logoPoints, logoWatermarks, pointImages, teamColor, teamColorPalette, teamFill, wordmarkPoints };
package/dist/chartjs.js CHANGED
@@ -1,7 +1,7 @@
1
- import { checkAlpha, placeSync } from './chunk-RMT2GMFH.js';
2
- import './chunk-KKH6ABMA.js';
1
+ import { colorPalette } from './chunk-UL5M6KDE.js';
2
+ import { checkAlpha, placeSync } from './chunk-7ULOCCFL.js';
3
+ import { teamColorsSync } from './chunk-ZAEQXFJM.js';
3
4
  import { hex6, onColor, contrast } from './chunk-J6R2LEJ7.js';
4
- import { teamColorsSync } from './chunk-TAXO3VXH.js';
5
5
  import { InputError, warn, UnsupportedTargetError } from './chunk-E7G7VSLV.js';
6
6
 
7
7
  // src/chartjs.ts
@@ -241,6 +241,9 @@ function teamColor(teams, league, o = {}) {
241
241
  const got = teamColorsSync(league, teams, co);
242
242
  return Array.isArray(got) ? got.map(paint2) : paint2(got);
243
243
  }
244
+ function teamColorPalette(league, teams, o = {}) {
245
+ return colorPalette(league, teams, o);
246
+ }
244
247
  function teamFill(teams, league, o = {}) {
245
248
  return teamColor(teams, league, { alpha: 0.2, ...o });
246
249
  }
@@ -334,6 +337,6 @@ function logoWatermarks(teams, o) {
334
337
  };
335
338
  }
336
339
 
337
- export { axisLogos, headshotPoints, logoPoints, logoWatermarks, pointImages, teamColor, teamFill, wordmarkPoints };
340
+ export { axisLogos, headshotPoints, logoPoints, logoWatermarks, pointImages, teamColor, teamColorPalette, teamFill, wordmarkPoints };
338
341
  //# sourceMappingURL=chartjs.js.map
339
342
  //# sourceMappingURL=chartjs.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chartjs.ts"],"names":["redraws","paint"],"mappings":"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","file":"chartjs.js","sourcesContent":["/**\n * Chart.js 4 helpers: team logo / wordmark / headshot point styles, axis-tick logos, faint logo watermarks, team\n * colours and a sporty surface background. `chart.js` is a type-only import (optional peer, 4.4 or later): everything\n * here is a dataset option or a plugin object, so Svelte, Astro, React or plain scripts pass it to `new Chart(...)`\n * unchanged.\n * The sporty court background lives in `sdvplot/chartjs/surface`, so this entry never needs `@sportsdataverse/sporty`.\n * Call after `loadLeague(league)` / `preloadAll()`; point styles and plugins need a DOM (build them client-side) unless\n * given `loadImage`, which in Node is `@napi-rs/canvas`'s.\n */\nimport type { Chart, Plugin, PointStyle, Scale, Tick } from \"chart.js\";\nimport { teamColorsSync } from \"./colors.js\";\nimport { contrast, hex6, onColor } from \"./contrast.js\";\nimport { InputError, UnsupportedTargetError, warn } from \"./errors.js\";\nimport type { EspnHeadshotLeague } from \"./headshots.js\";\nimport { type Kind, type PlaceOptions, checkAlpha, placeSync } from \"./placement.js\";\nimport type { Value } from \"./resolve.js\";\nimport type { HeadshotIdSystem, IdSystem, League, SeasonInput, Variant, Which } from \"./types.js\";\n\nexport interface PointOptions {\n league: League;\n /** Half the image height in px; also the dataset's `pointRadius` (hit area). Default 12. */\n radius?: number;\n season?: SeasonInput | readonly SeasonInput[];\n variant?: Variant;\n idSystem?: IdSystem;\n /** What an unresolved value draws: `\"text\"` (its own label, the default) or any Chart.js point style. */\n fallback?: PointStyle | \"text\";\n /** The chart's background colour, so the text fallback reads on it (default white, or black with `variant: \"dark\"`). */\n background?: string;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\nexport interface HeadshotPointOptions {\n league: EspnHeadshotLeague;\n radius?: number;\n idSystem?: HeadshotIdSystem;\n fallback?: PointStyle | \"text\";\n /** The chart's background colour, so the text fallback reads on it (default white). */\n background?: string;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\n/** Spread into a scatter / bubble / line dataset: one style per data point, in data order. */\nexport interface PointStyles {\n pointStyle: PointStyle[];\n pointRadius: number;\n}\n\n/**\n * An image a `loadImage` option resolves: anything the chart's 2D context can `drawImage`, such as `@napi-rs/canvas`'s\n * `Image` in Node or an `HTMLImageElement` in the browser. `loadImage` is called once per URL and drawn size, and the\n * image's `width` and `height` are then set to that size (Chart.js draws an image point style at its own size), so\n * resolve a new image on every call, as `@napi-rs/canvas`'s `loadImage` does.\n */\nexport interface ImageLike {\n readonly width: number;\n readonly height: number;\n}\n\nfunction needDom(what: string): Document {\n if (typeof document === \"undefined\")\n throw new UnsupportedTargetError(\n `${what} needs a DOM: build it in the browser (onMount, $effect, an Astro client:only island), not during SSR`,\n );\n return document;\n}\nfunction checkSize(size: number, what: string): number {\n if (!(Number.isFinite(size) && size > 0))\n throw new InputError(`${what} is an image height in px > 0, got ${size}`);\n return size;\n}\n// ponytail: unbounded cache keyed by size + url; a page holds a few hundred marks at most.\nconst images = new Map<string, HTMLImageElement>();\nfunction image(url: string, h: number, aspect: number): HTMLImageElement {\n const w = Math.round(h * aspect);\n const key = `${w}x${h} ${url}`;\n let img = images.get(key);\n if (img === undefined) {\n img = needDom(\"an image point style\").createElement(\"img\");\n img.width = w; // Chart.js draws an image point style at the element's own width x height\n img.height = h;\n img.crossOrigin = \"anonymous\"; // keeps chart.toBase64Image() usable\n img.src = url;\n images.set(key, img);\n }\n return img;\n}\ntype LoadImage = (url: string) => Promise<ImageLike>;\n/** A `loadImage` image at its drawn size: `img` is undefined while it loads and null if it failed. */\nclass Loading {\n img: ImageLike | null | undefined = undefined;\n /** Point-style slots to fill, then charts to redraw, all in the first reaction to the loader's promise. */\n readonly slots: [PointStyle[], number][] = [];\n readonly on = new Set<() => void>();\n constructor(\n readonly width: number,\n readonly height: number,\n ) {}\n}\ntype Mark = HTMLImageElement | Loading;\n/** The size each loaded image was set to, to catch a loader that hands the same image out for two sizes. */\nconst sizes = new WeakMap<object, { width: number; height: number }>();\nconst DRAWN = [\"[object HTMLImageElement]\", \"[object HTMLCanvasElement]\"];\n/** Chart.js draws a point-style image at its own width x height, and only one that stringifies as a DOM image or canvas. */\nfunction sized(img: ImageLike, w: number, h: number): ImageLike | null {\n const was = sizes.get(img);\n if (was !== undefined && (was.width !== w || was.height !== h)) {\n warn(\n \"chartjs:loadImage:shared\",\n \"loadImage returned an image already sized for another drawn size, so that use is not drawn: loadImage must return a fresh image per call (wrap a cache so each call returns a new image)\",\n );\n return null;\n }\n const own = (value: unknown): PropertyDescriptor => ({ value, writable: true, configurable: true });\n const tag: PropertyDescriptorMap = DRAWN.includes(String(img)) ? {} : { toString: own(() => DRAWN[0]) };\n try {\n Object.defineProperties(img, { width: own(w), height: own(h), ...tag });\n } catch (e) {\n warn(\n \"chartjs:loadImage:unsizable\",\n `loadImage returned an image that cannot be sized (${String(e)}), so it is not drawn`,\n );\n return null;\n }\n sizes.set(img, { width: w, height: h });\n return img;\n}\n// ponytail: unbounded like `images`; per loader, so two loaders never share an image.\nconst loads = new WeakMap<LoadImage, Map<string, Loading>>();\nfunction loading(load: LoadImage, url: string, h: number, aspect: number): Loading {\n const w = Math.round(h * aspect);\n const key = `${w}x${h} ${url}`;\n const byKey = loads.get(load) ?? new Map<string, Loading>();\n loads.set(load, byKey);\n let m = byKey.get(key);\n if (m === undefined) {\n const it = new Loading(w, h);\n // everything runs here, in the promise's first reaction, so a caller awaiting the same promises sees it all done\n const land = (img: ImageLike | null): void => {\n it.img = img;\n if (img !== null) for (const [styles, i] of it.slots) styles[i] = img as unknown as PointStyle;\n it.slots.length = 0;\n const redraws = [...it.on];\n it.on.clear();\n for (const f of redraws) f();\n };\n void load(url).then(\n (img) => land(sized(img, w, h)),\n (e: unknown) => {\n warn(`chartjs:loadImage:${url}`, `loadImage failed for ${url} (${String(e)}), so it is not drawn`);\n land(null);\n },\n );\n m = it;\n byKey.set(key, m);\n }\n return m;\n}\n/** Game on Paper's light-theme or dark-theme canvas text colour, whichever reads better on `background`. */\nfunction textInk(background: string): string {\n return contrast(\"#555555\", background) >= contrast(\"#e8e6e3\", background) ? \"#555555\" : \"#e8e6e3\";\n}\nfunction textStyle(label: string, h: number, ink: string): HTMLCanvasElement | \"circle\" {\n // ponytail: Node (only reachable with loadImage) has no canvas to letter the label on, so it draws a circle\n if (typeof document === \"undefined\") return \"circle\";\n const c = document.createElement(\"canvas\");\n const g = c.getContext(\"2d\");\n if (g === null) return \"circle\";\n const font = `bold ${Math.round(h * 0.45)}px sans-serif`;\n g.font = font;\n c.width = Math.max(h, Math.ceil(g.measureText(label).width) + 4);\n c.height = h;\n g.font = font; // resizing a canvas resets its context\n g.textAlign = \"center\";\n g.textBaseline = \"middle\";\n g.fillStyle = ink;\n g.fillText(label, c.width / 2, h / 2);\n return c;\n}\n/** One image per resolvable value at `h` px tall, indexed like `values` (gaps where nothing can be drawn); warns once per call (J28). */\nfunction imagesFor(\n values: readonly Value[],\n h: number,\n place: PlaceOptions,\n load: LoadImage | undefined,\n): (Mark | undefined)[] {\n const out = new Array<Mark | undefined>(values.length);\n // The row index as x keeps data order; placeSync drops what it cannot draw and warns once per call (J28).\n const idx = values.map((_, i) => i);\n for (const p of placeSync(idx, idx, values, place))\n out[p.index] =\n load === undefined ? image(p.url, h, p.aspect ?? 1) : loading(load, p.url, h, p.aspect ?? 1);\n return out;\n}\n/** The point-style arrays still waiting on a `loadImage` image, for `pointImages` to refresh. */\nconst pending = new WeakMap<object, Loading[]>();\nfunction points(\n values: readonly Value[],\n kind: Kind,\n radius: number | undefined,\n fallback: PointStyle | \"text\" | undefined,\n background: string | undefined,\n place: PlaceOptions,\n load: LoadImage | undefined,\n): PointStyles {\n if (load === undefined) needDom(\"point styles\"); // before resolving, so SSR fails without a resolve warning\n const r = radius ?? 12;\n if (!(Number.isFinite(r) && r > 0))\n throw new InputError(`radius is a point radius in px > 0, got ${String(radius)}`);\n const ink = textInk(background ?? (place.variant === \"dark\" ? \"#000000\" : \"#ffffff\")); // a bad colour throws here\n const styles = new Array<PointStyle>(values.length);\n const waiting: Loading[] = [];\n imagesFor(values, 2 * r, { ...place, kind }, load).forEach((m, i) => {\n if (m === undefined) return;\n if (!(m instanceof Loading)) {\n styles[i] = m;\n return;\n }\n // until it lands the slot draws nothing, as a loading image does; Chart.js re-reads the array on update\n styles[i] = (m.img ?? false) as PointStyle;\n if (m.img !== undefined) return;\n m.slots.push([styles, i]);\n waiting.push(m);\n });\n if (waiting.length > 0) pending.set(styles, waiting);\n for (let i = 0; i < values.length; i++)\n styles[i] ??=\n fallback === undefined || fallback === \"text\"\n ? textStyle(String(values[i] ?? \"\"), 2 * r, ink)\n : fallback;\n return { pointStyle: styles, pointRadius: r };\n}\nfunction teamPoints(teams: readonly Value[], kind: \"logo\" | \"wordmark\", o: PointOptions): PointStyles {\n const { league, radius, fallback, background, loadImage, ...rest } = o;\n return points(teams, kind, radius, fallback, background, { league, ...rest }, loadImage);\n}\n/** Team logos as point styles: `{ data, ...logoPoints(teams, { league: \"nfl\", radius: 12 }) }`. Add `pointImages` to `plugins`. */\nexport function logoPoints(teams: readonly Value[], o: PointOptions): PointStyles {\n return teamPoints(teams, \"logo\", o);\n}\n/** As `logoPoints`, with wordmarks. */\nexport function wordmarkPoints(teams: readonly Value[], o: PointOptions): PointStyles {\n return teamPoints(teams, \"wordmark\", o);\n}\n/** ESPN player headshots as point styles; `idSystem: \"gsis\"` needs `loadGsis()` first. */\nexport function headshotPoints(players: readonly Value[], o: HeadshotPointOptions): PointStyles {\n return points(\n players,\n \"headshot\",\n o.radius,\n o.fallback,\n o.background,\n { league: o.league, idSystem: o.idSystem ?? \"espn\" },\n o.loadImage,\n );\n}\n\ntype Redraws = { redraw: () => void; refresh: () => void; stop: AbortController };\nconst redraws = new WeakMap<Chart, Redraws>();\nconst isImage = (v: unknown): v is HTMLImageElement =>\n Object.prototype.toString.call(v) === \"[object HTMLImageElement]\"; // Chart.js's own test (drawPointLegend)\nfunction redrawsOf(chart: Chart): Redraws {\n let r = redraws.get(chart);\n if (r === undefined) {\n r = {\n redraw: () => {\n if (chart.ctx) chart.draw(); // null once destroyed\n },\n refresh: () => {\n if (chart.ctx) chart.update(\"none\"); // re-reads the point styles, which a draw does not\n },\n stop: new AbortController(),\n };\n redraws.set(chart, r);\n }\n return r;\n}\n/** Redraw `chart` once `img` loads; one listener per (image, chart) because addEventListener ignores a repeat. */\nfunction redrawOnLoad(chart: Chart, img: HTMLImageElement): void {\n if (img.complete) return;\n const r = redrawsOf(chart);\n img.addEventListener(\"load\", r.redraw, { once: true, signal: r.stop.signal });\n}\n/** As `redrawOnLoad`, for a `loadImage` image still loading; the same per-chart abort drops it on destroy. */\nfunction redrawOnLanding(chart: Chart, m: Loading, how: \"redraw\" | \"refresh\"): void {\n const r = redrawsOf(chart);\n const f = r[how];\n if (m.on.has(f)) return;\n m.on.add(f);\n r.stop.signal.addEventListener(\"abort\", () => m.on.delete(f), { once: true });\n}\n/** The image to paint now, or undefined with a redraw arranged for when it loads (a broken image is skipped). */\nfunction paint(chart: Chart, m: Mark | undefined): HTMLImageElement | undefined {\n if (m === undefined) return undefined;\n if (m instanceof Loading) {\n if (m.img === undefined) redrawOnLanding(chart, m, \"redraw\");\n return (m.img ?? undefined) as HTMLImageElement | undefined; // drawImage takes it as one; only its size is read\n }\n if (!m.complete || m.naturalWidth === 0) {\n redrawOnLoad(chart, m);\n return undefined;\n }\n return m;\n}\n/** `afterDestroy`: drop the chart's pending load listeners, so a late (or never-loading) image cannot hold or redraw it. */\nfunction forget(chart: Chart): void {\n redraws.get(chart)?.stop.abort();\n redraws.delete(chart);\n}\n/** Redraws the chart as each image point style finishes loading (Chart.js does not watch them). */\nexport const pointImages: Plugin = {\n id: \"sdvplotPointImages\",\n afterDestroy: forget,\n afterDraw(chart) {\n for (const ds of chart.data.datasets) {\n const s = (ds as { pointStyle?: unknown }).pointStyle;\n for (const v of Array.isArray(s) ? s : [s]) if (isImage(v)) redrawOnLoad(chart, v);\n for (const m of (Array.isArray(s) && pending.get(s)) || [])\n if (m.img === undefined) redrawOnLanding(chart, m, \"refresh\");\n }\n },\n};\n\nexport interface TeamColorOptions {\n which?: Which;\n season?: SeasonInput;\n idSystem?: IdSystem;\n /** Opacity in [0, 1]; below 1 the colour is written `rgba(r, g, b, a)`. */\n alpha?: number;\n /** The colour of an unresolved team (default `#808080`). */\n fallback?: string;\n /** Return black or white, whichever reads on the team colour (labels, point borders). */\n onColor?: boolean;\n}\nexport type ColorsFor<T> = T extends readonly Value[] ? string[] : string;\n/** Team colour(s) for `backgroundColor` / `borderColor`: one team gives one string, an array gives one per team. */\nexport function teamColor<T extends Value | readonly Value[]>(\n teams: T,\n league: League,\n o: TeamColorOptions = {},\n): ColorsFor<T> {\n const { alpha = 1, fallback = \"#808080\", onColor: ink = false, ...co } = o;\n const a = checkAlpha(alpha);\n const paint = (c: unknown): string => {\n const hex = hex6(typeof c === \"string\" ? c : fallback, { dropAlpha: true });\n if (ink) return onColor(hex);\n if (a === 1) return hex;\n const n = Number.parseInt(hex.slice(1), 16);\n return `rgba(${n >> 16}, ${(n >> 8) & 255}, ${n & 255}, ${a})`;\n };\n const got: unknown = teamColorsSync(league, teams, co);\n return (Array.isArray(got) ? got.map(paint) : paint(got)) as ColorsFor<T>;\n}\n/** `teamColor` at 0.2 opacity by default: the fill under a radar or area dataset. */\nexport function teamFill<T extends Value | readonly Value[]>(\n teams: T,\n league: League,\n o: TeamColorOptions = {},\n): ColorsFor<T> {\n return teamColor(teams, league, { alpha: 0.2, ...o });\n}\n\nexport interface AxisLogoOptions {\n league: League;\n /** Image height in px (default 24); the width follows the mark's aspect. */\n size?: number;\n season?: SeasonInput;\n variant?: Variant;\n markType?: \"logo\" | \"wordmark\";\n idSystem?: IdSystem;\n /** The category scale's id (default: the axis letter). */\n scaleId?: string;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\ntype TickCallback = (this: Scale, value: number | string, index: number, ticks: Tick[]) => unknown;\n/**\n * Swap a category axis's tick labels for team logos: resolved labels are painted as images (after the datasets, under\n * the tooltip) and their text is blanked; unresolved labels keep their text, with one warning per distinct label set\n * (J28). Any other scale type is left as it is, with one warning.\n */\nexport function axisLogos(axis: \"x\" | \"y\", o: AxisLogoOptions): Plugin {\n if (axis !== \"x\" && axis !== \"y\")\n throw new InputError(`axis must be \"x\" or \"y\", got ${JSON.stringify(axis)}`);\n const { league, size = 24, markType = \"logo\", scaleId = axis, loadImage, ...rest } = o;\n checkSize(size, \"size\");\n const byChart = new WeakMap<Chart, { m: Map<string, Mark>; band: number }>();\n const bases = new WeakMap<TickCallback, number>(); // each wired callback -> the padding it was wired over\n return {\n id: `sdvplotAxisLogos${axis.toUpperCase()}`,\n afterDestroy: forget,\n beforeUpdate(chart) {\n // Chart.js merges options.scales into a fresh copy on every update (and `chart.options = next` replaces it), so\n // the tick wiring is (re)applied to that copy here, once per copy: never in beforeInit, never the caller's object.\n const conf = chart.config as unknown as {\n options: {\n scales?: Record<string, { type?: string; ticks?: { callback?: TickCallback; padding?: number } }>;\n };\n };\n const scale = conf.options.scales?.[scaleId];\n if (scale?.type !== \"category\") {\n byChart.delete(chart);\n warn(\n `chartjs:axisLogos:${scaleId}`,\n `axisLogos needs a category scale; scale ${JSON.stringify(scaleId)} is ${scale?.type ?? \"missing\"}, so its ticks are left as they are`,\n );\n return;\n }\n const labels = (chart.data.labels ?? []).map(String);\n const m = new Map<string, Mark>();\n imagesFor(labels, size, { league, kind: markType, ...rest }, loadImage).forEach((img, i) => {\n if (img !== undefined) m.set(labels[i] ?? \"\", img);\n });\n // the band the images fill: their height on x, the widest mark on y (a wordmark is several times its height)\n const band = axis === \"y\" ? Math.max(size, ...[...m.values()].map((img) => img.width)) : size;\n byChart.set(chart, { m, band });\n scale.ticks ??= {};\n const ticks = scale.ticks;\n const user = ticks.callback;\n let base = user === undefined ? undefined : bases.get(user);\n if (base === undefined) {\n base = ticks.padding ?? 3; // 3 = Chart.js's default padding\n const callback: TickCallback = function (this: Scale, value, index, all) {\n const label = this.getLabelForValue(Number(value));\n if (byChart.get(chart)?.m.has(label)) return \"\";\n return user === undefined ? label : user.call(this, value, index, all);\n };\n bases.set(callback, base);\n ticks.callback = callback;\n }\n ticks.padding = base + band;\n },\n afterDatasetsDraw(chart) {\n const scale = chart.scales[scaleId];\n const got = byChart.get(chart);\n if (scale === undefined || got === undefined) return;\n const { m, band } = got;\n // resolved options: Chart.js has filled every default by draw time\n const { grid, ticks } = scale.options as unknown as {\n grid: { display: boolean; drawTicks: boolean; tickLength: number };\n ticks: { padding: number };\n };\n const gap = (grid.display && grid.drawTicks ? grid.tickLength : 0) + ticks.padding - band;\n scale.ticks.forEach((t, i) => {\n const img = paint(chart, m.get(scale.getLabelForValue(t.value)));\n if (img === undefined) return;\n const at = scale.getPixelForTick(i);\n const { width: w, height: h } = img;\n const x =\n axis === \"y\" ? (scale.position === \"right\" ? scale.left + gap : scale.right - gap - w) : at - w / 2;\n const y =\n axis === \"x\" ? (scale.position === \"top\" ? scale.bottom - gap - h : scale.top + gap) : at - h / 2;\n chart.ctx.drawImage(img, x, y, w, h);\n });\n },\n };\n}\n\nexport interface WatermarkOptions {\n league: League;\n /** Image height in px (default 75, Game on Paper's win-probability chart); the width follows the mark's aspect. */\n size?: number;\n /** Opacity of the watermarks (default 0.4). */\n alpha?: number;\n /** Gap in px from the chart area's left edge and from its top / bottom (default 8). */\n inset?: number;\n season?: SeasonInput | readonly SeasonInput[];\n variant?: Variant;\n idSystem?: IdSystem;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\n/**\n * Faint team logos behind the datasets (Game on Paper's win-probability chart): the first team sits top-left of the\n * chart area, the last bottom-left, any between spaced evenly down the left edge, so pass `[home, away]` under a home\n * win-probability line. Unknown teams are skipped with one warning per call (J28); `variant: \"dark\"` falls back to a\n * light mark by polarity, so no `onerror` retry is needed.\n */\nexport function logoWatermarks(teams: readonly Value[], o: WatermarkOptions): Plugin {\n if (o.loadImage === undefined) needDom(\"logo watermarks\"); // before resolving, so SSR fails without a resolve warning\n const { league, size = 75, alpha = 0.4, inset = 8, loadImage, ...rest } = o;\n checkSize(size, \"size\");\n const a = checkAlpha(alpha);\n const imgs = imagesFor(teams, size, { league, kind: \"logo\", ...rest }, loadImage);\n const n = imgs.length;\n return {\n id: \"sdvplotLogoWatermarks\",\n afterDestroy: forget,\n beforeDatasetsDraw(chart) {\n const { ctx, chartArea: ar } = chart;\n if (!ar) return; // a draw before the first layout\n ctx.save();\n ctx.globalAlpha = a;\n imgs.forEach((m, i) => {\n const img = paint(chart, m);\n if (img === undefined) return;\n const t = n > 1 ? i / (n - 1) : 0;\n const y = ar.top + inset + t * (ar.bottom - ar.top - 2 * inset - img.height);\n ctx.drawImage(img, ar.left + inset, y, img.width, img.height);\n });\n ctx.restore();\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/chartjs.ts"],"names":["redraws","paint"],"mappings":"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","file":"chartjs.js","sourcesContent":["/**\n * Chart.js 4 helpers: team logo / wordmark / headshot point styles, axis-tick logos, faint logo watermarks, team\n * colours and a sporty surface background. `chart.js` is a type-only import (optional peer, 4.4 or later): everything\n * here is a dataset option or a plugin object, so Svelte, Astro, React or plain scripts pass it to `new Chart(...)`\n * unchanged.\n * The sporty court background lives in `sdvplot/chartjs/surface`, so this entry never needs `@sportsdataverse/sporty`.\n * Call after `loadLeague(league)` / `preloadAll()`; point styles and plugins need a DOM (build them client-side) unless\n * given `loadImage`, which in Node is `@napi-rs/canvas`'s.\n */\nimport type { Chart, Plugin, PointStyle, Scale, Tick } from \"chart.js\";\nimport { colorPalette } from \"./_web.js\";\nimport { teamColorsSync } from \"./colors.js\";\nimport { contrast, hex6, onColor } from \"./contrast.js\";\nimport { InputError, UnsupportedTargetError, warn } from \"./errors.js\";\nimport type { EspnHeadshotLeague } from \"./headshots.js\";\nimport { type Kind, type PlaceOptions, checkAlpha, placeSync } from \"./placement.js\";\nimport type { Value } from \"./resolve.js\";\nimport type { HeadshotIdSystem, IdSystem, League, SeasonInput, Variant, Which } from \"./types.js\";\n\nexport interface PointOptions {\n league: League;\n /** Half the image height in px; also the dataset's `pointRadius` (hit area). Default 12. */\n radius?: number;\n season?: SeasonInput | readonly SeasonInput[];\n variant?: Variant;\n idSystem?: IdSystem;\n /** What an unresolved value draws: `\"text\"` (its own label, the default) or any Chart.js point style. */\n fallback?: PointStyle | \"text\";\n /** The chart's background colour, so the text fallback reads on it (default white, or black with `variant: \"dark\"`). */\n background?: string;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\nexport interface HeadshotPointOptions {\n league: EspnHeadshotLeague;\n radius?: number;\n idSystem?: HeadshotIdSystem;\n fallback?: PointStyle | \"text\";\n /** The chart's background colour, so the text fallback reads on it (default white). */\n background?: string;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\n/** Spread into a scatter / bubble / line dataset: one style per data point, in data order. */\nexport interface PointStyles {\n pointStyle: PointStyle[];\n pointRadius: number;\n}\n\n/**\n * An image a `loadImage` option resolves: anything the chart's 2D context can `drawImage`, such as `@napi-rs/canvas`'s\n * `Image` in Node or an `HTMLImageElement` in the browser. `loadImage` is called once per URL and drawn size, and the\n * image's `width` and `height` are then set to that size (Chart.js draws an image point style at its own size), so\n * resolve a new image on every call, as `@napi-rs/canvas`'s `loadImage` does.\n */\nexport interface ImageLike {\n readonly width: number;\n readonly height: number;\n}\n\nfunction needDom(what: string): Document {\n if (typeof document === \"undefined\")\n throw new UnsupportedTargetError(\n `${what} needs a DOM: build it in the browser (onMount, $effect, an Astro client:only island), not during SSR`,\n );\n return document;\n}\nfunction checkSize(size: number, what: string): number {\n if (!(Number.isFinite(size) && size > 0))\n throw new InputError(`${what} is an image height in px > 0, got ${size}`);\n return size;\n}\n// ponytail: unbounded cache keyed by size + url; a page holds a few hundred marks at most.\nconst images = new Map<string, HTMLImageElement>();\nfunction image(url: string, h: number, aspect: number): HTMLImageElement {\n const w = Math.round(h * aspect);\n const key = `${w}x${h} ${url}`;\n let img = images.get(key);\n if (img === undefined) {\n img = needDom(\"an image point style\").createElement(\"img\");\n img.width = w; // Chart.js draws an image point style at the element's own width x height\n img.height = h;\n img.crossOrigin = \"anonymous\"; // keeps chart.toBase64Image() usable\n img.src = url;\n images.set(key, img);\n }\n return img;\n}\ntype LoadImage = (url: string) => Promise<ImageLike>;\n/** A `loadImage` image at its drawn size: `img` is undefined while it loads and null if it failed. */\nclass Loading {\n img: ImageLike | null | undefined = undefined;\n /** Point-style slots to fill, then charts to redraw, all in the first reaction to the loader's promise. */\n readonly slots: [PointStyle[], number][] = [];\n readonly on = new Set<() => void>();\n constructor(\n readonly width: number,\n readonly height: number,\n ) {}\n}\ntype Mark = HTMLImageElement | Loading;\n/** The size each loaded image was set to, to catch a loader that hands the same image out for two sizes. */\nconst sizes = new WeakMap<object, { width: number; height: number }>();\nconst DRAWN = [\"[object HTMLImageElement]\", \"[object HTMLCanvasElement]\"];\n/** Chart.js draws a point-style image at its own width x height, and only one that stringifies as a DOM image or canvas. */\nfunction sized(img: ImageLike, w: number, h: number): ImageLike | null {\n const was = sizes.get(img);\n if (was !== undefined && (was.width !== w || was.height !== h)) {\n warn(\n \"chartjs:loadImage:shared\",\n \"loadImage returned an image already sized for another drawn size, so that use is not drawn: loadImage must return a fresh image per call (wrap a cache so each call returns a new image)\",\n );\n return null;\n }\n const own = (value: unknown): PropertyDescriptor => ({ value, writable: true, configurable: true });\n const tag: PropertyDescriptorMap = DRAWN.includes(String(img)) ? {} : { toString: own(() => DRAWN[0]) };\n try {\n Object.defineProperties(img, { width: own(w), height: own(h), ...tag });\n } catch (e) {\n warn(\n \"chartjs:loadImage:unsizable\",\n `loadImage returned an image that cannot be sized (${String(e)}), so it is not drawn`,\n );\n return null;\n }\n sizes.set(img, { width: w, height: h });\n return img;\n}\n// ponytail: unbounded like `images`; per loader, so two loaders never share an image.\nconst loads = new WeakMap<LoadImage, Map<string, Loading>>();\nfunction loading(load: LoadImage, url: string, h: number, aspect: number): Loading {\n const w = Math.round(h * aspect);\n const key = `${w}x${h} ${url}`;\n const byKey = loads.get(load) ?? new Map<string, Loading>();\n loads.set(load, byKey);\n let m = byKey.get(key);\n if (m === undefined) {\n const it = new Loading(w, h);\n // everything runs here, in the promise's first reaction, so a caller awaiting the same promises sees it all done\n const land = (img: ImageLike | null): void => {\n it.img = img;\n if (img !== null) for (const [styles, i] of it.slots) styles[i] = img as unknown as PointStyle;\n it.slots.length = 0;\n const redraws = [...it.on];\n it.on.clear();\n for (const f of redraws) f();\n };\n void load(url).then(\n (img) => land(sized(img, w, h)),\n (e: unknown) => {\n warn(`chartjs:loadImage:${url}`, `loadImage failed for ${url} (${String(e)}), so it is not drawn`);\n land(null);\n },\n );\n m = it;\n byKey.set(key, m);\n }\n return m;\n}\n/** Game on Paper's light-theme or dark-theme canvas text colour, whichever reads better on `background`. */\nfunction textInk(background: string): string {\n return contrast(\"#555555\", background) >= contrast(\"#e8e6e3\", background) ? \"#555555\" : \"#e8e6e3\";\n}\nfunction textStyle(label: string, h: number, ink: string): HTMLCanvasElement | \"circle\" {\n // ponytail: Node (only reachable with loadImage) has no canvas to letter the label on, so it draws a circle\n if (typeof document === \"undefined\") return \"circle\";\n const c = document.createElement(\"canvas\");\n const g = c.getContext(\"2d\");\n if (g === null) return \"circle\";\n const font = `bold ${Math.round(h * 0.45)}px sans-serif`;\n g.font = font;\n c.width = Math.max(h, Math.ceil(g.measureText(label).width) + 4);\n c.height = h;\n g.font = font; // resizing a canvas resets its context\n g.textAlign = \"center\";\n g.textBaseline = \"middle\";\n g.fillStyle = ink;\n g.fillText(label, c.width / 2, h / 2);\n return c;\n}\n/** One image per resolvable value at `h` px tall, indexed like `values` (gaps where nothing can be drawn); warns once per call (J28). */\nfunction imagesFor(\n values: readonly Value[],\n h: number,\n place: PlaceOptions,\n load: LoadImage | undefined,\n): (Mark | undefined)[] {\n const out = new Array<Mark | undefined>(values.length);\n // The row index as x keeps data order; placeSync drops what it cannot draw and warns once per call (J28).\n const idx = values.map((_, i) => i);\n for (const p of placeSync(idx, idx, values, place))\n out[p.index] =\n load === undefined ? image(p.url, h, p.aspect ?? 1) : loading(load, p.url, h, p.aspect ?? 1);\n return out;\n}\n/** The point-style arrays still waiting on a `loadImage` image, for `pointImages` to refresh. */\nconst pending = new WeakMap<object, Loading[]>();\nfunction points(\n values: readonly Value[],\n kind: Kind,\n radius: number | undefined,\n fallback: PointStyle | \"text\" | undefined,\n background: string | undefined,\n place: PlaceOptions,\n load: LoadImage | undefined,\n): PointStyles {\n if (load === undefined) needDom(\"point styles\"); // before resolving, so SSR fails without a resolve warning\n const r = radius ?? 12;\n if (!(Number.isFinite(r) && r > 0))\n throw new InputError(`radius is a point radius in px > 0, got ${String(radius)}`);\n const ink = textInk(background ?? (place.variant === \"dark\" ? \"#000000\" : \"#ffffff\")); // a bad colour throws here\n const styles = new Array<PointStyle>(values.length);\n const waiting: Loading[] = [];\n imagesFor(values, 2 * r, { ...place, kind }, load).forEach((m, i) => {\n if (m === undefined) return;\n if (!(m instanceof Loading)) {\n styles[i] = m;\n return;\n }\n // until it lands the slot draws nothing, as a loading image does; Chart.js re-reads the array on update\n styles[i] = (m.img ?? false) as PointStyle;\n if (m.img !== undefined) return;\n m.slots.push([styles, i]);\n waiting.push(m);\n });\n if (waiting.length > 0) pending.set(styles, waiting);\n for (let i = 0; i < values.length; i++)\n styles[i] ??=\n fallback === undefined || fallback === \"text\"\n ? textStyle(String(values[i] ?? \"\"), 2 * r, ink)\n : fallback;\n return { pointStyle: styles, pointRadius: r };\n}\nfunction teamPoints(teams: readonly Value[], kind: \"logo\" | \"wordmark\", o: PointOptions): PointStyles {\n const { league, radius, fallback, background, loadImage, ...rest } = o;\n return points(teams, kind, radius, fallback, background, { league, ...rest }, loadImage);\n}\n/** Team logos as point styles: `{ data, ...logoPoints(teams, { league: \"nfl\", radius: 12 }) }`. Add `pointImages` to `plugins`. */\nexport function logoPoints(teams: readonly Value[], o: PointOptions): PointStyles {\n return teamPoints(teams, \"logo\", o);\n}\n/** As `logoPoints`, with wordmarks. */\nexport function wordmarkPoints(teams: readonly Value[], o: PointOptions): PointStyles {\n return teamPoints(teams, \"wordmark\", o);\n}\n/** ESPN player headshots as point styles; `idSystem: \"gsis\"` needs `loadGsis()` first. */\nexport function headshotPoints(players: readonly Value[], o: HeadshotPointOptions): PointStyles {\n return points(\n players,\n \"headshot\",\n o.radius,\n o.fallback,\n o.background,\n { league: o.league, idSystem: o.idSystem ?? \"espn\" },\n o.loadImage,\n );\n}\n\ntype Redraws = { redraw: () => void; refresh: () => void; stop: AbortController };\nconst redraws = new WeakMap<Chart, Redraws>();\nconst isImage = (v: unknown): v is HTMLImageElement =>\n Object.prototype.toString.call(v) === \"[object HTMLImageElement]\"; // Chart.js's own test (drawPointLegend)\nfunction redrawsOf(chart: Chart): Redraws {\n let r = redraws.get(chart);\n if (r === undefined) {\n r = {\n redraw: () => {\n if (chart.ctx) chart.draw(); // null once destroyed\n },\n refresh: () => {\n if (chart.ctx) chart.update(\"none\"); // re-reads the point styles, which a draw does not\n },\n stop: new AbortController(),\n };\n redraws.set(chart, r);\n }\n return r;\n}\n/** Redraw `chart` once `img` loads; one listener per (image, chart) because addEventListener ignores a repeat. */\nfunction redrawOnLoad(chart: Chart, img: HTMLImageElement): void {\n if (img.complete) return;\n const r = redrawsOf(chart);\n img.addEventListener(\"load\", r.redraw, { once: true, signal: r.stop.signal });\n}\n/** As `redrawOnLoad`, for a `loadImage` image still loading; the same per-chart abort drops it on destroy. */\nfunction redrawOnLanding(chart: Chart, m: Loading, how: \"redraw\" | \"refresh\"): void {\n const r = redrawsOf(chart);\n const f = r[how];\n if (m.on.has(f)) return;\n m.on.add(f);\n r.stop.signal.addEventListener(\"abort\", () => m.on.delete(f), { once: true });\n}\n/** The image to paint now, or undefined with a redraw arranged for when it loads (a broken image is skipped). */\nfunction paint(chart: Chart, m: Mark | undefined): HTMLImageElement | undefined {\n if (m === undefined) return undefined;\n if (m instanceof Loading) {\n if (m.img === undefined) redrawOnLanding(chart, m, \"redraw\");\n return (m.img ?? undefined) as HTMLImageElement | undefined; // drawImage takes it as one; only its size is read\n }\n if (!m.complete || m.naturalWidth === 0) {\n redrawOnLoad(chart, m);\n return undefined;\n }\n return m;\n}\n/** `afterDestroy`: drop the chart's pending load listeners, so a late (or never-loading) image cannot hold or redraw it. */\nfunction forget(chart: Chart): void {\n redraws.get(chart)?.stop.abort();\n redraws.delete(chart);\n}\n/** Redraws the chart as each image point style finishes loading (Chart.js does not watch them). */\nexport const pointImages: Plugin = {\n id: \"sdvplotPointImages\",\n afterDestroy: forget,\n afterDraw(chart) {\n for (const ds of chart.data.datasets) {\n const s = (ds as { pointStyle?: unknown }).pointStyle;\n for (const v of Array.isArray(s) ? s : [s]) if (isImage(v)) redrawOnLoad(chart, v);\n for (const m of (Array.isArray(s) && pending.get(s)) || [])\n if (m.img === undefined) redrawOnLanding(chart, m, \"refresh\");\n }\n },\n};\n\nexport interface TeamColorOptions {\n which?: Which;\n season?: SeasonInput;\n idSystem?: IdSystem;\n /** Opacity in [0, 1]; below 1 the colour is written `rgba(r, g, b, a)`. */\n alpha?: number;\n /** The colour of an unresolved team (default `#808080`). */\n fallback?: string;\n /** Return black or white, whichever reads on the team colour (labels, point borders). */\n onColor?: boolean;\n}\nexport type ColorsFor<T> = T extends readonly Value[] ? string[] : string;\n/** Team colour(s) for `backgroundColor` / `borderColor`: one team gives one string, an array gives one per team. */\nexport function teamColor<T extends Value | readonly Value[]>(\n teams: T,\n league: League,\n o: TeamColorOptions = {},\n): ColorsFor<T> {\n const { alpha = 1, fallback = \"#808080\", onColor: ink = false, ...co } = o;\n const a = checkAlpha(alpha);\n const paint = (c: unknown): string => {\n const hex = hex6(typeof c === \"string\" ? c : fallback, { dropAlpha: true });\n if (ink) return onColor(hex);\n if (a === 1) return hex;\n const n = Number.parseInt(hex.slice(1), 16);\n return `rgba(${n >> 16}, ${(n >> 8) & 255}, ${n & 255}, ${a})`;\n };\n const got: unknown = teamColorsSync(league, teams, co);\n return (Array.isArray(got) ? got.map(paint) : paint(got)) as ColorsFor<T>;\n}\n/** `teamColorPalette` options. */\nexport interface ChartjsColorOptions {\n which?: Which;\n season?: SeasonInput;\n idSystem?: IdSystem;\n /** The colour of an unresolved team. Default \"#808080\". A hex colour when `background` is given. */\n fallback?: string;\n /**\n * The chart's background, as an opaque hex colour (`#181a1b` or `#000`; a CSS colour name or `rgb()` throws).\n * 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 * One colour per team, in order, for `backgroundColor` / `borderColor`. With `background`, every colour keeps 3:1\n * contrast against it (dark mode) and stays distinct from the others, as every sdvplot adapter's `teamColorPalette`.\n *\n * @example\n * ```ts\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamColorPalette } from \"@sportsdataverse/sdvplot/chartjs\";\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: ChartjsColorOptions = {},\n): string[] {\n return colorPalette(league, teams, o);\n}\n/** `teamColor` at 0.2 opacity by default: the fill under a radar or area dataset. */\nexport function teamFill<T extends Value | readonly Value[]>(\n teams: T,\n league: League,\n o: TeamColorOptions = {},\n): ColorsFor<T> {\n return teamColor(teams, league, { alpha: 0.2, ...o });\n}\n\nexport interface AxisLogoOptions {\n league: League;\n /** Image height in px (default 24); the width follows the mark's aspect. */\n size?: number;\n season?: SeasonInput;\n variant?: Variant;\n markType?: \"logo\" | \"wordmark\";\n idSystem?: IdSystem;\n /** The category scale's id (default: the axis letter). */\n scaleId?: string;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\ntype TickCallback = (this: Scale, value: number | string, index: number, ticks: Tick[]) => unknown;\n/**\n * Swap a category axis's tick labels for team logos: resolved labels are painted as images (after the datasets, under\n * the tooltip) and their text is blanked; unresolved labels keep their text, with one warning per distinct label set\n * (J28). Any other scale type is left as it is, with one warning.\n */\nexport function axisLogos(axis: \"x\" | \"y\", o: AxisLogoOptions): Plugin {\n if (axis !== \"x\" && axis !== \"y\")\n throw new InputError(`axis must be \"x\" or \"y\", got ${JSON.stringify(axis)}`);\n const { league, size = 24, markType = \"logo\", scaleId = axis, loadImage, ...rest } = o;\n checkSize(size, \"size\");\n const byChart = new WeakMap<Chart, { m: Map<string, Mark>; band: number }>();\n const bases = new WeakMap<TickCallback, number>(); // each wired callback -> the padding it was wired over\n return {\n id: `sdvplotAxisLogos${axis.toUpperCase()}`,\n afterDestroy: forget,\n beforeUpdate(chart) {\n // Chart.js merges options.scales into a fresh copy on every update (and `chart.options = next` replaces it), so\n // the tick wiring is (re)applied to that copy here, once per copy: never in beforeInit, never the caller's object.\n const conf = chart.config as unknown as {\n options: {\n scales?: Record<string, { type?: string; ticks?: { callback?: TickCallback; padding?: number } }>;\n };\n };\n const scale = conf.options.scales?.[scaleId];\n if (scale?.type !== \"category\") {\n byChart.delete(chart);\n warn(\n `chartjs:axisLogos:${scaleId}`,\n `axisLogos needs a category scale; scale ${JSON.stringify(scaleId)} is ${scale?.type ?? \"missing\"}, so its ticks are left as they are`,\n );\n return;\n }\n const labels = (chart.data.labels ?? []).map(String);\n const m = new Map<string, Mark>();\n imagesFor(labels, size, { league, kind: markType, ...rest }, loadImage).forEach((img, i) => {\n if (img !== undefined) m.set(labels[i] ?? \"\", img);\n });\n // the band the images fill: their height on x, the widest mark on y (a wordmark is several times its height)\n const band = axis === \"y\" ? Math.max(size, ...[...m.values()].map((img) => img.width)) : size;\n byChart.set(chart, { m, band });\n scale.ticks ??= {};\n const ticks = scale.ticks;\n const user = ticks.callback;\n let base = user === undefined ? undefined : bases.get(user);\n if (base === undefined) {\n base = ticks.padding ?? 3; // 3 = Chart.js's default padding\n const callback: TickCallback = function (this: Scale, value, index, all) {\n const label = this.getLabelForValue(Number(value));\n if (byChart.get(chart)?.m.has(label)) return \"\";\n return user === undefined ? label : user.call(this, value, index, all);\n };\n bases.set(callback, base);\n ticks.callback = callback;\n }\n ticks.padding = base + band;\n },\n afterDatasetsDraw(chart) {\n const scale = chart.scales[scaleId];\n const got = byChart.get(chart);\n if (scale === undefined || got === undefined) return;\n const { m, band } = got;\n // resolved options: Chart.js has filled every default by draw time\n const { grid, ticks } = scale.options as unknown as {\n grid: { display: boolean; drawTicks: boolean; tickLength: number };\n ticks: { padding: number };\n };\n const gap = (grid.display && grid.drawTicks ? grid.tickLength : 0) + ticks.padding - band;\n scale.ticks.forEach((t, i) => {\n const img = paint(chart, m.get(scale.getLabelForValue(t.value)));\n if (img === undefined) return;\n const at = scale.getPixelForTick(i);\n const { width: w, height: h } = img;\n const x =\n axis === \"y\" ? (scale.position === \"right\" ? scale.left + gap : scale.right - gap - w) : at - w / 2;\n const y =\n axis === \"x\" ? (scale.position === \"top\" ? scale.bottom - gap - h : scale.top + gap) : at - h / 2;\n chart.ctx.drawImage(img, x, y, w, h);\n });\n },\n };\n}\n\nexport interface WatermarkOptions {\n league: League;\n /** Image height in px (default 75, Game on Paper's win-probability chart); the width follows the mark's aspect. */\n size?: number;\n /** Opacity of the watermarks (default 0.4). */\n alpha?: number;\n /** Gap in px from the chart area's left edge and from its top / bottom (default 8). */\n inset?: number;\n season?: SeasonInput | readonly SeasonInput[];\n variant?: Variant;\n idSystem?: IdSystem;\n /**\n * Loads each image instead of a DOM image element, so this also runs in Node: pass `@napi-rs/canvas`'s `loadImage`.\n * See {@link ImageLike}.\n */\n loadImage?: (url: string) => Promise<ImageLike>;\n}\n/**\n * Faint team logos behind the datasets (Game on Paper's win-probability chart): the first team sits top-left of the\n * chart area, the last bottom-left, any between spaced evenly down the left edge, so pass `[home, away]` under a home\n * win-probability line. Unknown teams are skipped with one warning per call (J28); `variant: \"dark\"` falls back to a\n * light mark by polarity, so no `onerror` retry is needed.\n */\nexport function logoWatermarks(teams: readonly Value[], o: WatermarkOptions): Plugin {\n if (o.loadImage === undefined) needDom(\"logo watermarks\"); // before resolving, so SSR fails without a resolve warning\n const { league, size = 75, alpha = 0.4, inset = 8, loadImage, ...rest } = o;\n checkSize(size, \"size\");\n const a = checkAlpha(alpha);\n const imgs = imagesFor(teams, size, { league, kind: \"logo\", ...rest }, loadImage);\n const n = imgs.length;\n return {\n id: \"sdvplotLogoWatermarks\",\n afterDestroy: forget,\n beforeDatasetsDraw(chart) {\n const { ctx, chartArea: ar } = chart;\n if (!ar) return; // a draw before the first layout\n ctx.save();\n ctx.globalAlpha = a;\n imgs.forEach((m, i) => {\n const img = paint(chart, m);\n if (img === undefined) return;\n const t = n > 1 ? i / (n - 1) : 0;\n const y = ar.top + inset + t * (ar.bottom - ar.top - 2 * inset - img.height);\n ctx.drawImage(img, ar.left + inset, y, img.width, img.height);\n });\n ctx.restore();\n },\n };\n}\n"]}