@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.
- package/NOTICE.md +15 -0
- package/README.md +84 -8
- package/dist/chartjs-surface.d.ts +2 -2
- package/dist/chartjs-surface.js +2 -2
- package/dist/chartjs-surface.js.map +1 -1
- package/dist/chartjs.d.ts +32 -2
- package/dist/chartjs.js +7 -4
- package/dist/chartjs.js.map +1 -1
- package/dist/chunk-57WFSI4Q.js +128 -0
- package/dist/chunk-57WFSI4Q.js.map +1 -0
- package/dist/{chunk-KKH6ABMA.js → chunk-7ULOCCFL.js} +94 -4
- package/dist/chunk-7ULOCCFL.js.map +1 -0
- package/dist/chunk-AMXASQHT.js +120 -0
- package/dist/chunk-AMXASQHT.js.map +1 -0
- package/dist/chunk-B2MP37SR.js +175 -0
- package/dist/chunk-B2MP37SR.js.map +1 -0
- package/dist/{chunk-NLPH2VZT.js → chunk-DYMUVE6K.js} +4 -4
- package/dist/{chunk-NLPH2VZT.js.map → chunk-DYMUVE6K.js.map} +1 -1
- package/dist/{chunk-QY65DUEF.js → chunk-H2C3FMMA.js} +4 -10
- package/dist/chunk-H2C3FMMA.js.map +1 -0
- package/dist/{chunk-JJFTD4VB.js → chunk-J4P4HDBF.js} +4 -4
- package/dist/{chunk-JJFTD4VB.js.map → chunk-J4P4HDBF.js.map} +1 -1
- package/dist/chunk-M3XD2OSN.js +132 -0
- package/dist/chunk-M3XD2OSN.js.map +1 -0
- package/dist/{chunk-OKEE4AH6.js → chunk-OIILARXI.js} +3 -3
- package/dist/{chunk-OKEE4AH6.js.map → chunk-OIILARXI.js.map} +1 -1
- package/dist/chunk-RPVVJY74.js +170 -0
- package/dist/chunk-RPVVJY74.js.map +1 -0
- package/dist/chunk-UL5M6KDE.js +205 -0
- package/dist/chunk-UL5M6KDE.js.map +1 -0
- package/dist/chunk-WQT4IVLX.js +10 -0
- package/dist/chunk-WQT4IVLX.js.map +1 -0
- package/dist/{chunk-TAXO3VXH.js → chunk-ZAEQXFJM.js} +3 -3
- package/dist/{chunk-TAXO3VXH.js.map → chunk-ZAEQXFJM.js.map} +1 -1
- package/dist/cytoscape.d.ts +188 -0
- package/dist/cytoscape.js +219 -0
- package/dist/cytoscape.js.map +1 -0
- package/dist/d3.d.ts +3 -3
- package/dist/d3.js +6 -6
- package/dist/d3.js.map +1 -1
- package/dist/deckgl.d.ts +232 -0
- package/dist/deckgl.js +197 -0
- package/dist/deckgl.js.map +1 -0
- package/dist/echarts.js +5 -5
- package/dist/g2.d.ts +251 -0
- package/dist/g2.js +102 -0
- package/dist/g2.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -5
- package/dist/lightweight-charts.d.ts +217 -0
- package/dist/lightweight-charts.js +155 -0
- package/dist/lightweight-charts.js.map +1 -0
- package/dist/maplibre.d.ts +271 -0
- package/dist/maplibre.js +175 -0
- package/dist/maplibre.js.map +1 -0
- package/dist/mui.d.ts +338 -0
- package/dist/mui.js +184 -0
- package/dist/mui.js.map +1 -0
- package/dist/nivo.d.ts +193 -0
- package/dist/nivo.js +8 -0
- package/dist/nivo.js.map +1 -0
- package/dist/perspective.d.ts +198 -0
- package/dist/perspective.js +171 -0
- package/dist/perspective.js.map +1 -0
- package/dist/placement-UWkqUzpa.d.ts +32 -0
- package/dist/plot.d.ts +7 -5
- package/dist/plot.js +9 -8
- package/dist/plot.js.map +1 -1
- package/dist/plotly.js +5 -5
- package/dist/react.d.ts +279 -3
- package/dist/react.js +364 -6
- package/dist/react.js.map +1 -1
- package/dist/recharts.d.ts +162 -0
- package/dist/recharts.js +8 -0
- package/dist/recharts.js.map +1 -0
- package/dist/shadcn.d.ts +83 -0
- package/dist/shadcn.js +88 -0
- package/dist/shadcn.js.map +1 -0
- package/dist/shots.js +3 -2
- package/dist/shots.js.map +1 -1
- package/dist/surface-TR7YFJW3.js +4 -0
- package/dist/surface-TR7YFJW3.js.map +1 -0
- package/dist/surfaces-MIG7HOFU.js +6 -0
- package/dist/surfaces-MIG7HOFU.js.map +1 -0
- package/dist/surfaces-W-odWLpT.d.ts +47 -0
- package/dist/svelte/HeadshotMark.svelte +25 -0
- package/dist/svelte/HeadshotMark.svelte.d.ts +10 -0
- package/dist/svelte/HeadshotMark.svelte.d.ts.map +1 -0
- package/dist/svelte/LogoMark.svelte +25 -0
- package/dist/svelte/LogoMark.svelte.d.ts +10 -0
- package/dist/svelte/LogoMark.svelte.d.ts.map +1 -0
- package/dist/svelte/Marks.svelte +25 -0
- package/dist/svelte/Marks.svelte.d.ts +10 -0
- package/dist/svelte/Marks.svelte.d.ts.map +1 -0
- package/dist/svelte/Surface.svelte +29 -0
- package/dist/svelte/Surface.svelte.d.ts +9 -0
- package/dist/svelte/Surface.svelte.d.ts.map +1 -0
- package/dist/svelte/SurfaceBackdrop.svelte +26 -0
- package/dist/svelte/SurfaceBackdrop.svelte.d.ts +11 -0
- package/dist/svelte/SurfaceBackdrop.svelte.d.ts.map +1 -0
- package/dist/svelte/index.d.ts +13 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +11 -0
- package/dist/svelte-core.d.ts +139 -0
- package/dist/svelte-core.js +123 -0
- package/dist/svelte-core.js.map +1 -0
- package/dist/tanstack.d.ts +240 -0
- package/dist/tanstack.js +110 -0
- package/dist/tanstack.js.map +1 -0
- package/dist/testing.js +4 -5
- package/dist/testing.js.map +1 -1
- package/dist/three.d.ts +223 -0
- package/dist/three.js +50 -0
- package/dist/three.js.map +1 -0
- package/dist/{tiers-B6pUBPcE.d.ts → tiers-BN4md-GB.d.ts} +2 -30
- package/dist/unovis.d.ts +127 -0
- package/dist/unovis.js +108 -0
- package/dist/unovis.js.map +1 -0
- package/dist/uplot.d.ts +120 -0
- package/dist/uplot.js +110 -0
- package/dist/uplot.js.map +1 -0
- package/dist/vega.js +5 -5
- package/dist/victory.d.ts +107 -0
- package/dist/victory.js +38 -0
- package/dist/victory.js.map +1 -0
- package/package.json +218 -6
- package/dist/chunk-KKH6ABMA.js.map +0 -1
- package/dist/chunk-QY65DUEF.js.map +0 -1
- package/dist/chunk-RMT2GMFH.js +0 -97
- package/dist/chunk-RMT2GMFH.js.map +0 -1
- package/dist/chunk-SEBO35DV.js +0 -76
- package/dist/chunk-SEBO35DV.js.map +0 -1
- package/dist/chunk-TDNBAEQB.js +0 -105
- package/dist/chunk-TDNBAEQB.js.map +0 -1
- package/dist/surfaces-ChaD9nei.d.ts +0 -38
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { InputError } from './chunk-E7G7VSLV.js';
|
|
2
|
+
import { surface } from '@sportsdataverse/sporty';
|
|
3
|
+
|
|
4
|
+
function loops(points) {
|
|
5
|
+
const out = [];
|
|
6
|
+
let loop = [];
|
|
7
|
+
let away = 0;
|
|
8
|
+
for (const p of points) {
|
|
9
|
+
const first = loop[0];
|
|
10
|
+
loop.push(p);
|
|
11
|
+
if (first === void 0) continue;
|
|
12
|
+
if (p[0] !== first[0] || p[1] !== first[1]) away++;
|
|
13
|
+
else if (away >= 2) {
|
|
14
|
+
out.push(loop);
|
|
15
|
+
loop = [];
|
|
16
|
+
away = 0;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (away >= 2) out.push(loop);
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
var turn = (a, b, c) => (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
|
|
23
|
+
function ring(loop) {
|
|
24
|
+
const r = loop.filter((p, i) => {
|
|
25
|
+
const q = loop[(i + 1) % loop.length];
|
|
26
|
+
return p[0] !== q[0] || p[1] !== q[1];
|
|
27
|
+
});
|
|
28
|
+
const flat = (p, i) => {
|
|
29
|
+
const [a, c] = [r[(i - 1 + r.length) % r.length], r[(i + 1) % r.length]];
|
|
30
|
+
return Math.abs(turn(a, p, c)) <= 1e-9 * Math.hypot(p[0] - a[0], p[1] - a[1]) * Math.hypot(c[0] - p[0], c[1] - p[1]);
|
|
31
|
+
};
|
|
32
|
+
for (let i = r.findIndex(flat); i >= 0 && r.length >= 3; i = r.findIndex(flat)) r.splice(i, 1);
|
|
33
|
+
const area = signedArea(r);
|
|
34
|
+
return area < 0 ? r.reverse() : r;
|
|
35
|
+
}
|
|
36
|
+
function signedArea(r) {
|
|
37
|
+
let s = 0;
|
|
38
|
+
for (let i = 0; i < r.length; i++) {
|
|
39
|
+
const [a, b] = [r[i], r[(i + 1) % r.length]];
|
|
40
|
+
s += a[0] * b[1] - b[0] * a[1];
|
|
41
|
+
}
|
|
42
|
+
return s / 2;
|
|
43
|
+
}
|
|
44
|
+
function empty(r) {
|
|
45
|
+
let [x0, y0, x1, y1] = [
|
|
46
|
+
Number.POSITIVE_INFINITY,
|
|
47
|
+
Number.POSITIVE_INFINITY,
|
|
48
|
+
Number.NEGATIVE_INFINITY,
|
|
49
|
+
Number.NEGATIVE_INFINITY
|
|
50
|
+
];
|
|
51
|
+
for (const [x, y] of r)
|
|
52
|
+
[x0, y0, x1, y1] = [Math.min(x0, x), Math.min(y0, y), Math.max(x1, x), Math.max(y1, y)];
|
|
53
|
+
return r.length < 3 || Math.abs(signedArea(r)) <= 1e-9 * ((x1 - x0) ** 2 + (y1 - y0) ** 2);
|
|
54
|
+
}
|
|
55
|
+
function simple(r) {
|
|
56
|
+
const n = r.length;
|
|
57
|
+
const side = (a, b, c) => Math.sign(turn(a, b, c));
|
|
58
|
+
for (let i = 0; i < n; i++)
|
|
59
|
+
for (let j = i + 2; j < n; j++) {
|
|
60
|
+
if (i === 0 && j === n - 1) continue;
|
|
61
|
+
const [a, b, c, d] = [r[i], r[(i + 1) % n], r[j], r[(j + 1) % n]];
|
|
62
|
+
if (side(a, b, c) * side(a, b, d) >= 0 || side(c, d, a) * side(c, d, b) >= 0) continue;
|
|
63
|
+
const s = turn(c, d, a) / (turn(c, d, a) - turn(c, d, b));
|
|
64
|
+
const x = [a[0] + s * (b[0] - a[0]), a[1] + s * (b[1] - a[1])];
|
|
65
|
+
return [
|
|
66
|
+
...simple([...r.slice(0, i + 1), x, ...r.slice(j + 1)]),
|
|
67
|
+
...simple([x, ...r.slice(i + 1, j + 1)])
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
return [[...r]];
|
|
71
|
+
}
|
|
72
|
+
function triangulate(r) {
|
|
73
|
+
const n = r.length;
|
|
74
|
+
const prev = Array.from({ length: n }, (_, i2) => (i2 - 1 + n) % n);
|
|
75
|
+
const next = Array.from({ length: n }, (_, i2) => (i2 + 1) % n);
|
|
76
|
+
const convex = (i2) => turn(r[prev[i2]], r[i2], r[next[i2]]) > 0;
|
|
77
|
+
const reflex = /* @__PURE__ */ new Set();
|
|
78
|
+
for (let i2 = 0; i2 < n; i2++) if (!convex(i2)) reflex.add(i2);
|
|
79
|
+
const inside = (p, a, b, c) => turn(a, b, p) >= 0 && turn(b, c, p) >= 0 && turn(c, a, p) >= 0;
|
|
80
|
+
const ear = (i2) => {
|
|
81
|
+
if (!convex(i2)) return false;
|
|
82
|
+
const [a, b, c] = [prev[i2], i2, next[i2]];
|
|
83
|
+
for (const j of reflex) {
|
|
84
|
+
if (j === a || j === b || j === c) continue;
|
|
85
|
+
const p = r[j];
|
|
86
|
+
const same = (q) => p[0] === r[q][0] && p[1] === r[q][1];
|
|
87
|
+
if (!same(a) && !same(c) && inside(p, r[a], r[b], r[c])) return false;
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
};
|
|
91
|
+
const out = [];
|
|
92
|
+
let i = 0;
|
|
93
|
+
let left = n;
|
|
94
|
+
let tried = 0;
|
|
95
|
+
while (left > 3) {
|
|
96
|
+
if (ear(i) || tried > left) {
|
|
97
|
+
const [a, c] = [prev[i], next[i]];
|
|
98
|
+
out.push(a, i, c);
|
|
99
|
+
next[a] = c;
|
|
100
|
+
prev[c] = a;
|
|
101
|
+
reflex.delete(i);
|
|
102
|
+
for (const k of [a, c]) if (convex(k)) reflex.delete(k);
|
|
103
|
+
left--;
|
|
104
|
+
tried = 0;
|
|
105
|
+
i = c;
|
|
106
|
+
} else {
|
|
107
|
+
i = next[i];
|
|
108
|
+
tried++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
out.push(prev[i], i, next[i]);
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
function linear(color, name) {
|
|
115
|
+
if (!/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color))
|
|
116
|
+
throw new InputError(
|
|
117
|
+
`surfaceMesh: ${name}'s fill ${JSON.stringify(color)} is not a hex colour (#rrggbb or #rrggbbaa)`
|
|
118
|
+
);
|
|
119
|
+
let c = color.slice(1);
|
|
120
|
+
if (c.length <= 4) c = [...c].map((d) => d + d).join("");
|
|
121
|
+
const lin = (s) => s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
122
|
+
const [r, g, b] = [0, 2, 4].map((i) => lin(Number.parseInt(c.slice(i, i + 2), 16) / 255));
|
|
123
|
+
return [r, g, b, c.length === 8 ? Number.parseInt(c.slice(6), 16) / 255 : 1];
|
|
124
|
+
}
|
|
125
|
+
var drawn = (f) => f.points.length > 0 && f.points.every(([x, y]) => Number.isFinite(x) && Number.isFinite(y)) && !(f.fill.length === 9 && f.fill.endsWith("00"));
|
|
126
|
+
function surfaceMesh(sport, league, o = {}) {
|
|
127
|
+
const scene = surface(sport, league, o);
|
|
128
|
+
const [x0, y0, x1, y1] = scene.bbox;
|
|
129
|
+
const parts = [];
|
|
130
|
+
if (scene.background !== void 0)
|
|
131
|
+
parts.push({
|
|
132
|
+
name: "background",
|
|
133
|
+
color: scene.background,
|
|
134
|
+
ring: ring([
|
|
135
|
+
[x0, y0],
|
|
136
|
+
[x1, y0],
|
|
137
|
+
[x1, y1],
|
|
138
|
+
[x0, y1]
|
|
139
|
+
])
|
|
140
|
+
});
|
|
141
|
+
for (const f of scene.features)
|
|
142
|
+
if (f.kind === "polygon" && drawn(f))
|
|
143
|
+
for (const l of loops(f.points))
|
|
144
|
+
for (const s of simple(ring(l))) {
|
|
145
|
+
const r = ring(s);
|
|
146
|
+
if (!empty(r)) parts.push({ name: f.name, color: f.fill, ring: r });
|
|
147
|
+
}
|
|
148
|
+
const vertices = parts.reduce((s, p) => s + p.ring.length, 0);
|
|
149
|
+
const positions = new Float32Array(vertices * 3);
|
|
150
|
+
const colors = new Float32Array(vertices * 4);
|
|
151
|
+
const indices = new Uint32Array(parts.reduce((s, p) => s + 3 * (p.ring.length - 2), 0));
|
|
152
|
+
const out = [];
|
|
153
|
+
let v = 0;
|
|
154
|
+
let i = 0;
|
|
155
|
+
for (const { name, color, ring: r } of parts) {
|
|
156
|
+
const rgba = linear(color, name);
|
|
157
|
+
r.forEach(([x, y], k) => {
|
|
158
|
+
positions.set([x, y, 0], 3 * (v + k));
|
|
159
|
+
colors.set(rgba, 4 * (v + k));
|
|
160
|
+
});
|
|
161
|
+
const tris = triangulate(r);
|
|
162
|
+
indices.set(
|
|
163
|
+
tris.map((t) => t + v),
|
|
164
|
+
i
|
|
165
|
+
);
|
|
166
|
+
out.push({ name, color, vertexStart: v, vertexCount: r.length, indexStart: i, indexCount: tris.length });
|
|
167
|
+
v += r.length;
|
|
168
|
+
i += tris.length;
|
|
169
|
+
}
|
|
170
|
+
return { positions, colors, indices, loops: out, units: scene.units, bbox: scene.bbox };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { surfaceMesh };
|
|
174
|
+
//# sourceMappingURL=chunk-B2MP37SR.js.map
|
|
175
|
+
//# sourceMappingURL=chunk-B2MP37SR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/three/surface.ts"],"names":["i","sportySurface"],"mappings":"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","file":"chunk-B2MP37SR.js","sourcesContent":["import { type PolygonFeature, surface as sportySurface } from \"@sportsdataverse/sporty\";\nimport type { LeagueOf, OptionsOf, Sport, Units } from \"@sportsdataverse/sporty\";\nimport { InputError } from \"../errors.js\";\n\n/** One closed loop of `surfaceMesh`: where its vertices and triangles sit in the mesh buffers. */\nexport interface SurfaceLoop {\n /** The sporty feature it comes from (e.g. \"infield_dirt\"), or \"background\" for the surface's own background. */\n name: string;\n /** The feature's sporty fill, `#rrggbb` or `#rrggbbaa`, as sporty gives it. */\n color: string;\n /** Its first vertex and number of vertices. */\n vertexStart: number;\n vertexCount: number;\n /** Its first index and number of indices (three per triangle). */\n indexStart: number;\n indexCount: number;\n}\n/**\n * A sporty playing surface as one triangle mesh in the z = 0 plane, in the surface's own units and frame (feet for a\n * baseball field or a rink, metres for a pitch; origin where sporty puts it), ready for a three.js `BufferGeometry`.\n */\nexport interface SurfaceMesh {\n /** x, y, z per vertex; z is 0. */\n positions: Float32Array;\n /** r, g, b, a per vertex, 0 to 1, in linear sRGB (three.js's working colour space): a vertex-colour attribute. */\n colors: Float32Array;\n /** Three vertex indices per triangle, counter-clockwise seen from +z, back to front. */\n indices: Uint32Array;\n /** Every loop, in drawing order (later ones lie over earlier ones in the same plane). */\n loops: SurfaceLoop[];\n units: Units;\n /** The surface's extent, `[x0, y0, x1, y1]`. */\n bbox: readonly [x0: number, y0: number, x1: number, y1: number];\n}\n\ntype Pt = readonly [x: number, y: number];\n/**\n * A feature's path as closed loops. sporty (after sportyR) draws some features as two loops in one path, such as a\n * faceoff circle's two half rings each closing back on its first point: an SVG or canvas fill draws that as it is, but\n * a triangulation of the path as one ring fills the wrong side of it (deck.gl's earcut did). A loop ends where the path\n * comes back to that loop's first point, after at least two other points (a repeated first point does not end it):\n * the rule of `sdvplot/deckgl` and sdvplot.pydeck. ponytail: a loop inside another would be filled, not cut out as a\n * hole; sporty builds every ring from two half rings, so none is.\n */\nfunction loops(points: readonly Pt[]): Pt[][] {\n const out: Pt[][] = [];\n let loop: Pt[] = [];\n let away = 0; // points of this loop that are not its first\n for (const p of points) {\n const first = loop[0];\n loop.push(p);\n if (first === undefined) continue;\n if (p[0] !== first[0] || p[1] !== first[1]) away++;\n else if (away >= 2) {\n out.push(loop);\n loop = [];\n away = 0;\n }\n }\n if (away >= 2) out.push(loop); // an open path, closed like a fill\n return out;\n}\n\nconst turn = (a: Pt, b: Pt, c: Pt): number => (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);\n\n/**\n * A loop as a simple counter-clockwise ring: no repeated point, no point on a straight run between its neighbours\n * (or a spike back on itself), which add nothing to the area and leave an ear-clipper with zero-area ears.\n */\nfunction ring(loop: readonly Pt[]): Pt[] {\n const r = loop.filter((p, i) => {\n const q = loop[(i + 1) % loop.length] as Pt;\n return p[0] !== q[0] || p[1] !== q[1];\n });\n // flat: the corner's sine under 1e-9, i.e. straight up to rounding\n const flat = (p: Pt, i: number): boolean => {\n const [a, c] = [r[(i - 1 + r.length) % r.length] as Pt, r[(i + 1) % r.length] as Pt];\n return (\n Math.abs(turn(a, p, c)) <=\n 1e-9 * Math.hypot(p[0] - a[0], p[1] - a[1]) * Math.hypot(c[0] - p[0], c[1] - p[1])\n );\n };\n for (let i = r.findIndex(flat); i >= 0 && r.length >= 3; i = r.findIndex(flat)) r.splice(i, 1);\n const area = signedArea(r);\n return area < 0 ? r.reverse() : r;\n}\nfunction signedArea(r: readonly Pt[]): number {\n let s = 0;\n for (let i = 0; i < r.length; i++) {\n const [a, b] = [r[i] as Pt, r[(i + 1) % r.length] as Pt];\n s += a[0] * b[1] - b[0] * a[1];\n }\n return s / 2;\n}\n/**\n * No area to fill: a path that goes out along a line and back along it (the NLL goal fan), which a fill leaves\n * invisible, as sporty's own SVG does, or the sliver left where a ring touched itself.\n */\nfunction empty(r: readonly Pt[]): boolean {\n let [x0, y0, x1, y1] = [\n Number.POSITIVE_INFINITY,\n Number.POSITIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n Number.NEGATIVE_INFINITY,\n ];\n for (const [x, y] of r)\n [x0, y0, x1, y1] = [Math.min(x0, x), Math.min(y0, y), Math.max(x1, x), Math.max(y1, y)];\n return r.length < 3 || Math.abs(signedArea(r)) <= 1e-9 * ((x1 - x0) ** 2 + (y1 - y0) ** 2);\n}\n\n/**\n * A ring that crosses itself split at each crossing into rings that do not, each to be filled: what an SVG fill shows\n * of a figure-of-eight. sporty has a few: the NHL goaltender's trapezoids and the faceoff hash marks nearest centre\n * ice twist at their corners by an inch. Rings come back un-oriented (`ring` orients them).\n */\nfunction simple(r: readonly Pt[]): Pt[][] {\n const n = r.length;\n const side = (a: Pt, b: Pt, c: Pt): number => Math.sign(turn(a, b, c));\n for (let i = 0; i < n; i++)\n for (let j = i + 2; j < n; j++) {\n if (i === 0 && j === n - 1) continue; // neighbours across the closing edge\n const [a, b, c, d] = [r[i] as Pt, r[(i + 1) % n] as Pt, r[j] as Pt, r[(j + 1) % n] as Pt];\n if (side(a, b, c) * side(a, b, d) >= 0 || side(c, d, a) * side(c, d, b) >= 0) continue;\n const s = turn(c, d, a) / (turn(c, d, a) - turn(c, d, b)); // where the crossing is along a -> b\n const x: Pt = [a[0] + s * (b[0] - a[0]), a[1] + s * (b[1] - a[1])];\n return [\n ...simple([...r.slice(0, i + 1), x, ...r.slice(j + 1)]),\n ...simple([x, ...r.slice(i + 1, j + 1)]),\n ];\n }\n return [[...r]];\n}\n\n/**\n * Ear clipping of a simple counter-clockwise ring: n - 2 triangles, as indices into it. An ear is a convex corner whose\n * triangle holds no other corner of the ring; only reflex corners can lie in one, so only they are checked.\n * ponytail: O(n²) in the worst case; sporty's longest loop is about 800 points.\n */\nfunction triangulate(r: readonly Pt[]): number[] {\n const n = r.length;\n const prev = Array.from({ length: n }, (_, i) => (i - 1 + n) % n);\n const next = Array.from({ length: n }, (_, i) => (i + 1) % n);\n const convex = (i: number): boolean =>\n turn(r[prev[i] as number] as Pt, r[i] as Pt, r[next[i] as number] as Pt) > 0;\n const reflex = new Set<number>();\n for (let i = 0; i < n; i++) if (!convex(i)) reflex.add(i);\n const inside = (p: Pt, a: Pt, b: Pt, c: Pt): boolean =>\n turn(a, b, p) >= 0 && turn(b, c, p) >= 0 && turn(c, a, p) >= 0;\n const ear = (i: number): boolean => {\n if (!convex(i)) return false;\n const [a, b, c] = [prev[i] as number, i, next[i] as number];\n for (const j of reflex) {\n if (j === a || j === b || j === c) continue;\n const p = r[j] as Pt;\n const same = (q: number): boolean => p[0] === (r[q] as Pt)[0] && p[1] === (r[q] as Pt)[1];\n if (!same(a) && !same(c) && inside(p, r[a] as Pt, r[b] as Pt, r[c] as Pt)) return false;\n }\n return true;\n };\n const out: number[] = [];\n let i = 0;\n let left = n;\n let tried = 0;\n while (left > 3) {\n // ponytail: with no ear left (a ring that is not simple), clip the corner anyway rather than loop forever\n if (ear(i) || tried > left) {\n const [a, c] = [prev[i] as number, next[i] as number];\n out.push(a, i, c);\n next[a] = c;\n prev[c] = a;\n reflex.delete(i);\n for (const k of [a, c]) if (convex(k)) reflex.delete(k);\n left--;\n tried = 0;\n i = c;\n } else {\n i = next[i] as number;\n tried++;\n }\n }\n out.push(prev[i] as number, i, next[i] as number);\n return out;\n}\n\n/**\n * A feature's fill (\"#rgb\", \"#rgba\", \"#rrggbb\" or \"#rrggbbaa\") as r, g, b in linear sRGB and a, each 0 to 1. Anything\n * else (a CSS colour name given through `colorUpdates`, say) is an InputError naming the feature: a vertex colour\n * cannot be parsed from it.\n */\nfunction linear(color: string, name: string): [number, number, number, number] {\n if (!/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color))\n throw new InputError(\n `surfaceMesh: ${name}'s fill ${JSON.stringify(color)} is not a hex colour (#rrggbb or #rrggbbaa)`,\n );\n let c = color.slice(1);\n if (c.length <= 4) c = [...c].map((d) => d + d).join(\"\");\n const lin = (s: number): number => (s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4);\n const [r, g, b] = [0, 2, 4].map((i) => lin(Number.parseInt(c.slice(i, i + 2), 16) / 255));\n return [r as number, g as number, b as number, c.length === 8 ? Number.parseInt(c.slice(6), 16) / 255 : 1];\n}\n\nconst drawn = (f: PolygonFeature): boolean =>\n f.points.length > 0 &&\n f.points.every(([x, y]) => Number.isFinite(x) && Number.isFinite(y)) &&\n !(f.fill.length === 9 && f.fill.endsWith(\"00\"));\n\n/**\n * sporty's playing surface for `sport` and `league` (sporty's own league keys, e.g. `surfaceMesh(\"baseball\", \"mlb\")`,\n * `surfaceMesh(\"hockey\", \"nhl\")`) as one triangle mesh in the z = 0 plane: plain buffers (positions, linear-sRGB\n * vertex colours, indices), with no three.js import, ready for `new BufferGeometry()` in three.js or the `<Surface3D>`\n * component in `sdvplot/react`. World units: the surface's own (feet for a baseball field or a rink, metres for a\n * pitch), in sporty's frame: a baseball field has home plate's point at the origin and +y towards centre field,\n * Statcast's frame, so `statcastPitchPath` points draw over it unconverted; the other surfaces have the origin at\n * their centre. The surface's background colour (a baseball field's outfield grass) is the first loop, over the\n * extent; then each closed loop of each polygon feature, in sporty's drawing order (a faceoff circle is two loops,\n * its half rings), filled with its colour, alpha included. Hidden features (a `#rrggbb00` fill) and text (a football\n * field's numbers) are left out, and sporty's heights (goal frames, backboards) are flattened: z is 0 throughout.\n * Every loop lies in one plane, so draw the mesh in order without depth writes (`depthWrite: false`), first\n * (`renderOrder` -1), with `vertexColors`, `transparent` and `toneMapped: false`, as `<Surface3D>` does: later loops\n * then paint over earlier ones with no z-fighting. `o` is passed to sporty's `surface()` (`colorUpdates`, `units`,\n * `rotation`, ...).\n *\n * @example\n * ```ts\n * import { surfaceMesh } from \"@sportsdataverse/sdvplot/three\";\n *\n * const field = surfaceMesh(\"baseball\", \"mlb\");\n * // in three.js: geometry.setAttribute(\"position\", new BufferAttribute(field.positions, 3)), and so on\n * field.loops.map((l) => l.name);\n * ```\n */\nexport function surfaceMesh<S extends Sport>(\n sport: S,\n league: LeagueOf<S>,\n o: OptionsOf<S> = {} as OptionsOf<S>,\n): SurfaceMesh {\n const scene = sportySurface(sport, league, o);\n const [x0, y0, x1, y1] = scene.bbox;\n const parts: { name: string; color: string; ring: Pt[] }[] = [];\n if (scene.background !== undefined)\n parts.push({\n name: \"background\",\n color: scene.background,\n ring: ring([\n [x0, y0],\n [x1, y0],\n [x1, y1],\n [x0, y1],\n ]),\n });\n // ponytail: features draw in array order (sporty's zIndex is its position); sort here if that ever changes\n for (const f of scene.features)\n if (f.kind === \"polygon\" && drawn(f))\n for (const l of loops(f.points))\n for (const s of simple(ring(l))) {\n const r = ring(s);\n if (!empty(r)) parts.push({ name: f.name, color: f.fill, ring: r });\n }\n const vertices = parts.reduce((s, p) => s + p.ring.length, 0);\n const positions = new Float32Array(vertices * 3);\n const colors = new Float32Array(vertices * 4);\n const indices = new Uint32Array(parts.reduce((s, p) => s + 3 * (p.ring.length - 2), 0));\n const out: SurfaceLoop[] = [];\n let v = 0;\n let i = 0;\n for (const { name, color, ring: r } of parts) {\n const rgba = linear(color, name);\n r.forEach(([x, y], k) => {\n positions.set([x, y, 0], 3 * (v + k));\n colors.set(rgba, 4 * (v + k));\n });\n const tris = triangulate(r);\n indices.set(\n tris.map((t) => t + v),\n i,\n );\n out.push({ name, color, vertexStart: v, vertexCount: r.length, indexStart: i, indexCount: tris.length });\n v += r.length;\n i += tris.length;\n }\n return { positions, colors, indices, loops: out, units: scene.units, bbox: scene.bbox };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { checkHeight, checkAlpha } from './chunk-
|
|
2
|
-
import { resolveSync, getLeagueSync } from './chunk-
|
|
1
|
+
import { checkHeight, checkAlpha } from './chunk-7ULOCCFL.js';
|
|
2
|
+
import { resolveSync, getLeagueSync } from './chunk-ZAEQXFJM.js';
|
|
3
3
|
import { InputError, warn } from './chunk-E7G7VSLV.js';
|
|
4
4
|
|
|
5
5
|
// src/tiers.ts
|
|
@@ -123,5 +123,5 @@ function prepareTiers(rows, league, o = {}) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
export { TIERS_SUBTITLE, TIER_DESC, TIER_THEMES, prepareTiers, wrapLabel };
|
|
126
|
-
//# sourceMappingURL=chunk-
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
126
|
+
//# sourceMappingURL=chunk-DYMUVE6K.js.map
|
|
127
|
+
//# sourceMappingURL=chunk-DYMUVE6K.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tiers.ts"],"names":[],"mappings":"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","file":"chunk-NLPH2VZT.js","sourcesContent":["import { InputError, warn } from \"./errors.js\";\nimport { getLeagueSync } from \"./index-data.js\";\nimport { checkAlpha, checkHeight } from \"./placement.js\";\nimport { type Value, resolveSync } from \"./resolve.js\";\nimport type { League, TeamId, Variant } from \"./types.js\";\n\nexport const TIER_DESC: Readonly<Record<number, string>> = {\n 1: \"Elite\",\n 2: \"Very Good\",\n 3: \"Medium\",\n 4: \"Bad\",\n 5: \"What are they doing?\",\n 6: \"\",\n 7: \"\",\n};\nexport const TIERS_SUBTITLE = \"created with the #sdvplot Tiermaker\";\nexport const TIER_THEMES = {\n dark: { bg: \"#1e1e1e\", line: \"#e0e0e0\", text: \"#ffffff\", muted: \"#8e8e93\" },\n light: { bg: \"#ffffff\", line: \"#3a3a3c\", text: \"#1e1e1e\", muted: \"#636366\" },\n} as const;\nconst AUTO_VARIANT = { dark: \"dark\", light: \"default\" } as const;\n// ponytail: DEFAULT_HEIGHT is the Python one (a fraction of panel height for 32 logos in 5 tiers).\nconst DEFAULT_HEIGHT = 0.1;\n\nexport interface TierRow {\n tierNo?: Value;\n tier_no?: Value;\n team: Value;\n tierRank?: Value;\n tier_rank?: Value;\n}\nexport interface TiersOptions {\n /** `undefined` gives the league name plus \"Team Tiers\"; `null` or an empty string gives no title. */\n title?: string | null;\n /** `undefined` gives the Tiermaker line; `null` or an empty string gives none. */\n subtitle?: string | null;\n caption?: string | null;\n tierDesc?: Readonly<Record<number, string>>;\n presort?: boolean;\n alpha?: number;\n /** Fraction of the plot height in (0, 1]; default 0.1. */\n height?: number;\n noLineBelowTier?: number | readonly number[];\n theme?: \"dark\" | \"light\";\n variant?: Variant | \"auto\";\n}\nexport interface Tiers {\n x: number[];\n y: number[];\n teamIds: TeamId[];\n labels: string[];\n lines: number[];\n breaks: number[];\n breakLabels: string[];\n xlim: [number, number];\n ylim: [number, number];\n title: string;\n subtitle: string | null;\n caption: string | null;\n height: number;\n alpha: number;\n variant: Variant;\n theme: (typeof TIER_THEMES)[keyof typeof TIER_THEMES];\n}\n\n/** `textwrap.wrap(text, 14, break_long_words=False, break_on_hyphens=False)` joined by newlines: lines of at most 14 characters, a longer word kept whole on its own line. */\nexport function wrapLabel(text: string): string {\n const out: string[] = [];\n let line = \"\";\n for (const w of text.split(/\\s+/).filter(Boolean)) {\n if (line && line.length + 1 + w.length > 14) {\n out.push(line);\n line = w;\n } else line = line ? `${line} ${w}` : w;\n }\n if (line) out.push(line);\n return out.join(\"\\n\");\n}\n\nconst miss = (v: Value): boolean =>\n v === null || v === undefined || (typeof v === \"number\" && Number.isNaN(v));\nconst real = (v: Value): boolean => (typeof v === \"number\" && !Number.isNaN(v)) || typeof v === \"bigint\";\n\n/** Port of `sdvplot._tiers.prepare`: validate the rows and compute everything a tier plot draws. */\nexport function prepareTiers(rows: readonly TierRow[], league: League, o: TiersOptions = {}): Tiers {\n const theme = o.theme ?? \"dark\";\n if (!Object.hasOwn(TIER_THEMES, theme))\n throw new InputError(`theme must be \"dark\" or \"light\", got ${String(theme)}`);\n const height = o.height === undefined ? DEFAULT_HEIGHT : checkHeight(o.height);\n const alpha = checkAlpha(o.alpha ?? 0.8);\n const tiers = rows.map((r): Value => r.tierNo ?? r.tier_no);\n const teams = rows.map((r) => r.team);\n const ranksIn = rows.map((r): Value => r.tierRank ?? r.tier_rank);\n const given = !o.presort && ranksIn.some((v) => v !== undefined) ? ranksIn : undefined;\n\n const all = rows.map((_, i) => i);\n const absent = all.filter((i) => miss(tiers[i]) || (given !== undefined && miss(given[i])));\n if (absent.length) {\n const names = absent.map((i) => String(teams[i]));\n const extra = names.length > 10 ? ` and ${names.length - 10} more` : \"\";\n const shown = `${names.slice(0, 10).join(\", \")}${extra}`;\n warn(\n `tiers:${league}:missing:${shown}`,\n `skipped ${names.length} point(s) with a missing tier_no or tier_rank: ${shown}`,\n );\n }\n let idx = all.filter((i) => !absent.includes(i));\n if (!idx.length) throw new InputError(\"data has no rows with a tier_no\");\n if (!idx.every((i) => real(tiers[i]) && (given === undefined || real(given[i]))))\n throw new InputError(\"tier_no and tier_rank must hold numbers (tier 1 is the top tier)\");\n const tierOf = (i: number): number => Number(tiers[i]);\n if (o.presort) {\n // arrange(tier_no, team), then rank within the tier; a missing team last, as R's NA\n const name = (i: number): string => String(teams[i]);\n const cp = (i: number): number[] => Array.from(name(i), (c) => c.codePointAt(0) as number);\n const cmp = (a: number[], b: number[]): number => {\n for (let k = 0; k < Math.min(a.length, b.length); k++)\n if (a[k] !== b[k]) return (a[k] as number) - (b[k] as number);\n return a.length - b.length;\n };\n idx = idx.sort(\n (a, b) => tierOf(a) - tierOf(b) || Number(miss(teams[a])) - Number(miss(teams[b])) || cmp(cp(a), cp(b)),\n );\n }\n const ranks = new Map<number, number>();\n const seen = new Map<number, number>();\n for (const i of idx) {\n if (given) ranks.set(i, Number(given[i]));\n else {\n const t = tierOf(i);\n const n = (seen.get(t) ?? 0) + 1;\n seen.set(t, n);\n ranks.set(i, n);\n }\n }\n\n // Rank first, then resolve: an unknown team keeps its slot (and the x range) but draws nothing.\n const ids = resolveSync(\n idx.map((i) => teams[i]),\n league,\n );\n const kept = idx.flatMap((i, k) => {\n const id = ids[k];\n return id === undefined ? [] : [[i, id] as const];\n });\n const abbr = new Map(getLeagueSync(league).teams.map((t) => [t.team_id, t.abbr]));\n const levels = [...new Set(idx.map(tierOf))].sort((a, b) => a - b);\n const skip = new Set<number>(\n o.noLineBelowTier === undefined\n ? []\n : typeof o.noLineBelowTier === \"number\"\n ? [o.noLineBelowTier]\n : o.noLineBelowTier,\n );\n const desc = o.tierDesc ?? TIER_DESC;\n const rs = [...ranks.values()];\n const lo = Math.min(...rs);\n const hi = Math.max(...rs);\n const pad = lo === hi ? 0.5 : 0.05 * (hi - lo);\n const first = levels[0] as number;\n const last = levels[levels.length - 1] as number;\n return {\n x: kept.map(([i]) => ranks.get(i) as number),\n y: kept.map(([i]) => tierOf(i)),\n teamIds: kept.map(([, id]) => id),\n labels: kept.map(([i, id]) => abbr.get(id) || String(teams[i])),\n lines: [first - 0.5, ...levels.filter((t) => !skip.has(t)).map((t) => t + 0.5)],\n breaks: levels,\n breakLabels: levels.map((t) => wrapLabel(desc[t] ?? \"\")),\n xlim: [lo - pad, hi + pad],\n ylim: [first - 0.6, last + 0.6],\n title: o.title === undefined ? `${league.toUpperCase()} Team Tiers` : (o.title ?? \"\"),\n subtitle: o.subtitle === undefined ? TIERS_SUBTITLE : o.subtitle,\n caption: o.caption ?? null,\n height,\n alpha,\n variant: (o.variant ?? \"auto\") === \"auto\" ? AUTO_VARIANT[theme] : (o.variant as Variant),\n theme: TIER_THEMES[theme],\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/tiers.ts"],"names":[],"mappings":"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","file":"chunk-DYMUVE6K.js","sourcesContent":["import { InputError, warn } from \"./errors.js\";\nimport { getLeagueSync } from \"./index-data.js\";\nimport { checkAlpha, checkHeight } from \"./placement.js\";\nimport { type Value, resolveSync } from \"./resolve.js\";\nimport type { League, TeamId, Variant } from \"./types.js\";\n\nexport const TIER_DESC: Readonly<Record<number, string>> = {\n 1: \"Elite\",\n 2: \"Very Good\",\n 3: \"Medium\",\n 4: \"Bad\",\n 5: \"What are they doing?\",\n 6: \"\",\n 7: \"\",\n};\nexport const TIERS_SUBTITLE = \"created with the #sdvplot Tiermaker\";\nexport const TIER_THEMES = {\n dark: { bg: \"#1e1e1e\", line: \"#e0e0e0\", text: \"#ffffff\", muted: \"#8e8e93\" },\n light: { bg: \"#ffffff\", line: \"#3a3a3c\", text: \"#1e1e1e\", muted: \"#636366\" },\n} as const;\nconst AUTO_VARIANT = { dark: \"dark\", light: \"default\" } as const;\n// ponytail: DEFAULT_HEIGHT is the Python one (a fraction of panel height for 32 logos in 5 tiers).\nconst DEFAULT_HEIGHT = 0.1;\n\nexport interface TierRow {\n tierNo?: Value;\n tier_no?: Value;\n team: Value;\n tierRank?: Value;\n tier_rank?: Value;\n}\nexport interface TiersOptions {\n /** `undefined` gives the league name plus \"Team Tiers\"; `null` or an empty string gives no title. */\n title?: string | null;\n /** `undefined` gives the Tiermaker line; `null` or an empty string gives none. */\n subtitle?: string | null;\n caption?: string | null;\n tierDesc?: Readonly<Record<number, string>>;\n presort?: boolean;\n alpha?: number;\n /** Fraction of the plot height in (0, 1]; default 0.1. */\n height?: number;\n noLineBelowTier?: number | readonly number[];\n theme?: \"dark\" | \"light\";\n variant?: Variant | \"auto\";\n}\nexport interface Tiers {\n x: number[];\n y: number[];\n teamIds: TeamId[];\n labels: string[];\n lines: number[];\n breaks: number[];\n breakLabels: string[];\n xlim: [number, number];\n ylim: [number, number];\n title: string;\n subtitle: string | null;\n caption: string | null;\n height: number;\n alpha: number;\n variant: Variant;\n theme: (typeof TIER_THEMES)[keyof typeof TIER_THEMES];\n}\n\n/** `textwrap.wrap(text, 14, break_long_words=False, break_on_hyphens=False)` joined by newlines: lines of at most 14 characters, a longer word kept whole on its own line. */\nexport function wrapLabel(text: string): string {\n const out: string[] = [];\n let line = \"\";\n for (const w of text.split(/\\s+/).filter(Boolean)) {\n if (line && line.length + 1 + w.length > 14) {\n out.push(line);\n line = w;\n } else line = line ? `${line} ${w}` : w;\n }\n if (line) out.push(line);\n return out.join(\"\\n\");\n}\n\nconst miss = (v: Value): boolean =>\n v === null || v === undefined || (typeof v === \"number\" && Number.isNaN(v));\nconst real = (v: Value): boolean => (typeof v === \"number\" && !Number.isNaN(v)) || typeof v === \"bigint\";\n\n/** Port of `sdvplot._tiers.prepare`: validate the rows and compute everything a tier plot draws. */\nexport function prepareTiers(rows: readonly TierRow[], league: League, o: TiersOptions = {}): Tiers {\n const theme = o.theme ?? \"dark\";\n if (!Object.hasOwn(TIER_THEMES, theme))\n throw new InputError(`theme must be \"dark\" or \"light\", got ${String(theme)}`);\n const height = o.height === undefined ? DEFAULT_HEIGHT : checkHeight(o.height);\n const alpha = checkAlpha(o.alpha ?? 0.8);\n const tiers = rows.map((r): Value => r.tierNo ?? r.tier_no);\n const teams = rows.map((r) => r.team);\n const ranksIn = rows.map((r): Value => r.tierRank ?? r.tier_rank);\n const given = !o.presort && ranksIn.some((v) => v !== undefined) ? ranksIn : undefined;\n\n const all = rows.map((_, i) => i);\n const absent = all.filter((i) => miss(tiers[i]) || (given !== undefined && miss(given[i])));\n if (absent.length) {\n const names = absent.map((i) => String(teams[i]));\n const extra = names.length > 10 ? ` and ${names.length - 10} more` : \"\";\n const shown = `${names.slice(0, 10).join(\", \")}${extra}`;\n warn(\n `tiers:${league}:missing:${shown}`,\n `skipped ${names.length} point(s) with a missing tier_no or tier_rank: ${shown}`,\n );\n }\n let idx = all.filter((i) => !absent.includes(i));\n if (!idx.length) throw new InputError(\"data has no rows with a tier_no\");\n if (!idx.every((i) => real(tiers[i]) && (given === undefined || real(given[i]))))\n throw new InputError(\"tier_no and tier_rank must hold numbers (tier 1 is the top tier)\");\n const tierOf = (i: number): number => Number(tiers[i]);\n if (o.presort) {\n // arrange(tier_no, team), then rank within the tier; a missing team last, as R's NA\n const name = (i: number): string => String(teams[i]);\n const cp = (i: number): number[] => Array.from(name(i), (c) => c.codePointAt(0) as number);\n const cmp = (a: number[], b: number[]): number => {\n for (let k = 0; k < Math.min(a.length, b.length); k++)\n if (a[k] !== b[k]) return (a[k] as number) - (b[k] as number);\n return a.length - b.length;\n };\n idx = idx.sort(\n (a, b) => tierOf(a) - tierOf(b) || Number(miss(teams[a])) - Number(miss(teams[b])) || cmp(cp(a), cp(b)),\n );\n }\n const ranks = new Map<number, number>();\n const seen = new Map<number, number>();\n for (const i of idx) {\n if (given) ranks.set(i, Number(given[i]));\n else {\n const t = tierOf(i);\n const n = (seen.get(t) ?? 0) + 1;\n seen.set(t, n);\n ranks.set(i, n);\n }\n }\n\n // Rank first, then resolve: an unknown team keeps its slot (and the x range) but draws nothing.\n const ids = resolveSync(\n idx.map((i) => teams[i]),\n league,\n );\n const kept = idx.flatMap((i, k) => {\n const id = ids[k];\n return id === undefined ? [] : [[i, id] as const];\n });\n const abbr = new Map(getLeagueSync(league).teams.map((t) => [t.team_id, t.abbr]));\n const levels = [...new Set(idx.map(tierOf))].sort((a, b) => a - b);\n const skip = new Set<number>(\n o.noLineBelowTier === undefined\n ? []\n : typeof o.noLineBelowTier === \"number\"\n ? [o.noLineBelowTier]\n : o.noLineBelowTier,\n );\n const desc = o.tierDesc ?? TIER_DESC;\n const rs = [...ranks.values()];\n const lo = Math.min(...rs);\n const hi = Math.max(...rs);\n const pad = lo === hi ? 0.5 : 0.05 * (hi - lo);\n const first = levels[0] as number;\n const last = levels[levels.length - 1] as number;\n return {\n x: kept.map(([i]) => ranks.get(i) as number),\n y: kept.map(([i]) => tierOf(i)),\n teamIds: kept.map(([, id]) => id),\n labels: kept.map(([i, id]) => abbr.get(id) || String(teams[i])),\n lines: [first - 0.5, ...levels.filter((t) => !skip.has(t)).map((t) => t + 0.5)],\n breaks: levels,\n breakLabels: levels.map((t) => wrapLabel(desc[t] ?? \"\")),\n xlim: [lo - pad, hi + pad],\n ylim: [first - 0.6, last + 0.6],\n title: o.title === undefined ? `${league.toUpperCase()} Team Tiers` : (o.title ?? \"\"),\n subtitle: o.subtitle === undefined ? TIERS_SUBTITLE : o.subtitle,\n caption: o.caption ?? null,\n height,\n alpha,\n variant: (o.variant ?? \"auto\") === \"auto\" ? AUTO_VARIANT[theme] : (o.variant as Variant),\n theme: TIER_THEMES[theme],\n };\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { contentId } from './chunk-WQT4IVLX.js';
|
|
1
2
|
import { binner } from './chunk-C2CDY5OG.js';
|
|
2
3
|
import { InputError } from './chunk-E7G7VSLV.js';
|
|
3
4
|
import { BASKETBALL_ZONES, basketballZoneOf } from '@sportsdataverse/sporty';
|
|
@@ -197,13 +198,6 @@ function diffScale(o = {}) {
|
|
|
197
198
|
return Object.assign(scale, { plot, stops });
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
// src/content-id.ts
|
|
201
|
-
function contentId(prefix, text) {
|
|
202
|
-
let h = 2166136261;
|
|
203
|
-
for (let i = 0; i < text.length; i++) h = Math.imul(h ^ text.charCodeAt(i), 16777619);
|
|
204
|
-
return `${prefix}-${(h >>> 0).toString(36)}`;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
201
|
// src/shots/signature.ts
|
|
208
202
|
function kernelSmooth(values, weights, sigma) {
|
|
209
203
|
if (sigma === 0) return [...values];
|
|
@@ -301,6 +295,6 @@ function signatureGradient(points, fill) {
|
|
|
301
295
|
};
|
|
302
296
|
}
|
|
303
297
|
|
|
304
|
-
export { LEAGUE_PRIOR_ATTEMPTS, SIGNATURE_NAME, binShots, cellsVsLeague,
|
|
305
|
-
//# sourceMappingURL=chunk-
|
|
306
|
-
//# sourceMappingURL=chunk-
|
|
298
|
+
export { LEAGUE_PRIOR_ATTEMPTS, SIGNATURE_NAME, binShots, cellsVsLeague, diffScale, leagueIndex, made, shrunkDiff, signatureGradient, signaturePoints, sizeCells, split, statsByZone };
|
|
299
|
+
//# sourceMappingURL=chunk-H2C3FMMA.js.map
|
|
300
|
+
//# sourceMappingURL=chunk-H2C3FMMA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shots/aggregate.ts","../src/shots/diff.ts","../src/shots/signature.ts"],"names":["R","lerp"],"mappings":"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","file":"chunk-H2C3FMMA.js","sourcesContent":["// Cell aggregations, ported from blazing-the-nets `main` lib/data/aggregate.ts (@31427b8). Pure; the parity gate\n// is fixtures/shots/oracle.json (hexagons). Squares (J38) run the same code on `squarebin`'s lattice.\nimport { BASKETBALL_ZONES, type BasketballZone, basketballZoneOf } from \"@sportsdataverse/sporty\";\nimport { type Binner, type BinnerOptions, type Lattice, binner } from \"../bins/index.js\";\n\n/** A number is a hexagon radius (the parity default); an object is any lattice, squares included (J38). */\nconst latticeOf = (cell: number | BinnerOptions): Binner =>\n binner(typeof cell === \"number\" ? { radius: cell } : cell);\n\n/**\n * One field-goal attempt, as the `nba_stats_shots` release ships it: `x_legacy`/`y_legacy` in tenths of a foot,\n * hoop at the origin, y toward half court; `shot_distance` in ROUNDED feet. Map other schemas once, first.\n */\nexport interface ShotRow {\n readonly x_legacy: number;\n readonly y_legacy: number;\n readonly shot_distance: number;\n /** 2 or 3; zones read it (the scorer's call, not the coordinates). */\n readonly shot_value: number;\n /** `\"Made\"` or `\"Missed\"`. */\n readonly shot_result: string;\n}\n\n/** Attempts, makes and FG% (`makes / attempts`, null with no attempts): the counts every shot aggregate carries. */\nexport interface Split {\n readonly attempts: number;\n readonly makes: number;\n readonly fgPct: number | null;\n}\n\n/** @internal */\nexport const made = (s: ShotRow): boolean => s.shot_result === \"Made\"; // aggregate.ts:14\n/** @internal */\nexport const split = (attempts: number, makes: number): Split => ({\n attempts,\n makes,\n fgPct: attempts > 0 ? makes / attempts : null,\n}); // aggregate.ts:16-18\n\n/** The shot's zone (sporty, legacy tenths). */\nexport const shotZone = (s: ShotRow): BasketballZone =>\n basketballZoneOf(s.x_legacy, s.y_legacy, s.shot_value, { scale: 10 });\n\n/**\n * Inside the sidelines and in front of the baseline (aggregate.ts:81-84); releases carry a few impossible points.\n * Also finite: `main` lets `y_legacy = Infinity` through. x's bound already rejects NaN and ±Infinity.\n */\nconst onCourt = (s: ShotRow): boolean =>\n Math.abs(s.x_legacy) <= 250 && s.y_legacy >= -52.5 && Number.isFinite(s.y_legacy);\n\n/** One cell of `binShots`: its centre, counts, mean shot distance and majority zone. */\nexport interface CellBin extends Split {\n /** Cell centre, legacy tenths. */\n readonly x: number;\n readonly y: number;\n readonly meanDistance: number;\n /** The zone most of the cell's attempts fall in (first seen wins a tie). */\n readonly zone: BasketballZone;\n}\n\n/**\n * Bin shots in DATA space (legacy tenths), dropping off-court points (aggregate.ts:86-104) and points with a\n * non-finite coordinate (`main` lets `y_legacy = Infinity` through). `cell` is a hexagon\n * radius (10 = a 1 ft hex) or any `binner` lattice, e.g. `{ shape: \"square\", side: 15 }`. Bins come out in\n * first-seen order (d3-hexbin's, for hexagons).\n *\n * @example\n * ```ts\n * import { binShots } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn shots from the sportsdataverse-data nba_stats_shots release, 2025-26\n * const shots = [\n * { x_legacy: -1, y_legacy: 7, shot_distance: 1, shot_value: 2, shot_result: \"Made\" },\n * { x_legacy: 0, y_legacy: 0, shot_distance: 0, shot_value: 2, shot_result: \"Missed\" },\n * { x_legacy: -44, y_legacy: 252, shot_distance: 26, shot_value: 3, shot_result: \"Made\" },\n * ];\n * binShots(shots, 15);\n * binShots(shots, { shape: \"square\", side: 15 });\n * ```\n */\nexport function binShots(shots: readonly ShotRow[], cell: number | BinnerOptions): CellBin[] {\n const bins = latticeOf(cell).bins(shots.filter(onCourt), {\n x: (s) => s.x_legacy,\n y: (s) => s.y_legacy,\n });\n return bins.map((b) => {\n let distance = 0;\n let makes = 0;\n const zones = new Map<BasketballZone, number>();\n for (const s of b) {\n distance += s.shot_distance;\n if (made(s)) makes += 1;\n const z = shotZone(s);\n zones.set(z, (zones.get(z) ?? 0) + 1);\n }\n let zone: BasketballZone = \"mid_range\";\n let most = -1;\n for (const [z, n] of zones) {\n if (n > most) {\n zone = z;\n most = n;\n }\n }\n return { x: b.x, y: b.y, ...split(b.length, makes), meanDistance: distance / b.length, zone };\n });\n}\n\n/**\n * League attempts behind a cell's league rate before it falls back to the zone, and the colour prior: one number for\n * both (aggregate.ts:106-110). It is blazing-the-nets' tunable, set in its commit 25c3ab9f (\"shrunk colours\"), not a\n * derived or measured constant; `cellsVsLeague`'s `minLeague`, `shrunkDiff`'s `k` and `signaturePoints`' `prior`\n * override it per call.\n */\nexport const LEAGUE_PRIOR_ATTEMPTS = 25;\n\n/**\n * FG% minus the league rate `league`, shrunk toward it by a `k`-attempt prior: `(makes + k*L)/(attempts + k) - L`\n * (aggregate.ts:112-119). `k = 0` is the raw difference (blazing-the-nets `master`). For colour, not labels.\n *\n * @example\n * ```ts\n * import { LEAGUE_PRIOR_ATTEMPTS, shrunkDiff } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn 2025-26, the radius-15 hexagon centred (77.9, 45): 4 of 4, where the league made 270 of 636\n * shrunkDiff(4, 4, 270 / 636, LEAGUE_PRIOR_ATTEMPTS); // +0.08, not the raw +0.58\n * ```\n */\nexport function shrunkDiff(\n makes: number,\n attempts: number,\n league: number,\n k: number = LEAGUE_PRIOR_ATTEMPTS,\n): number {\n return (makes + k * league) / (attempts + k) - league;\n}\n\n/** One league cell in a `LeagueIndex`: centre (legacy tenths), attempts and FG%. */\nexport interface LeagueCell {\n readonly x: number;\n readonly y: number;\n readonly attempts: number;\n readonly fgPct: number | null;\n}\n/**\n * A season's league cells and zone rates on one lattice (`{ radius }` for hexagons, `{ shape: \"square\", side }`):\n * plain JSON, computed once (aggregate.ts:125-146). blazing-the-nets names the cells `hexes`; here they are `cells`\n * for either shape, so map that key when loading its JSON.\n */\nexport type LeagueIndex = Lattice & {\n readonly cells: readonly LeagueCell[];\n readonly zones: Readonly<Record<BasketballZone, Split>>;\n};\n/** A player cell with the league FG% it is compared to (`cellsVsLeague`, `cellsVsDistance`); null with no league figure. */\nexport interface CellVsLeague extends CellBin {\n readonly leagueFgPct: number | null;\n}\n\n/**\n * The league index every player chart compares against (aggregate.ts:140-146), on a hexagon radius or any `binner`\n * lattice; it stores the resolved lattice, so `equalArea` becomes the square's `side`.\n *\n * @example\n * ```ts\n * import { leagueIndex } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn shots from the sportsdataverse-data nba_stats_shots release, 2025-26\n * const shots = [\n * { x_legacy: -1, y_legacy: 7, shot_distance: 1, shot_value: 2, shot_result: \"Made\" },\n * { x_legacy: 0, y_legacy: 0, shot_distance: 0, shot_value: 2, shot_result: \"Missed\" },\n * { x_legacy: -44, y_legacy: 252, shot_distance: 26, shot_value: 3, shot_result: \"Made\" },\n * ];\n * leagueIndex(shots, 15).cells;\n * ```\n */\nexport function leagueIndex(league: readonly ShotRow[], cell: number | BinnerOptions): LeagueIndex {\n const { lattice } = latticeOf(cell);\n return {\n ...lattice,\n cells: binShots(league, lattice).map(({ x, y, attempts, fgPct }) => ({ x, y, attempts, fgPct })),\n zones: statsByZone(league),\n };\n}\n\nconst centres = new WeakMap<LeagueIndex, Map<string, LeagueCell>>();\n/**\n * Player cells with the league FG% of the SAME cell (the player is binned on the index's own lattice, so the\n * centres are equal); a cell the league shot fewer than `minLeague` times from falls back to its zone's league rate\n * (aggregate.ts:155-165; blazing-the-nets `main`).\n *\n * @example\n * ```ts\n * import { cellsVsLeague, leagueIndex } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn shots from the sportsdataverse-data nba_stats_shots release, 2025-26\n * const made = { x_legacy: 0, y_legacy: 0, shot_distance: 0, shot_value: 2, shot_result: \"Made\" };\n * const missed = { ...made, shot_result: \"Missed\" };\n * cellsVsLeague([made], leagueIndex([made, missed], 15));\n * ```\n */\nexport function cellsVsLeague(\n player: readonly ShotRow[],\n league: LeagueIndex,\n minLeague: number = LEAGUE_PRIOR_ATTEMPTS,\n): CellVsLeague[] {\n let byCentre = centres.get(league);\n if (byCentre === undefined) {\n byCentre = new Map(league.cells.map((h) => [`${h.x},${h.y}`, h]));\n centres.set(league, byCentre);\n }\n const index = byCentre;\n return binShots(player, league).map((h) => {\n const l = index.get(`${h.x},${h.y}`);\n return { ...h, leagueFgPct: l && l.attempts >= minLeague ? l.fgPct : league.zones[h.zone].fgPct };\n });\n}\n\n/** How a cell's attempts set its size: `main` (sqrt to the 95th percentile) or `master` (linear, capped). */\nexport type SizeRule = \"sqrt-p95\" | \"linear-cap\";\n/** `sizeCells`' result: each cell's size, the cap, the size of any count, and the counts for a size key. */\nexport interface CellSizes {\n /** Size per cell in legacy tenths: a hexagon's circumradius, or a square's side. 0 hides a cell. */\n readonly r: readonly number[];\n /** Attempts at which size saturates. */\n readonly cap: number;\n /** The size of any attempt count, for a size key. */\n readonly size: (attempts: number) => number;\n /** A size key: 1, half the cap, the cap (blazing-the-nets `main` `lib/charts/hexShotChart.ts:199`). */\n readonly steps: readonly number[];\n}\n\n/** d3-array 3.2.4 `quantile` (src/quantile.js:10-20, R-7) over finite values; undefined when there are none. */\nfunction quantile(values: readonly number[], p: number): number | undefined {\n const v = values.filter((x) => x != null && !Number.isNaN(x)).sort((a, b) => a - b);\n const n = v.length;\n if (n === 0) return undefined;\n if (p <= 0 || n < 2) return v[0];\n if (p >= 1) return v[n - 1];\n const i = (n - 1) * p;\n const i0 = Math.floor(i);\n const v0 = v[i0] as number;\n const v1 = v[i0 + 1] as number;\n return v0 + (v1 - v0) * (i - i0);\n}\n\n/**\n * Frequency size for each cell (the dual encoding's size half; colour is `diffScale`), on the lattice's full cell\n * size `R` (a hexagon's radius, or a square's side; pass the index itself: `sizeCells(cells, index)`).\n * `\"sqrt-p95\"` (default, `main` `hexShotChart.ts:65-81`): a sqrt scale of attempts to `R`, capped at the 95th\n * percentile so one busy rim cell does not shrink the rest; area follows attempts for either shape.\n * `\"linear-cap\"` (`master` `Hexagon/index.js:22-30`): attempts in tenths, capped at `R`, cells under 2 attempts\n * hidden.\n *\n * @example\n * ```ts\n * import { binShots, sizeCells } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn shots from the sportsdataverse-data nba_stats_shots release, 2025-26\n * const shots = [\n * { x_legacy: -1, y_legacy: 7, shot_distance: 1, shot_value: 2, shot_result: \"Made\" },\n * { x_legacy: 0, y_legacy: 0, shot_distance: 0, shot_value: 2, shot_result: \"Missed\" },\n * { x_legacy: -44, y_legacy: 252, shot_distance: 26, shot_value: 3, shot_result: \"Made\" },\n * ];\n * sizeCells(binShots(shots, 15), { radius: 15 }).r; // the 2-attempt rim cell is full size, the 1-attempt three smaller\n * ```\n */\nexport function sizeCells(\n cells: readonly { readonly attempts: number }[],\n o: BinnerOptions & { readonly rule?: SizeRule },\n): CellSizes {\n const R = binner(o).size; // throws InputError on a size that is not a finite number > 0\n let cap: number;\n let size: (a: number) => number;\n if ((o.rule ?? \"sqrt-p95\") === \"sqrt-p95\") {\n cap = Math.max(\n 2,\n Math.ceil(\n quantile(\n cells.map((h) => h.attempts),\n 0.95,\n ) ?? 2,\n ),\n );\n const top = Math.sqrt(cap);\n size = (a) => R * Math.min(1, Math.max(0, Math.sqrt(Math.max(0, a)) / top));\n } else {\n cap = R;\n size = (a) => (a > R ? R : a < 2 ? 0 : a);\n }\n return {\n r: cells.map((h) => size(h.attempts)),\n cap,\n size,\n steps: [1, Math.max(2, Math.round(cap / 2)), cap],\n };\n}\n\n/**\n * Attempts, makes and FG% per zone (aggregate.ts:269-277).\n *\n * @example\n * ```ts\n * import { statsByZone } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // a Brooklyn corner three, 2025-26 (sportsdataverse-data nba_stats_shots)\n * statsByZone([{ x_legacy: 237, y_legacy: 34, shot_distance: 24, shot_value: 3, shot_result: \"Made\" }]);\n * ```\n */\nexport function statsByZone(shots: readonly ShotRow[]): Record<BasketballZone, Split> {\n const acc = new Map<BasketballZone, [number, number]>(BASKETBALL_ZONES.map((z) => [z, [0, 0]]));\n for (const s of shots) {\n const z = acc.get(shotZone(s));\n if (z === undefined) continue;\n z[0] += 1;\n if (made(s)) z[1] += 1;\n }\n return Object.fromEntries(\n BASKETBALL_ZONES.map((z) => {\n const [a, m] = acc.get(z) ?? [0, 0];\n return [z, split(a, m)];\n }),\n ) as Record<BasketballZone, Split>;\n}\n","// diffScale reproduces blazing-the-nets' diff colours with no d3 at runtime. \"rdbu\" = main lib/charts/theme.ts:47-64;\n// \"master\" = master src/components/HexShotchart/index.js:57-64. The RdBu ramp ports d3-scale-chromatic 3.1.0\n// src/diverging/RdBu.js:13 + src/ramp.js:3 and d3-interpolate 3.0.1 src/basis.js:1-19 + src/rgb.js:28-52 (ISC,\n// Mike Bostock; notice in NOTICE.md). Strings match d3-color's `rgb(r, g, b)` exactly.\nimport { InputError } from \"../errors.js\";\n\ntype Rgb = readonly [number, number, number];\nconst hex = (s: string): Rgb => [\n Number.parseInt(s.slice(0, 2), 16),\n Number.parseInt(s.slice(2, 4), 16),\n Number.parseInt(s.slice(4, 6), 16),\n];\nconst RDBU: readonly Rgb[] = (\n \"67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061\".match(/.{6}/g) ?? []\n).map(hex);\nconst MASTER: readonly Rgb[] = [\"8d0801\", \"bf0603\", \"f4d58d\", \"708d81\", \"195943\"].map(hex);\nconst MASTER_DOMAIN = [-0.99, -0.15, 0, 0.15, 0.99] as const;\nconst DARK_NEUTRAL: Rgb = [0x30, 0x30, 0x30]; // theme.ts:54\n\n/** d3-color's formatter: each channel rounded and clamped to 0-255. */\nconst clampi = (v: number): number => Math.max(0, Math.min(255, Math.round(v) || 0));\nconst fmt = (c: Rgb): string => `rgb(${clampi(c[0])}, ${clampi(c[1])}, ${clampi(c[2])})`;\n\nfunction basis(t1: number, v0: number, v1: number, v2: number, v3: number): number {\n const t2 = t1 * t1;\n const t3 = t2 * t1;\n return (\n ((1 - 3 * t1 + 3 * t2 - t3) * v0 +\n (4 - 6 * t2 + 3 * t3) * v1 +\n (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2 +\n t3 * v3) /\n 6\n );\n}\nfunction spline(values: readonly number[], tIn: number): number {\n const n = values.length - 1;\n let t = tIn;\n let i: number;\n if (t <= 0) {\n t = 0;\n i = 0;\n } else if (t >= 1) {\n t = 1;\n i = n - 1;\n } else i = Math.floor(t * n);\n const v1 = values[i] as number;\n const v2 = values[i + 1] as number;\n const v0 = i > 0 ? (values[i - 1] as number) : 2 * v1 - v2;\n const v3 = i < n - 1 ? (values[i + 2] as number) : 2 * v2 - v1;\n return basis((t - i / n) * n, v0, v1, v2, v3);\n}\nconst channel = (k: 0 | 1 | 2): number[] => RDBU.map((c) => c[k]);\nconst R = channel(0);\nconst G = channel(1);\nconst B = channel(2);\n/** d3.interpolateRdBu(t), unrounded. */\nconst rdbu = (t: number): Rgb => [spline(R, t), spline(G, t), spline(B, t)];\n/** d3.interpolateRgb(a, b)(t). */\nconst lerp = (a: Rgb, b: Rgb, t: number): Rgb => [\n a[0] + t * (b[0] - a[0]),\n a[1] + t * (b[1] - a[1]),\n a[2] + t * (b[2] - a[2]),\n];\n/** A d3 piecewise scaleLinear over colours: bisectRight segment, unclamped t unless the input was clamped. */\nfunction piecewise(domain: readonly number[], range: readonly Rgb[], x: number): Rgb {\n let i = 1;\n while (i < domain.length - 1 && (domain[i] as number) <= x) i++;\n const a = domain[i - 1] as number;\n const b = domain[i] as number;\n return lerp(range[i - 1] as Rgb, range[i] as Rgb, (x - a) / (b - a));\n}\n\n/** The diff colours: `\"rdbu\"` (blazing-the-nets `main`, the default) or `\"master\"` (its 2021 five stops). */\nexport type DiffPalette = \"rdbu\" | \"master\";\n/** Options for `diffScale`. */\nexport interface DiffScaleOptions {\n /**\n * `\"rdbu\"` (default): RdBu reversed, above league red (blazing-the-nets `main`), clamped at `±domain`.\n * `\"master\"`: the 2021 five-stop red-yellow-green, UNCLAMPED like master's d3 `scaleLinear`: a diff past the end\n * stops (±0.99) extrapolates, each channel then clamped to 0-255. An infinite diff takes the end colour (d3 gives\n * `rgb(0, 0, 0)` for `Infinity` and `rgb(0, 255, 0)` for `-Infinity`).\n */\n palette?: DiffPalette;\n /** `\"dark\"` swaps RdBu's near-white centre for `#303030` so an average mark recedes (`theme.ts:52-58`). Ignored by `\"master\"`. */\n theme?: \"light\" | \"dark\";\n /** Saturation in FG% fraction, finite and above 0 (else InputError); default 0.15 (`theme.ts:29`). `\"master\"` keeps its own stops. */\n domain?: number;\n /** Colour for `null` (no league figure); default `var(--sdv-muted, #525252)`. */\n nullColor?: string;\n}\n/** A diff colour function plus the equivalent Plot colour-scale options (for fills and `Plot.legend`). */\nexport interface DiffScale {\n (diff: number | null): string;\n /** Diffs to place gradient stops at: 5 across [-D, D] (`theme.ts:127-130`), or `master`'s own 5 stops. */\n readonly stops: readonly number[];\n readonly plot: {\n readonly type: \"diverging\" | \"linear\";\n readonly domain: readonly number[];\n readonly range?: readonly string[];\n readonly scheme?: \"RdBu\";\n readonly reverse?: boolean;\n readonly pivot?: number;\n readonly interpolate?: \"rgb\";\n readonly clamp: boolean;\n };\n}\n\n/**\n * The FG%-vs-league colour: `diffScale()(0.05)`. Light RdBu, dark RdBu, or `master`'s palette; `null` is\n * `nullColor`. `.plot` is the same scale as Observable Plot `color` options, so `Plot.legend({ color: s.plot })`\n * draws the matching key.\n *\n * @example\n * ```ts\n * import { diffScale } from \"@sportsdataverse/sdvplot/shots\";\n *\n * diffScale({ theme: \"dark\" })(0.05);\n * ```\n */\nexport function diffScale(o: DiffScaleOptions = {}): DiffScale {\n const palette = o.palette ?? \"rdbu\";\n const D = o.domain ?? 0.15;\n if (!(Number.isFinite(D) && D > 0))\n throw new InputError(`diffScale domain must be a finite number > 0, got ${String(D)}`);\n const nullColor = o.nullColor ?? \"var(--sdv-muted, #525252)\";\n let colour: (d: number) => string;\n let plot: DiffScale[\"plot\"];\n let stops: readonly number[] = [0, 0.25, 0.5, 0.75, 1].map((t) => (t * 2 - 1) * D);\n if (palette === \"master\") {\n const range = MASTER.map(fmt);\n // Deliberate divergence from d3: ±Infinity takes the end colour, where d3 gives black (+) or green (-).\n colour = (d) =>\n Number.isFinite(d)\n ? fmt(piecewise(MASTER_DOMAIN, MASTER, d))\n : (range[d > 0 ? range.length - 1 : 0] as string);\n plot = { type: \"linear\", domain: MASTER_DOMAIN, range, interpolate: \"rgb\", clamp: false };\n stops = MASTER_DOMAIN;\n } else if (o.theme === \"dark\") {\n // theme.ts:55-58: the ends are d3's ROUNDED rgb() strings, re-parsed, so round before interpolating.\n const ends: readonly Rgb[] = [rdbu(0.85), DARK_NEUTRAL, rdbu(0.15)].map(\n (c): Rgb => [clampi(c[0]), clampi(c[1]), clampi(c[2])],\n );\n const domain = [-D, 0, D];\n colour = (d) => fmt(piecewise(domain, ends, Math.max(-D, Math.min(D, d))));\n plot = { type: \"linear\", domain, range: ends.map(fmt), interpolate: \"rgb\", clamp: true };\n } else {\n // theme.ts:49-51: scaleDiverging(t => interpolateRdBu(1 - t)).domain([-D, 0, D]).clamp(true).\n const k = 0.5 / D;\n colour = (d) => fmt(rdbu(1 - Math.max(0, Math.min(1, 0.5 + d * k))));\n plot = { type: \"diverging\", scheme: \"RdBu\", reverse: true, domain: [-D, D], pivot: 0, clamp: true };\n }\n const scale = (diff: number | null): string =>\n diff === null || Number.isNaN(diff) ? nullColor : colour(diff);\n return Object.assign(scale, { plot, stops });\n}\n","// signaturePoints ports blazing-the-nets `main` lib/charts/shootingSignature.ts:13-100 (@31427b8).\nimport { contentId } from \"../content-id.js\";\nimport { InputError } from \"../errors.js\";\nimport { LEAGUE_PRIOR_ATTEMPTS, shrunkDiff } from \"./aggregate.js\";\nimport type { DistanceVsLeague } from \"./distance.js\";\n\n/** Gaussian kernel smoothing (`:27-39`); with `weights`, a weighted local mean. `sigma` 0 = no smoothing. */\nexport function kernelSmooth(\n values: readonly number[],\n weights: readonly number[] | null,\n sigma: number,\n): number[] {\n if (sigma === 0) return [...values];\n const reach = Math.ceil(sigma * 3);\n return values.map((_, i) => {\n let num = 0;\n let den = 0;\n for (let j = Math.max(0, i - reach); j <= Math.min(values.length - 1, i + reach); j++) {\n const k = Math.exp(-((i - j) ** 2) / (2 * sigma * sigma)) * (weights ? (weights[j] ?? 0) : 1);\n num += k * (values[j] ?? 0);\n den += k;\n }\n return den > 0 ? num / den : 0;\n });\n}\n\n/** Gaussian kernel sums, weight 1 at the bin itself (`:42-51`): effective makes or attempts near each bin. */\nexport function kernelSum(values: readonly number[], sigma: number): number[] {\n if (sigma === 0) return [...values];\n const reach = Math.ceil(sigma * 3);\n return values.map((_, i) => {\n let sum = 0;\n for (let j = Math.max(0, i - reach); j <= Math.min(values.length - 1, i + reach); j++) {\n sum += Math.exp(-((i - j) ** 2) / (2 * sigma * sigma)) * (values[j] ?? 0);\n }\n return sum;\n });\n}\n\n/** One shooting-signature sample (`signaturePoints`): the input of the Plot `shootingSignature` and d3 `appendSignature`. */\nexport interface SignaturePoint {\n readonly distance: number;\n /** Effective makes / attempts near this distance; null (a gap in the ribbon) under `minAttempts`. */\n readonly fgPct: number | null;\n readonly leagueFgPct: number | null;\n readonly share: number;\n /** The colour value: `shrunkDiff(makes, attempts, league, prior)`, null in a gap. */\n readonly colourDiff: number | null;\n}\n\n/** Options for `signaturePoints`; `master` mode is `{ step: 1, smooth: false, minAttempts: 1, prior: 0 }`. */\nexport interface SignatureOptions {\n /** Feet between samples; default 0.25 (`:16`). `master` sampled each 1-ft bin. */\n step?: number;\n /** Kernel smoothing (sigma 0.9 ft for makes/attempts, 1 for share, 0.6 for league; `:17`, `:76-77`); default true. */\n smooth?: boolean;\n /** No ribbon past the last bin with this many attempts, nor where the effective attempts fall below it; default 5 (`:19-21`). */\n minAttempts?: number;\n /** Colour prior in attempts (`shrunkDiff` k); default 25. 0 = the raw difference (`master`). */\n prior?: number;\n}\n\n/**\n * The shooting signature's samples: FG% from separately kernel-summed makes and attempts (a stretch with no\n * shots is a gap, never 0%), the smoothed league FG% and shot share, and the shrunk colour value (`:69-100`).\n * Input: 1-ft bins from `vsLeague(fgPctByDistance(player), fgPctByDistance(league))`.\n *\n * @example\n * ```ts\n * import { fgPctByDistance, signaturePoints, vsLeague } from \"@sportsdataverse/sdvplot/shots\";\n *\n * // Brooklyn shots from the sportsdataverse-data nba_stats_shots release, 2025-26\n * const made = { x_legacy: 0, y_legacy: 0, shot_distance: 0, shot_value: 2, shot_result: \"Made\" };\n * const missed = { ...made, shot_result: \"Missed\" };\n * signaturePoints(vsLeague(fgPctByDistance([made]), fgPctByDistance([made, missed])), { minAttempts: 1 })[0];\n * ```\n */\nexport function signaturePoints(\n bins: readonly DistanceVsLeague[],\n o: SignatureOptions = {},\n): SignaturePoint[] {\n const step = o.step ?? 0.25;\n if (!(step > 0)) throw new InputError(`signaturePoints step must be > 0, got ${String(step)}`);\n const smooth = o.smooth ?? true;\n const min = o.minAttempts ?? 5;\n const prior = o.prior ?? LEAGUE_PRIOR_ATTEMPTS;\n const attempts = kernelSum(\n bins.map((b) => b.attempts),\n smooth ? 0.9 : 0,\n );\n const makes = kernelSum(\n bins.map((b) => b.makes),\n smooth ? 0.9 : 0,\n );\n const share = kernelSmooth(\n bins.map((b) => b.share),\n null,\n smooth ? 1 : 0,\n );\n const league = kernelSmooth(\n bins.map((b) => b.leagueFgPct ?? 0),\n bins.map((b) => (b.leagueFgPct === null ? 0 : 1)),\n smooth ? 0.6 : 0,\n );\n let end: number | null = null; // ribbonEnd (`:54-57`); a loop, not findLast (ES2023, outside the ES2022 lib)\n for (let i = bins.length - 1; i >= 0; i--) {\n const b = bins[i];\n if (b !== undefined && b.attempts >= min) {\n end = b.distance;\n break;\n }\n }\n const last = bins.length - 1;\n const lerp = (a: readonly number[], d: number): number => {\n const i = Math.min(Math.floor(d), last);\n const j = Math.min(i + 1, last);\n const ai = a[i] ?? 0;\n return ai + ((a[j] ?? 0) - ai) * (d - i);\n };\n return Array.from({ length: Math.round(last / step) + 1 }, (_, k) => {\n const d = k * step;\n const a = lerp(attempts, d);\n const m = lerp(makes, d);\n const hasLeague = bins[Math.min(Math.round(d), last)]?.leagueFgPct != null;\n const leagueFgPct = hasLeague ? lerp(league, d) : null;\n const ok = end !== null && d <= end && a >= min;\n return {\n distance: d,\n fgPct: ok ? m / a : null,\n leagueFgPct,\n share: lerp(share, d),\n colourDiff: ok && leagueFgPct !== null ? shrunkDiff(m, a, leagueFgPct, prior) : null,\n };\n });\n}\n\n/**\n * What the Plot and d3 signatures share, so the two cannot drift (`main` `shootingSignature.ts:126-131`, `:183-193`):\n * the busiest drawn share, the last distance, the gradient's stops (drawn samples about half a foot apart, as\n * percentages of [0, maxFt]) and its id for a pixel x range. The stops are thinned by spacing, not by index: `main`'s\n * 0.25-ft samples keep every other one (`:192`), and `master`'s 1-ft samples keep every foot, as master drew them\n * (`ShootingSignature/index.js:52-67`). The gradient is in user space (pixels), so the id hashes that range\n * with the colours: the same signature at two widths never shares one, and two signatures never steal each other's\n * (`master`'s fixed id did, `Gradient.js:10`). Internal: not exported from `sdvplot/shots`.\n */\n/**\n * The signature ribbon's accessible name, shared by the Plot mark and its d3 twin.\n * @internal\n */\nexport const SIGNATURE_NAME = \"shooting signature: FG% by distance against the league\";\n\nexport function signatureGradient(\n points: readonly SignaturePoint[],\n fill: (diff: number | null) => string,\n): {\n readonly maxShare: number;\n readonly maxFt: number;\n readonly stops: readonly (readonly [offset: number, colour: string])[];\n readonly id: (x1: string, x2: string) => string;\n} {\n const drawn = points.filter((p) => p.fgPct !== null);\n const maxFt = points.at(-1)?.distance ?? 0;\n const step = (points[1]?.distance ?? 0) - (points[0]?.distance ?? 0);\n const every = step > 0 ? Math.max(1, Math.round(0.5 / step)) : 1; // 2 for main's 0.25 ft, 1 for master's 1 ft\n const stops = drawn\n .filter((_, i) => i % every === 0)\n .map((p) => [maxFt ? (p.distance / maxFt) * 100 : 0, fill(p.colourDiff)] as const);\n const text = stops.map((s) => s.join(\" \")).join(\";\");\n return {\n maxShare: Math.max(0, ...drawn.map((p) => p.share)) || 1,\n maxFt,\n stops,\n id: (x1, x2) => contentId(\"sdv-signature\", `${x1} ${x2}|${text}`),\n };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { loadLeague, preloadAll, LEAGUES, resolveSync, getLeagueSync, MANIFEST_LAST_MODIFIED, INDEX_VERSION } from './chunk-ZAEQXFJM.js';
|
|
1
2
|
import { hex6, contrast } from './chunk-J6R2LEJ7.js';
|
|
2
|
-
import { loadLeague, preloadAll, LEAGUES, resolveSync, getLeagueSync, MANIFEST_LAST_MODIFIED, INDEX_VERSION } from './chunk-TAXO3VXH.js';
|
|
3
3
|
import { InputError } from './chunk-E7G7VSLV.js';
|
|
4
4
|
|
|
5
5
|
// src/teams.ts
|
|
@@ -163,7 +163,7 @@ async function matchupColors(teamA, teamB, opts) {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
// src/version.ts
|
|
166
|
-
var VERSION = "0.
|
|
166
|
+
var VERSION = "0.2.0";
|
|
167
167
|
|
|
168
168
|
// src/versions.ts
|
|
169
169
|
function versions() {
|
|
@@ -171,5 +171,5 @@ function versions() {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
export { VERSION, matchupColors, matchupColorsSync, rowsFrom, teams, versions };
|
|
174
|
-
//# sourceMappingURL=chunk-
|
|
175
|
-
//# sourceMappingURL=chunk-
|
|
174
|
+
//# sourceMappingURL=chunk-J4P4HDBF.js.map
|
|
175
|
+
//# sourceMappingURL=chunk-J4P4HDBF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/teams.ts","../src/rows.ts","../src/matchup-colors.ts","../src/version.ts","../src/versions.ts"],"names":["x","y"],"mappings":"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","file":"chunk-JJFTD4VB.js","sourcesContent":["import { LEAGUES, type League, type Team } from \"./data/index.js\";\nimport { loadLeague, preloadAll } from \"./index-data.js\";\n\n/** All teams for one league, or every league (in `LEAGUES` order) when omitted. */\nexport async function teams(league?: League): Promise<readonly Team[]> {\n if (league) return (await loadLeague(league)).teams;\n await preloadAll();\n return (await Promise.all(LEAGUES.map(loadLeague))).flatMap((d) => d.teams);\n}\n","import { InputError } from \"./errors.js\";\n\n/** Column form → `Row[]` (flat objects, one per index). Columns must be equal length; `{}` → `[]`. */\nexport function rowsFrom(columns: Record<string, readonly unknown[]>): Record<string, unknown>[] {\n const keys = Object.keys(columns);\n const n = keys.length ? (columns[keys[0] as string] as readonly unknown[]).length : 0;\n for (const k of keys) {\n const len = (columns[k] as readonly unknown[]).length;\n if (len !== n) throw new InputError(`rowsFrom: column \"${k}\" has length ${len}, expected ${n}`);\n }\n return Array.from({ length: n }, (_, i) => {\n const row: Record<string, unknown> = {};\n for (const k of keys) row[k] = (columns[k] as readonly unknown[])[i];\n return row;\n });\n}\n","import { contrast, hex6 } from \"./contrast.js\";\nimport { getLeagueSync, loadLeague } from \"./index-data.js\";\nimport { type ResolveOptions, type Value, resolveSync } from \"./resolve.js\";\nimport type { League } from \"./types.js\";\n\n// Port of Game on Paper's game colours (`pickGameColors`, astro/src/utils/misc.ts at b8b8eaad): its Lab\n// conversion, candidate order, thresholds and fallbacks, kept operation for operation so the pairs match\n// its output exactly (fixtures/matchup-colors).\n\nconst MIN_DELTA_E = 20;\nconst MIN_CONTRAST = 2.5;\n/** Game on Paper's page backgrounds (`GAME_BACKGROUNDS`). */\nconst BACKGROUNDS = { light: \"#ffffff\", dark: \"#181a1b\" } as const;\n/** A team with no colour gets Game on Paper's `STANDARD_THEME_COLOR`. */\nconst NO_COLOR = \"#2394fd\";\n\ntype Lab = [number, number, number];\n\n/** CIE L*a*b* (D65) of `#rrggbb`: Game on Paper's `rgb2lab`, with its rounded constants. */\nfunction lab(hex: string): Lab {\n const [r, g, b] = [1, 3, 5].map((i) => {\n const s = Number.parseInt(hex.slice(i, i + 2), 16) / 255;\n return s > 0.04045 ? ((s + 0.055) / 1.055) ** 2.4 : s / 12.92;\n }) as Lab;\n const f = (t: number) => (t > 0.008856 ? t ** (1 / 3) : 7.787 * t + 16 / 116);\n const x = f((r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047);\n const y = f(r * 0.2126 + g * 0.7152 + b * 0.0722);\n const z = f((r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883);\n return [116 * y - 16, 500 * (x - y), 200 * (y - z)];\n}\n\n/** `hex` with its L* set to `L` (a*, b* kept), clamped into sRGB: Game on Paper's `lab2rgb` + `rgbArrayToHex`. */\nfunction withLightness(hex: string, L: number): string {\n const [, A, B] = lab(hex);\n const f = (t: number) => (t ** 3 > 0.008856 ? t ** 3 : (t - 16 / 116) / 7.787);\n const fy = (L + 16) / 116;\n const x = 0.95047 * f(A / 500 + fy);\n const y = f(fy);\n const z = 1.08883 * f(fy - B / 200);\n const lin = [\n x * 3.2406 + y * -1.5372 + z * -0.4986,\n x * -0.9689 + y * 1.8758 + z * 0.0415,\n x * 0.0557 + y * -0.204 + z * 1.057,\n ];\n return `#${lin\n .map((v) => {\n const s = v > 0.0031308 ? 1.055 * v ** (1 / 2.4) - 0.055 : 12.92 * v;\n return Math.round(Math.max(0, Math.min(1, s)) * 255)\n .toString(16)\n .padStart(2, \"0\");\n })\n .join(\"\")}`;\n}\n\n/** CIEDE2000 colour difference between two L*a*b* colours (Sharma, Wu and Dalal 2005). */\nexport function deltaE2000Lab([L1, a1, b1]: Lab, [L2, a2, b2]: Lab): number {\n const rad = Math.PI / 180;\n const Cm = (Math.hypot(a1, b1) + Math.hypot(a2, b2)) / 2;\n const G = 0.5 * (1 - Math.sqrt(Cm ** 7 / (Cm ** 7 + 25 ** 7)));\n const a1p = (1 + G) * a1;\n const a2p = (1 + G) * a2;\n const C1p = Math.hypot(a1p, b1);\n const C2p = Math.hypot(a2p, b2);\n const hue = (ap: number, bp: number) => (ap === 0 && bp === 0 ? 0 : (Math.atan2(bp, ap) / rad + 360) % 360);\n const h1 = hue(a1p, b1);\n const h2 = hue(a2p, b2);\n const dL = L2 - L1;\n const dC = C2p - C1p;\n let dh = 0;\n if (C1p * C2p !== 0)\n dh = Math.abs(h2 - h1) <= 180 ? h2 - h1 : h2 - h1 > 180 ? h2 - h1 - 360 : h2 - h1 + 360;\n const dH = 2 * Math.sqrt(C1p * C2p) * Math.sin((dh * rad) / 2);\n const Lm = (L1 + L2) / 2;\n const Cmp = (C1p + C2p) / 2;\n let Hm = h1 + h2;\n if (C1p * C2p !== 0)\n Hm = Math.abs(h1 - h2) <= 180 ? (h1 + h2) / 2 : h1 + h2 < 360 ? (h1 + h2 + 360) / 2 : (h1 + h2 - 360) / 2;\n const T =\n 1 -\n 0.17 * Math.cos((Hm - 30) * rad) +\n 0.24 * Math.cos(2 * Hm * rad) +\n 0.32 * Math.cos((3 * Hm + 6) * rad) -\n 0.2 * Math.cos((4 * Hm - 63) * rad);\n const dTheta = 30 * Math.exp(-(((Hm - 275) / 25) ** 2));\n const Rc = 2 * Math.sqrt(Cmp ** 7 / (Cmp ** 7 + 25 ** 7));\n const Sl = 1 + (0.015 * (Lm - 50) ** 2) / Math.sqrt(20 + (Lm - 50) ** 2);\n const Sc = 1 + 0.045 * Cmp;\n const Sh = 1 + 0.015 * Cmp * T;\n const Rt = -Math.sin(2 * dTheta * rad) * Rc;\n return Math.sqrt((dL / Sl) ** 2 + (dC / Sc) ** 2 + (dH / Sh) ** 2 + Rt * (dC / Sc) * (dH / Sh));\n}\n\n/** CIEDE2000 between two `#rrggbb` colours, through Game on Paper's Lab conversion. */\nexport function deltaE2000(a: string, b: string): number {\n return deltaE2000Lab(lab(a), lab(b));\n}\n\n/** Game on Paper's `pickPairOn`: the first usable candidate, else L* moved until the pair reads and separates. */\nfunction pickPair(candidates: [string, string][], background: string): [string, string] {\n const readable = (c: string) => contrast(c, background) >= MIN_CONTRAST;\n const apart = (x: string, y: string) => deltaE2000(x, y) >= MIN_DELTA_E;\n // the side with room to read: darker on a light background, lighter on a dark one\n const dir = lab(background)[0] >= 50 ? -1 : 1;\n // nearest L* at which the colour reads on this background\n const readableVariant = (c: string) => {\n if (readable(c)) return c;\n const L0 = lab(c)[0];\n for (let k = 1; k <= 100; k++) {\n const v = withLightness(c, L0 + dir * k);\n if (readable(v)) return v;\n }\n return c;\n };\n\n for (const [x, y] of candidates) if (readable(x) && readable(y) && apart(x, y)) return [x, y];\n const variants = candidates.map(([x, y]): [string, string] => [readableVariant(x), readableVariant(y)]);\n for (const [x, y] of variants) if (apart(x, y)) return [x, y];\n\n // move both colours' L* within the range where each still reads, least total movement first;\n // keep the widest readable separation seen in case nothing clears\n const [x, y] = variants[0] as [string, string];\n const readableShifts = (c: string) => {\n const L0 = lab(c)[0];\n const byShift: string[][] = []; // byShift[|k|] = readable variants moved |k| in L*\n for (let k = -100; k <= 100; k++) {\n if (L0 + k < 0 || L0 + k > 100) continue;\n const v = k === 0 ? c : withLightness(c, L0 + k);\n if (!readable(v)) continue;\n byShift[Math.abs(k)] ??= [];\n byShift[Math.abs(k)]?.push(v);\n }\n return byShift;\n };\n const xs = readableShifts(x);\n const ys = readableShifts(y);\n let best: [string, string] = [x, y];\n let bestDE = deltaE2000(x, y);\n for (let total = 1; total <= 200; total++) {\n for (let i = 0; i <= total; i++) {\n for (const hx of xs[i] ?? [])\n for (const hy of ys[total - i] ?? []) {\n const d = deltaE2000(hx, hy);\n if (d >= MIN_DELTA_E) return [hx, hy];\n if (d > bestDE) {\n best = [hx, hy];\n bestDE = d;\n }\n }\n }\n }\n return best;\n}\n\n/** Options for {@link matchupColors}: the league, how to resolve the two teams, and the backgrounds. */\nexport interface MatchupColorOptions extends ResolveOptions {\n /** The league both teams belong to. */\n league: League;\n /** The background each theme's pair must read on; default `{ light: \"#ffffff\", dark: \"#181a1b\" }` (Game on Paper's pages). */\n theme?: { light?: string; dark?: string };\n}\n/** One `[teamA, teamB]` colour pair per theme, as lowercase `#rrggbb`. */\nexport interface MatchupColors {\n /** The pair for a light background. */\n light: [string, string];\n /** The pair for a dark background. */\n dark: [string, string];\n}\n\n/**\n * {@link matchupColors} once the league is loaded (`loadLeague` or `preloadAll`).\n *\n * @example\n * ```ts\n * import { loadLeague, matchupColorsSync } from \"@sportsdataverse/sdvplot\";\n *\n * await loadLeague(\"cfb\");\n * matchupColorsSync(\"Alabama\", \"Georgia\", { league: \"cfb\" });\n * ```\n */\nexport function matchupColorsSync(teamA: Value, teamB: Value, opts: MatchupColorOptions): MatchupColors {\n const { league, theme, ...resolveOpts } = opts;\n const bg = { light: hex6(theme?.light ?? BACKGROUNDS.light), dark: hex6(theme?.dark ?? BACKGROUNDS.dark) };\n const ids = resolveSync([teamA, teamB], league, resolveOpts);\n const rows = getLeagueSync(league).teams;\n const [a, b] = ids.map((id) => {\n const t = id === undefined ? undefined : rows.find((r) => r.team_id === id);\n const alt = t?.color_secondary ?? null;\n return { primary: t?.color_primary ?? alt ?? NO_COLOR, alt };\n }) as [{ primary: string; alt: string | null }, { primary: string; alt: string | null }];\n // both primaries, teamB's alternate, teamA's alternate, both alternates\n const candidates = [\n [a.primary, b.primary],\n [a.primary, b.alt],\n [a.alt, b.primary],\n [a.alt, b.alt],\n ].filter((p): p is [string, string] => p[0] !== null && p[1] !== null);\n return { light: pickPair(candidates, bg.light), dark: pickPair(candidates, bg.dark) };\n}\n\n/**\n * Two team colours that tell the teams apart on a chart: Game on Paper's \"game colours\" picker.\n *\n * @remarks\n * One pair per theme, each the first candidate whose colours are at least 20 apart in CIEDE2000 and each\n * at least 2.5:1 (WCAG) against that theme's background. Candidates, in order: both primaries, teamB's\n * secondary, teamA's secondary, both secondaries; so a team keeps its primary whenever it works, and teamA\n * (Game on Paper's home team) keeps it first. When no candidate works, an unreadable colour's L* moves just\n * far enough to read; then both colours' L* move, least total movement first, until they separate; failing\n * that, the widest readable separation found. A team with no colour gets `#2394fd`. Deterministic.\n *\n * @example\n * ```ts\n * import { matchupColors } from \"@sportsdataverse/sdvplot\";\n *\n * // two crimson teams; light: [\"#9e1b32\", \"#2c2a29\"] (Georgia's secondary), dark: [\"#ffffff\", \"#ba0c2f\"]\n * // in a page, pick the pair for the theme:\n * // const [alabama, georgia] = window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? dark : light;\n * await matchupColors(\"Alabama\", \"Georgia\", { league: \"cfb\" });\n * ```\n */\nexport async function matchupColors(\n teamA: Value,\n teamB: Value,\n opts: MatchupColorOptions,\n): Promise<MatchupColors> {\n await loadLeague(opts.league);\n return matchupColorsSync(teamA, teamB, opts);\n}\n","// Injected from package.json by tsup/vitest `define`, so changesets version bumps reach versions().\nexport const VERSION: string = __SDVPLOT_VERSION__;\n","import { INDEX_VERSION, MANIFEST_LAST_MODIFIED } from \"./data/index.js\";\nimport { VERSION } from \"./version.js\";\n\nexport function versions(): { sdvplot: string; index: string; manifestLastModified: string } {\n return { sdvplot: VERSION, index: INDEX_VERSION, manifestLastModified: MANIFEST_LAST_MODIFIED };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/teams.ts","../src/rows.ts","../src/matchup-colors.ts","../src/version.ts","../src/versions.ts"],"names":["x","y"],"mappings":";;;;;AAIA,eAAsB,MAAM,MAAA,EAA2C;AACrE,EAAA,IAAI,MAAA,EAAQ,OAAA,CAAQ,MAAM,UAAA,CAAW,MAAM,CAAA,EAAG,KAAA;AAC9C,EAAA,MAAM,UAAA,EAAW;AACjB,EAAA,OAAA,CAAQ,MAAM,OAAA,CAAQ,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAC,CAAA,EAAG,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAA;AAC5E;;;ACLO,SAAS,SAAS,OAAA,EAAwE;AAC/F,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAChC,EAAA,MAAM,CAAA,GAAI,KAAK,MAAA,GAAU,OAAA,CAAQ,KAAK,CAAC,CAAW,EAAyB,MAAA,GAAS,CAAA;AACpF,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AACpB,IAAA,MAAM,GAAA,GAAO,OAAA,CAAQ,CAAC,CAAA,CAAyB,MAAA;AAC/C,IAAA,IAAI,GAAA,KAAQ,CAAA,EAAG,MAAM,IAAI,UAAA,CAAW,CAAA,kBAAA,EAAqB,CAAC,CAAA,aAAA,EAAgB,GAAG,CAAA,WAAA,EAAc,CAAC,CAAA,CAAE,CAAA;AAAA,EAChG;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,GAAE,EAAG,CAAC,GAAG,CAAA,KAAM;AACzC,IAAA,MAAM,MAA+B,EAAC;AACtC,IAAA,KAAA,MAAW,CAAA,IAAK,MAAM,GAAA,CAAI,CAAC,IAAK,OAAA,CAAQ,CAAC,EAAyB,CAAC,CAAA;AACnE,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AACH;;;ACNA,IAAM,WAAA,GAAc,EAAA;AACpB,IAAM,YAAA,GAAe,GAAA;AAErB,IAAM,WAAA,GAAc,EAAE,KAAA,EAAO,SAAA,EAAW,MAAM,SAAA,EAAU;AAExD,IAAM,QAAA,GAAW,SAAA;AAKjB,SAAS,IAAI,GAAA,EAAkB;AAC7B,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM;AACrC,IAAA,MAAM,CAAA,GAAI,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA,GAAI,GAAA;AACrD,IAAA,OAAO,IAAI,OAAA,GAAA,CAAA,CAAY,CAAA,GAAI,KAAA,IAAS,KAAA,KAAU,MAAM,CAAA,GAAI,KAAA;AAAA,EAC1D,CAAC,CAAA;AACD,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,KAAe,CAAA,GAAI,OAAA,GAAW,MAAM,CAAA,GAAI,CAAA,CAAA,GAAK,KAAA,GAAQ,CAAA,GAAI,EAAA,GAAK,GAAA;AACzE,EAAA,MAAM,CAAA,GAAI,GAAG,CAAA,GAAI,MAAA,GAAS,IAAI,MAAA,GAAS,CAAA,GAAI,UAAU,OAAO,CAAA;AAC5D,EAAA,MAAM,IAAI,CAAA,CAAE,CAAA,GAAI,SAAS,CAAA,GAAI,MAAA,GAAS,IAAI,MAAM,CAAA;AAChD,EAAA,MAAM,CAAA,GAAI,GAAG,CAAA,GAAI,MAAA,GAAS,IAAI,MAAA,GAAS,CAAA,GAAI,UAAU,OAAO,CAAA;AAC5D,EAAA,OAAO,CAAC,MAAM,CAAA,GAAI,EAAA,EAAI,OAAO,CAAA,GAAI,CAAA,CAAA,EAAI,GAAA,IAAO,CAAA,GAAI,CAAA,CAAE,CAAA;AACpD;AAGA,SAAS,aAAA,CAAc,KAAa,CAAA,EAAmB;AACrD,EAAA,MAAM,GAAG,CAAA,EAAG,CAAC,CAAA,GAAI,IAAI,GAAG,CAAA;AACxB,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,KAAe,CAAA,IAAK,CAAA,GAAI,UAAW,CAAA,IAAK,CAAA,GAAA,CAAK,CAAA,GAAI,EAAA,GAAK,GAAA,IAAO,KAAA;AACxE,EAAA,MAAM,EAAA,GAAA,CAAM,IAAI,EAAA,IAAM,GAAA;AACtB,EAAA,MAAM,CAAA,GAAI,OAAA,GAAU,CAAA,CAAE,CAAA,GAAI,MAAM,EAAE,CAAA;AAClC,EAAA,MAAM,CAAA,GAAI,EAAE,EAAE,CAAA;AACd,EAAA,MAAM,CAAA,GAAI,OAAA,GAAU,CAAA,CAAE,EAAA,GAAK,IAAI,GAAG,CAAA;AAClC,EAAA,MAAM,GAAA,GAAM;AAAA,IACV,CAAA,GAAI,MAAA,GAAS,CAAA,GAAI,OAAA,GAAU,CAAA,GAAI,OAAA;AAAA,IAC/B,CAAA,GAAI,OAAA,GAAU,CAAA,GAAI,MAAA,GAAS,CAAA,GAAI,MAAA;AAAA,IAC/B,CAAA,GAAI,MAAA,GAAS,CAAA,GAAI,MAAA,GAAS,CAAA,GAAI;AAAA,GAChC;AACA,EAAA,OAAO,CAAA,CAAA,EAAI,GAAA,CACR,GAAA,CAAI,CAAC,CAAA,KAAM;AACV,IAAA,MAAM,CAAA,GAAI,IAAI,QAAA,GAAY,KAAA,GAAQ,MAAM,CAAA,GAAI,GAAA,CAAA,GAAO,QAAQ,KAAA,GAAQ,CAAA;AACnE,IAAA,OAAO,KAAK,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,EAAG,CAAC,CAAC,CAAA,GAAI,GAAG,CAAA,CAChD,QAAA,CAAS,EAAE,CAAA,CACX,QAAA,CAAS,GAAG,GAAG,CAAA;AAAA,EACpB,CAAC,CAAA,CACA,IAAA,CAAK,EAAE,CAAC,CAAA,CAAA;AACb;AAGO,SAAS,aAAA,CAAc,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,GAAQ,CAAC,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,EAAgB;AAC1E,EAAA,MAAM,GAAA,GAAM,KAAK,EAAA,GAAK,GAAA;AACtB,EAAA,MAAM,EAAA,GAAA,CAAM,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,IAAI,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA,IAAK,CAAA;AACvD,EAAA,MAAM,CAAA,GAAI,GAAA,IAAO,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,IAAK,EAAA,IAAM,CAAA,GAAI,EAAA,IAAM,CAAA,CAAE,CAAA,CAAA;AAC5D,EAAA,MAAM,GAAA,GAAA,CAAO,IAAI,CAAA,IAAK,EAAA;AACtB,EAAA,MAAM,GAAA,GAAA,CAAO,IAAI,CAAA,IAAK,EAAA;AACtB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAA,EAAK,EAAE,CAAA;AAC9B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAA,EAAK,EAAE,CAAA;AAC9B,EAAA,MAAM,GAAA,GAAM,CAAC,EAAA,EAAY,EAAA,KAAgB,OAAO,CAAA,IAAK,EAAA,KAAO,CAAA,GAAI,CAAA,GAAA,CAAK,KAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA,GAAI,MAAM,GAAA,IAAO,GAAA;AACvG,EAAA,MAAM,EAAA,GAAK,GAAA,CAAI,GAAA,EAAK,EAAE,CAAA;AACtB,EAAA,MAAM,EAAA,GAAK,GAAA,CAAI,GAAA,EAAK,EAAE,CAAA;AACtB,EAAA,MAAM,KAAK,EAAA,GAAK,EAAA;AAChB,EAAA,MAAM,KAAK,GAAA,GAAM,GAAA;AACjB,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,MAAM,GAAA,KAAQ,CAAA;AAChB,IAAA,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,EAAA,GAAK,EAAE,KAAK,GAAA,GAAM,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,KAAK,GAAA,GAAM,EAAA,GAAK,EAAA,GAAK,GAAA,GAAM,KAAK,EAAA,GAAK,GAAA;AACtF,EAAA,MAAM,EAAA,GAAK,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,GAAA,GAAM,GAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAK,EAAA,GAAK,GAAA,GAAO,CAAC,CAAA;AAC7D,EAAA,MAAM,EAAA,GAAA,CAAM,KAAK,EAAA,IAAM,CAAA;AACvB,EAAA,MAAM,GAAA,GAAA,CAAO,MAAM,GAAA,IAAO,CAAA;AAC1B,EAAA,IAAI,KAAK,EAAA,GAAK,EAAA;AACd,EAAA,IAAI,MAAM,GAAA,KAAQ,CAAA;AAChB,IAAA,EAAA,GAAK,KAAK,GAAA,CAAI,EAAA,GAAK,EAAE,CAAA,IAAK,GAAA,GAAA,CAAO,KAAK,EAAA,IAAM,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,OAAO,EAAA,GAAK,EAAA,GAAK,OAAO,CAAA,GAAA,CAAK,EAAA,GAAK,KAAK,GAAA,IAAO,CAAA;AAC1G,EAAA,MAAM,CAAA,GACJ,CAAA,GACA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAA,CAAK,EAAA,GAAK,EAAA,IAAM,GAAG,CAAA,GAC/B,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAI,EAAA,GAAK,GAAG,CAAA,GAC5B,IAAA,GAAO,IAAA,CAAK,GAAA,CAAA,CAAK,CAAA,GAAI,EAAA,GAAK,CAAA,IAAK,GAAG,CAAA,GAClC,GAAA,GAAM,IAAA,CAAK,GAAA,CAAA,CAAK,CAAA,GAAI,EAAA,GAAK,MAAM,GAAG,CAAA;AACpC,EAAA,MAAM,MAAA,GAAS,KAAK,IAAA,CAAK,GAAA,CAAI,IAAI,EAAA,GAAK,GAAA,IAAO,OAAO,CAAA,CAAE,CAAA;AACtD,EAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAK,IAAA,CAAK,OAAO,CAAA,IAAK,GAAA,IAAO,CAAA,GAAI,EAAA,IAAM,CAAA,CAAE,CAAA;AACxD,EAAA,MAAM,EAAA,GAAK,CAAA,GAAK,KAAA,GAAA,CAAS,EAAA,GAAK,EAAA,KAAO,CAAA,GAAK,IAAA,CAAK,IAAA,CAAK,EAAA,GAAA,CAAM,EAAA,GAAK,EAAA,KAAO,CAAC,CAAA;AACvE,EAAA,MAAM,EAAA,GAAK,IAAI,KAAA,GAAQ,GAAA;AACvB,EAAA,MAAM,EAAA,GAAK,CAAA,GAAI,KAAA,GAAQ,GAAA,GAAM,CAAA;AAC7B,EAAA,MAAM,KAAK,CAAC,IAAA,CAAK,IAAI,CAAA,GAAI,MAAA,GAAS,GAAG,CAAA,GAAI,EAAA;AACzC,EAAA,OAAO,IAAA,CAAK,IAAA,CAAA,CAAM,EAAA,GAAK,EAAA,KAAO,KAAK,EAAA,GAAK,EAAA,KAAO,CAAA,GAAA,CAAK,EAAA,GAAK,OAAO,CAAA,GAAI,EAAA,IAAM,EAAA,GAAK,EAAA,CAAA,IAAO,KAAK,EAAA,CAAG,CAAA;AAChG;AAGO,SAAS,UAAA,CAAW,GAAW,CAAA,EAAmB;AACvD,EAAA,OAAO,cAAc,GAAA,CAAI,CAAC,CAAA,EAAG,GAAA,CAAI,CAAC,CAAC,CAAA;AACrC;AAGA,SAAS,QAAA,CAAS,YAAgC,UAAA,EAAsC;AACtF,EAAA,MAAM,WAAW,CAAC,CAAA,KAAc,QAAA,CAAS,CAAA,EAAG,UAAU,CAAA,IAAK,YAAA;AAC3D,EAAA,MAAM,QAAQ,CAACA,EAAAA,EAAWC,OAAc,UAAA,CAAWD,EAAAA,EAAGC,EAAC,CAAA,IAAK,WAAA;AAE5D,EAAA,MAAM,MAAM,GAAA,CAAI,UAAU,EAAE,CAAC,CAAA,IAAK,KAAK,EAAA,GAAK,CAAA;AAE5C,EAAA,MAAM,eAAA,GAAkB,CAAC,CAAA,KAAc;AACrC,IAAA,IAAI,QAAA,CAAS,CAAC,CAAA,EAAG,OAAO,CAAA;AACxB,IAAA,MAAM,EAAA,GAAK,GAAA,CAAI,CAAC,CAAA,CAAE,CAAC,CAAA;AACnB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,GAAA,EAAK,CAAA,EAAA,EAAK;AAC7B,MAAA,MAAM,CAAA,GAAI,aAAA,CAAc,CAAA,EAAG,EAAA,GAAK,MAAM,CAAC,CAAA;AACvC,MAAA,IAAI,QAAA,CAAS,CAAC,CAAA,EAAG,OAAO,CAAA;AAAA,IAC1B;AACA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AAEA,EAAA,KAAA,MAAW,CAACD,EAAAA,EAAGC,EAAC,KAAK,UAAA,EAAY,IAAI,SAASD,EAAC,CAAA,IAAK,SAASC,EAAC,CAAA,IAAK,MAAMD,EAAAA,EAAGC,EAAC,GAAG,OAAO,CAACD,IAAGC,EAAC,CAAA;AAC5F,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,GAAA,CAAI,CAAC,CAACD,EAAAA,EAAGC,EAAC,CAAA,KAAwB,CAAC,gBAAgBD,EAAC,CAAA,EAAG,eAAA,CAAgBC,EAAC,CAAC,CAAC,CAAA;AACtG,EAAA,KAAA,MAAW,CAACD,EAAAA,EAAGC,EAAC,CAAA,IAAK,QAAA,EAAU,IAAI,KAAA,CAAMD,EAAAA,EAAGC,EAAC,CAAA,EAAG,OAAO,CAACD,IAAGC,EAAC,CAAA;AAI5D,EAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,SAAS,CAAC,CAAA;AACzB,EAAA,MAAM,cAAA,GAAiB,CAAC,CAAA,KAAc;AACpC,IAAA,MAAM,EAAA,GAAK,GAAA,CAAI,CAAC,CAAA,CAAE,CAAC,CAAA;AACnB,IAAA,MAAM,UAAsB,EAAC;AAC7B,IAAA,KAAA,IAAS,CAAA,GAAI,IAAA,EAAM,CAAA,IAAK,GAAA,EAAK,CAAA,EAAA,EAAK;AAChC,MAAA,IAAI,EAAA,GAAK,CAAA,GAAI,CAAA,IAAK,EAAA,GAAK,IAAI,GAAA,EAAK;AAChC,MAAA,MAAM,IAAI,CAAA,KAAM,CAAA,GAAI,IAAI,aAAA,CAAc,CAAA,EAAG,KAAK,CAAC,CAAA;AAC/C,MAAA,IAAI,CAAC,QAAA,CAAS,CAAC,CAAA,EAAG;AAClB,MAAA,OAAA,CAAQ,IAAA,CAAK,GAAA,CAAI,CAAC,CAAC,MAAM,EAAC;AAC1B,MAAA,OAAA,CAAQ,KAAK,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,IAC9B;AACA,IAAA,OAAO,OAAA;AAAA,EACT,CAAA;AACA,EAAA,MAAM,EAAA,GAAK,eAAe,CAAC,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,eAAe,CAAC,CAAA;AAC3B,EAAA,IAAI,IAAA,GAAyB,CAAC,CAAA,EAAG,CAAC,CAAA;AAClC,EAAA,IAAI,MAAA,GAAS,UAAA,CAAW,CAAA,EAAG,CAAC,CAAA;AAC5B,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,IAAS,GAAA,EAAK,KAAA,EAAA,EAAS;AACzC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,KAAA,EAAO,CAAA,EAAA,EAAK;AAC/B,MAAA,KAAA,MAAW,EAAA,IAAM,EAAA,CAAG,CAAC,CAAA,IAAK,EAAC;AACzB,QAAA,KAAA,MAAW,MAAM,EAAA,CAAG,KAAA,GAAQ,CAAC,CAAA,IAAK,EAAC,EAAG;AACpC,UAAA,MAAM,CAAA,GAAI,UAAA,CAAW,EAAA,EAAI,EAAE,CAAA;AAC3B,UAAA,IAAI,CAAA,IAAK,WAAA,EAAa,OAAO,CAAC,IAAI,EAAE,CAAA;AACpC,UAAA,IAAI,IAAI,MAAA,EAAQ;AACd,YAAA,IAAA,GAAO,CAAC,IAAI,EAAE,CAAA;AACd,YAAA,MAAA,GAAS,CAAA;AAAA,UACX;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AA4BO,SAAS,iBAAA,CAAkB,KAAA,EAAc,KAAA,EAAc,IAAA,EAA0C;AACtG,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,GAAG,aAAY,GAAI,IAAA;AAC1C,EAAA,MAAM,EAAA,GAAK,EAAE,KAAA,EAAO,IAAA,CAAK,OAAO,KAAA,IAAS,WAAA,CAAY,KAAK,CAAA,EAAG,MAAM,IAAA,CAAK,KAAA,EAAO,IAAA,IAAQ,WAAA,CAAY,IAAI,CAAA,EAAE;AACzG,EAAA,MAAM,MAAM,WAAA,CAAY,CAAC,OAAO,KAAK,CAAA,EAAG,QAAQ,WAAW,CAAA;AAC3D,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,MAAM,CAAA,CAAE,KAAA;AACnC,EAAA,MAAM,CAAC,CAAA,EAAG,CAAC,IAAI,GAAA,CAAI,GAAA,CAAI,CAAC,EAAA,KAAO;AAC7B,IAAA,MAAM,CAAA,GAAI,EAAA,KAAO,MAAA,GAAY,MAAA,GAAY,IAAA,CAAK,KAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,EAAE,CAAA;AAC1E,IAAA,MAAM,GAAA,GAAM,GAAG,eAAA,IAAmB,IAAA;AAClC,IAAA,OAAO,EAAE,OAAA,EAAS,CAAA,EAAG,aAAA,IAAiB,GAAA,IAAO,UAAU,GAAA,EAAI;AAAA,EAC7D,CAAC,CAAA;AAED,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,CAAC,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA;AAAA,IACrB,CAAC,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,GAAG,CAAA;AAAA,IACjB,CAAC,CAAA,CAAE,GAAA,EAAK,CAAA,CAAE,OAAO,CAAA;AAAA,IACjB,CAAC,CAAA,CAAE,GAAA,EAAK,CAAA,CAAE,GAAG;AAAA,GACf,CAAE,MAAA,CAAO,CAAC,CAAA,KAA6B,CAAA,CAAE,CAAC,CAAA,KAAM,IAAA,IAAQ,CAAA,CAAE,CAAC,CAAA,KAAM,IAAI,CAAA;AACrE,EAAA,OAAO,EAAE,KAAA,EAAO,QAAA,CAAS,UAAA,EAAY,EAAA,CAAG,KAAK,CAAA,EAAG,IAAA,EAAM,QAAA,CAAS,UAAA,EAAY,EAAA,CAAG,IAAI,CAAA,EAAE;AACtF;AAuBA,eAAsB,aAAA,CACpB,KAAA,EACA,KAAA,EACA,IAAA,EACwB;AACxB,EAAA,MAAM,UAAA,CAAW,KAAK,MAAM,CAAA;AAC5B,EAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,KAAA,EAAO,IAAI,CAAA;AAC7C;;;AClOO,IAAM,OAAA,GAAkB;;;ACExB,SAAS,QAAA,GAA6E;AAC3F,EAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,KAAA,EAAO,aAAA,EAAe,sBAAsB,sBAAA,EAAuB;AAChG","file":"chunk-J4P4HDBF.js","sourcesContent":["import { LEAGUES, type League, type Team } from \"./data/index.js\";\nimport { loadLeague, preloadAll } from \"./index-data.js\";\n\n/** All teams for one league, or every league (in `LEAGUES` order) when omitted. */\nexport async function teams(league?: League): Promise<readonly Team[]> {\n if (league) return (await loadLeague(league)).teams;\n await preloadAll();\n return (await Promise.all(LEAGUES.map(loadLeague))).flatMap((d) => d.teams);\n}\n","import { InputError } from \"./errors.js\";\n\n/** Column form → `Row[]` (flat objects, one per index). Columns must be equal length; `{}` → `[]`. */\nexport function rowsFrom(columns: Record<string, readonly unknown[]>): Record<string, unknown>[] {\n const keys = Object.keys(columns);\n const n = keys.length ? (columns[keys[0] as string] as readonly unknown[]).length : 0;\n for (const k of keys) {\n const len = (columns[k] as readonly unknown[]).length;\n if (len !== n) throw new InputError(`rowsFrom: column \"${k}\" has length ${len}, expected ${n}`);\n }\n return Array.from({ length: n }, (_, i) => {\n const row: Record<string, unknown> = {};\n for (const k of keys) row[k] = (columns[k] as readonly unknown[])[i];\n return row;\n });\n}\n","import { contrast, hex6 } from \"./contrast.js\";\nimport { getLeagueSync, loadLeague } from \"./index-data.js\";\nimport { type ResolveOptions, type Value, resolveSync } from \"./resolve.js\";\nimport type { League } from \"./types.js\";\n\n// Port of Game on Paper's game colours (`pickGameColors`, astro/src/utils/misc.ts at b8b8eaad): its Lab\n// conversion, candidate order, thresholds and fallbacks, kept operation for operation so the pairs match\n// its output exactly (fixtures/matchup-colors).\n\nconst MIN_DELTA_E = 20;\nconst MIN_CONTRAST = 2.5;\n/** Game on Paper's page backgrounds (`GAME_BACKGROUNDS`). */\nconst BACKGROUNDS = { light: \"#ffffff\", dark: \"#181a1b\" } as const;\n/** A team with no colour gets Game on Paper's `STANDARD_THEME_COLOR`. */\nconst NO_COLOR = \"#2394fd\";\n\ntype Lab = [number, number, number];\n\n/** CIE L*a*b* (D65) of `#rrggbb`: Game on Paper's `rgb2lab`, with its rounded constants. */\nfunction lab(hex: string): Lab {\n const [r, g, b] = [1, 3, 5].map((i) => {\n const s = Number.parseInt(hex.slice(i, i + 2), 16) / 255;\n return s > 0.04045 ? ((s + 0.055) / 1.055) ** 2.4 : s / 12.92;\n }) as Lab;\n const f = (t: number) => (t > 0.008856 ? t ** (1 / 3) : 7.787 * t + 16 / 116);\n const x = f((r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047);\n const y = f(r * 0.2126 + g * 0.7152 + b * 0.0722);\n const z = f((r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883);\n return [116 * y - 16, 500 * (x - y), 200 * (y - z)];\n}\n\n/** `hex` with its L* set to `L` (a*, b* kept), clamped into sRGB: Game on Paper's `lab2rgb` + `rgbArrayToHex`. */\nfunction withLightness(hex: string, L: number): string {\n const [, A, B] = lab(hex);\n const f = (t: number) => (t ** 3 > 0.008856 ? t ** 3 : (t - 16 / 116) / 7.787);\n const fy = (L + 16) / 116;\n const x = 0.95047 * f(A / 500 + fy);\n const y = f(fy);\n const z = 1.08883 * f(fy - B / 200);\n const lin = [\n x * 3.2406 + y * -1.5372 + z * -0.4986,\n x * -0.9689 + y * 1.8758 + z * 0.0415,\n x * 0.0557 + y * -0.204 + z * 1.057,\n ];\n return `#${lin\n .map((v) => {\n const s = v > 0.0031308 ? 1.055 * v ** (1 / 2.4) - 0.055 : 12.92 * v;\n return Math.round(Math.max(0, Math.min(1, s)) * 255)\n .toString(16)\n .padStart(2, \"0\");\n })\n .join(\"\")}`;\n}\n\n/** CIEDE2000 colour difference between two L*a*b* colours (Sharma, Wu and Dalal 2005). */\nexport function deltaE2000Lab([L1, a1, b1]: Lab, [L2, a2, b2]: Lab): number {\n const rad = Math.PI / 180;\n const Cm = (Math.hypot(a1, b1) + Math.hypot(a2, b2)) / 2;\n const G = 0.5 * (1 - Math.sqrt(Cm ** 7 / (Cm ** 7 + 25 ** 7)));\n const a1p = (1 + G) * a1;\n const a2p = (1 + G) * a2;\n const C1p = Math.hypot(a1p, b1);\n const C2p = Math.hypot(a2p, b2);\n const hue = (ap: number, bp: number) => (ap === 0 && bp === 0 ? 0 : (Math.atan2(bp, ap) / rad + 360) % 360);\n const h1 = hue(a1p, b1);\n const h2 = hue(a2p, b2);\n const dL = L2 - L1;\n const dC = C2p - C1p;\n let dh = 0;\n if (C1p * C2p !== 0)\n dh = Math.abs(h2 - h1) <= 180 ? h2 - h1 : h2 - h1 > 180 ? h2 - h1 - 360 : h2 - h1 + 360;\n const dH = 2 * Math.sqrt(C1p * C2p) * Math.sin((dh * rad) / 2);\n const Lm = (L1 + L2) / 2;\n const Cmp = (C1p + C2p) / 2;\n let Hm = h1 + h2;\n if (C1p * C2p !== 0)\n Hm = Math.abs(h1 - h2) <= 180 ? (h1 + h2) / 2 : h1 + h2 < 360 ? (h1 + h2 + 360) / 2 : (h1 + h2 - 360) / 2;\n const T =\n 1 -\n 0.17 * Math.cos((Hm - 30) * rad) +\n 0.24 * Math.cos(2 * Hm * rad) +\n 0.32 * Math.cos((3 * Hm + 6) * rad) -\n 0.2 * Math.cos((4 * Hm - 63) * rad);\n const dTheta = 30 * Math.exp(-(((Hm - 275) / 25) ** 2));\n const Rc = 2 * Math.sqrt(Cmp ** 7 / (Cmp ** 7 + 25 ** 7));\n const Sl = 1 + (0.015 * (Lm - 50) ** 2) / Math.sqrt(20 + (Lm - 50) ** 2);\n const Sc = 1 + 0.045 * Cmp;\n const Sh = 1 + 0.015 * Cmp * T;\n const Rt = -Math.sin(2 * dTheta * rad) * Rc;\n return Math.sqrt((dL / Sl) ** 2 + (dC / Sc) ** 2 + (dH / Sh) ** 2 + Rt * (dC / Sc) * (dH / Sh));\n}\n\n/** CIEDE2000 between two `#rrggbb` colours, through Game on Paper's Lab conversion. */\nexport function deltaE2000(a: string, b: string): number {\n return deltaE2000Lab(lab(a), lab(b));\n}\n\n/** Game on Paper's `pickPairOn`: the first usable candidate, else L* moved until the pair reads and separates. */\nfunction pickPair(candidates: [string, string][], background: string): [string, string] {\n const readable = (c: string) => contrast(c, background) >= MIN_CONTRAST;\n const apart = (x: string, y: string) => deltaE2000(x, y) >= MIN_DELTA_E;\n // the side with room to read: darker on a light background, lighter on a dark one\n const dir = lab(background)[0] >= 50 ? -1 : 1;\n // nearest L* at which the colour reads on this background\n const readableVariant = (c: string) => {\n if (readable(c)) return c;\n const L0 = lab(c)[0];\n for (let k = 1; k <= 100; k++) {\n const v = withLightness(c, L0 + dir * k);\n if (readable(v)) return v;\n }\n return c;\n };\n\n for (const [x, y] of candidates) if (readable(x) && readable(y) && apart(x, y)) return [x, y];\n const variants = candidates.map(([x, y]): [string, string] => [readableVariant(x), readableVariant(y)]);\n for (const [x, y] of variants) if (apart(x, y)) return [x, y];\n\n // move both colours' L* within the range where each still reads, least total movement first;\n // keep the widest readable separation seen in case nothing clears\n const [x, y] = variants[0] as [string, string];\n const readableShifts = (c: string) => {\n const L0 = lab(c)[0];\n const byShift: string[][] = []; // byShift[|k|] = readable variants moved |k| in L*\n for (let k = -100; k <= 100; k++) {\n if (L0 + k < 0 || L0 + k > 100) continue;\n const v = k === 0 ? c : withLightness(c, L0 + k);\n if (!readable(v)) continue;\n byShift[Math.abs(k)] ??= [];\n byShift[Math.abs(k)]?.push(v);\n }\n return byShift;\n };\n const xs = readableShifts(x);\n const ys = readableShifts(y);\n let best: [string, string] = [x, y];\n let bestDE = deltaE2000(x, y);\n for (let total = 1; total <= 200; total++) {\n for (let i = 0; i <= total; i++) {\n for (const hx of xs[i] ?? [])\n for (const hy of ys[total - i] ?? []) {\n const d = deltaE2000(hx, hy);\n if (d >= MIN_DELTA_E) return [hx, hy];\n if (d > bestDE) {\n best = [hx, hy];\n bestDE = d;\n }\n }\n }\n }\n return best;\n}\n\n/** Options for {@link matchupColors}: the league, how to resolve the two teams, and the backgrounds. */\nexport interface MatchupColorOptions extends ResolveOptions {\n /** The league both teams belong to. */\n league: League;\n /** The background each theme's pair must read on; default `{ light: \"#ffffff\", dark: \"#181a1b\" }` (Game on Paper's pages). */\n theme?: { light?: string; dark?: string };\n}\n/** One `[teamA, teamB]` colour pair per theme, as lowercase `#rrggbb`. */\nexport interface MatchupColors {\n /** The pair for a light background. */\n light: [string, string];\n /** The pair for a dark background. */\n dark: [string, string];\n}\n\n/**\n * {@link matchupColors} once the league is loaded (`loadLeague` or `preloadAll`).\n *\n * @example\n * ```ts\n * import { loadLeague, matchupColorsSync } from \"@sportsdataverse/sdvplot\";\n *\n * await loadLeague(\"cfb\");\n * matchupColorsSync(\"Alabama\", \"Georgia\", { league: \"cfb\" });\n * ```\n */\nexport function matchupColorsSync(teamA: Value, teamB: Value, opts: MatchupColorOptions): MatchupColors {\n const { league, theme, ...resolveOpts } = opts;\n const bg = { light: hex6(theme?.light ?? BACKGROUNDS.light), dark: hex6(theme?.dark ?? BACKGROUNDS.dark) };\n const ids = resolveSync([teamA, teamB], league, resolveOpts);\n const rows = getLeagueSync(league).teams;\n const [a, b] = ids.map((id) => {\n const t = id === undefined ? undefined : rows.find((r) => r.team_id === id);\n const alt = t?.color_secondary ?? null;\n return { primary: t?.color_primary ?? alt ?? NO_COLOR, alt };\n }) as [{ primary: string; alt: string | null }, { primary: string; alt: string | null }];\n // both primaries, teamB's alternate, teamA's alternate, both alternates\n const candidates = [\n [a.primary, b.primary],\n [a.primary, b.alt],\n [a.alt, b.primary],\n [a.alt, b.alt],\n ].filter((p): p is [string, string] => p[0] !== null && p[1] !== null);\n return { light: pickPair(candidates, bg.light), dark: pickPair(candidates, bg.dark) };\n}\n\n/**\n * Two team colours that tell the teams apart on a chart: Game on Paper's \"game colours\" picker.\n *\n * @remarks\n * One pair per theme, each the first candidate whose colours are at least 20 apart in CIEDE2000 and each\n * at least 2.5:1 (WCAG) against that theme's background. Candidates, in order: both primaries, teamB's\n * secondary, teamA's secondary, both secondaries; so a team keeps its primary whenever it works, and teamA\n * (Game on Paper's home team) keeps it first. When no candidate works, an unreadable colour's L* moves just\n * far enough to read; then both colours' L* move, least total movement first, until they separate; failing\n * that, the widest readable separation found. A team with no colour gets `#2394fd`. Deterministic.\n *\n * @example\n * ```ts\n * import { matchupColors } from \"@sportsdataverse/sdvplot\";\n *\n * // two crimson teams; light: [\"#9e1b32\", \"#2c2a29\"] (Georgia's secondary), dark: [\"#ffffff\", \"#ba0c2f\"]\n * // in a page, pick the pair for the theme:\n * // const [alabama, georgia] = window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? dark : light;\n * await matchupColors(\"Alabama\", \"Georgia\", { league: \"cfb\" });\n * ```\n */\nexport async function matchupColors(\n teamA: Value,\n teamB: Value,\n opts: MatchupColorOptions,\n): Promise<MatchupColors> {\n await loadLeague(opts.league);\n return matchupColorsSync(teamA, teamB, opts);\n}\n","// Injected from package.json by tsup/vitest `define`, so changesets version bumps reach versions().\nexport const VERSION: string = __SDVPLOT_VERSION__;\n","import { INDEX_VERSION, MANIFEST_LAST_MODIFIED } from \"./data/index.js\";\nimport { VERSION } from \"./version.js\";\n\nexport function versions(): { sdvplot: string; index: string; manifestLastModified: string } {\n return { sdvplot: VERSION, index: INDEX_VERSION, manifestLastModified: MANIFEST_LAST_MODIFIED };\n}\n"]}
|