@sportsdataverse/sdvplot 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +109 -0
- package/README.md +984 -2
- package/dist/_web-D7Aa5Rd8.d.ts +69 -0
- package/dist/aaf-GJ3SH34T.js +13 -0
- package/dist/aaf-HCYN5T6Y.js +37 -0
- package/dist/aaf-ZAE5KS2Y.js +13 -0
- package/dist/ahl-E66MDVCU.js +66 -0
- package/dist/ahl-NPQQWZEV.js +249 -0
- package/dist/ahl-QRDU73XX.js +309 -0
- package/dist/axis-CraWQRUJ.d.ts +49 -0
- package/dist/bins.d.ts +174 -0
- package/dist/bins.js +4 -0
- package/dist/bins.js.map +1 -0
- package/dist/cfb-F42SVS4X.js +5000 -0
- package/dist/cfb-P3SHEYRZ.js +692 -0
- package/dist/cfb-WXRZANLP.js +10226 -0
- package/dist/chartjs-surface.d.ts +42 -0
- package/dist/chartjs-surface.js +65 -0
- package/dist/chartjs-surface.js.map +1 -0
- package/dist/chartjs.d.ts +162 -0
- package/dist/chartjs.js +342 -0
- package/dist/chartjs.js.map +1 -0
- package/dist/chunk-4C3GX6QO.js +92 -0
- package/dist/chunk-4C3GX6QO.js.map +1 -0
- package/dist/chunk-57WFSI4Q.js +128 -0
- package/dist/chunk-57WFSI4Q.js.map +1 -0
- package/dist/chunk-7ULOCCFL.js +313 -0
- 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-C2CDY5OG.js +137 -0
- package/dist/chunk-C2CDY5OG.js.map +1 -0
- package/dist/chunk-DYMUVE6K.js +127 -0
- package/dist/chunk-DYMUVE6K.js.map +1 -0
- package/dist/chunk-E7G7VSLV.js +43 -0
- package/dist/chunk-E7G7VSLV.js.map +1 -0
- package/dist/chunk-H2C3FMMA.js +300 -0
- package/dist/chunk-H2C3FMMA.js.map +1 -0
- package/dist/chunk-J4P4HDBF.js +175 -0
- package/dist/chunk-J4P4HDBF.js.map +1 -0
- package/dist/chunk-J6R2LEJ7.js +58 -0
- package/dist/chunk-J6R2LEJ7.js.map +1 -0
- package/dist/chunk-M3XD2OSN.js +132 -0
- package/dist/chunk-M3XD2OSN.js.map +1 -0
- package/dist/chunk-OIILARXI.js +30 -0
- package/dist/chunk-OIILARXI.js.map +1 -0
- 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-ZAEQXFJM.js +556 -0
- package/dist/chunk-ZAEQXFJM.js.map +1 -0
- package/dist/cricket-KPCYG2HL.js +493 -0
- package/dist/cricket-NDXLE25B.js +116 -0
- package/dist/cricket-YUUF7P6M.js +160 -0
- 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 +234 -0
- package/dist/d3.js +198 -0
- package/dist/d3.js.map +1 -0
- package/dist/deckgl.d.ts +232 -0
- package/dist/deckgl.js +197 -0
- package/dist/deckgl.js.map +1 -0
- package/dist/echarts.d.ts +121 -0
- package/dist/echarts.js +228 -0
- package/dist/echarts.js.map +1 -0
- package/dist/echl-3CR4RGFC.js +241 -0
- package/dist/echl-NPC32C23.js +107 -0
- package/dist/echl-PI33DGJC.js +64 -0
- package/dist/export.d.ts +130 -0
- package/dist/export.js +258 -0
- package/dist/export.js.map +1 -0
- package/dist/g2.d.ts +251 -0
- package/dist/g2.js +102 -0
- package/dist/g2.js.map +1 -0
- package/dist/headshots-B2J_LOO8.d.ts +40 -0
- package/dist/index.d.ts +183 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/interact.d.ts +567 -0
- package/dist/interact.js +809 -0
- package/dist/interact.js.map +1 -0
- 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/marks-DH-tQIP-.d.ts +75 -0
- package/dist/mbb-3TRLVW3H.js +3619 -0
- package/dist/mbb-DQUHCHZP.js +5111 -0
- package/dist/mbb-PRAIO2P5.js +371 -0
- package/dist/milb-6IQ6NCEW.js +291 -0
- package/dist/milb-EYY5MD4T.js +1752 -0
- package/dist/milb-EYZ4SZLI.js +797 -0
- package/dist/mlb-4PBUJSVQ.js +35 -0
- package/dist/mlb-FHPY3GQJ.js +701 -0
- package/dist/mlb-REVGL3N2.js +665 -0
- package/dist/mui.d.ts +338 -0
- package/dist/mui.js +184 -0
- package/dist/mui.js.map +1 -0
- package/dist/nba-ATT775GS.js +485 -0
- package/dist/nba-LKM4UHVU.js +482 -0
- package/dist/nba-YX7PXM3R.js +35 -0
- package/dist/nbagl-3WGZCZ4S.js +37 -0
- package/dist/nbagl-LP4XJRAL.js +229 -0
- package/dist/nbagl-VTTOU7LN.js +499 -0
- package/dist/ncaa_baseball-UV75LNVR.js +2670 -0
- package/dist/ncaa_baseball-VD5J5C72.js +419 -0
- package/dist/ncaa_baseball-YRBS32D6.js +4592 -0
- package/dist/ncaa_mhockey-IMYHS7QS.js +1033 -0
- package/dist/ncaa_mhockey-TXTKWHE3.js +115 -0
- package/dist/ncaa_mhockey-U3MFW5VT.js +663 -0
- package/dist/ncaa_softball-6WR6KS64.js +420 -0
- package/dist/ncaa_softball-RZCTIE56.js +2654 -0
- package/dist/ncaa_softball-VOD4PVGY.js +4599 -0
- package/dist/ncaa_whockey-6XXGUTBK.js +607 -0
- package/dist/ncaa_whockey-AKKYKY67.js +53 -0
- package/dist/ncaa_whockey-KBEKXFBB.js +293 -0
- package/dist/nfl-BDB2HYAR.js +625 -0
- package/dist/nfl-EHYHDLJD.js +37 -0
- package/dist/nfl-VF4NJCHY.js +514 -0
- package/dist/nfl_gsis-UY64JO37.js +4 -0
- package/dist/nhl-6WPHME7H.js +511 -0
- package/dist/nhl-EMIJFZHY.js +884 -0
- package/dist/nhl-ISFUKRFU.js +37 -0
- package/dist/nivo.d.ts +193 -0
- package/dist/nivo.js +8 -0
- package/dist/nivo.js.map +1 -0
- package/dist/ohl-2FEM554G.js +113 -0
- package/dist/ohl-C5Q4W6JB.js +32 -0
- package/dist/ohl-TQ4J46VC.js +66 -0
- package/dist/perspective.d.ts +198 -0
- package/dist/perspective.js +171 -0
- package/dist/perspective.js.map +1 -0
- package/dist/phf-H7POU2KW.js +32 -0
- package/dist/phf-K5IFMZUM.js +13 -0
- package/dist/phf-TWJI3BOW.js +20 -0
- package/dist/placement-UWkqUzpa.d.ts +32 -0
- package/dist/plot.d.ts +451 -0
- package/dist/plot.js +712 -0
- package/dist/plot.js.map +1 -0
- package/dist/plotly.d.ts +129 -0
- package/dist/plotly.js +360 -0
- package/dist/plotly.js.map +1 -0
- package/dist/pwhl-OX3BO4JI.js +53 -0
- package/dist/pwhl-W44OC3C6.js +17 -0
- package/dist/pwhl-ZJGG3H7W.js +23 -0
- package/dist/qmjhl-5HISEHLL.js +35 -0
- package/dist/qmjhl-DA3UHKE5.js +125 -0
- package/dist/qmjhl-YG4BOQPF.js +614 -0
- package/dist/react.d.ts +377 -0
- package/dist/react.js +522 -0
- package/dist/react.js.map +1 -0
- package/dist/recharts.d.ts +162 -0
- package/dist/recharts.js +8 -0
- package/dist/recharts.js.map +1 -0
- package/dist/resolve-CQW-jzvr.d.ts +28 -0
- package/dist/selection-D4T3PkRt.d.ts +140 -0
- package/dist/shadcn.d.ts +83 -0
- package/dist/shadcn.js +88 -0
- package/dist/shadcn.js.map +1 -0
- package/dist/shots.d.ts +364 -0
- package/dist/shots.js +86 -0
- package/dist/shots.js.map +1 -0
- package/dist/soccer-7BH3ZLVL.js +7898 -0
- package/dist/soccer-MRU25OGE.js +2636 -0
- package/dist/soccer-PF4IPPVA.js +12342 -0
- 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.d.ts +75 -0
- package/dist/testing.js +239 -0
- package/dist/testing.js.map +1 -0
- package/dist/three.d.ts +223 -0
- package/dist/three.js +50 -0
- package/dist/three.js.map +1 -0
- package/dist/tiers-BN4md-GB.d.ts +65 -0
- package/dist/types-C7n6gJF3.d.ts +62 -0
- package/dist/ufl-7VLZTLTT.js +143 -0
- package/dist/ufl-CCMBLPSW.js +100 -0
- package/dist/ufl-F2BJRXME.js +16 -0
- 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/usfl-4CR5RMZJ.js +32 -0
- package/dist/usfl-LD7HP2YK.js +14 -0
- package/dist/usfl-VU4YSJQD.js +19 -0
- package/dist/ushl-CPG2LB4L.js +73 -0
- package/dist/ushl-PQL6HJAD.js +88 -0
- package/dist/ushl-ZT2ATPHK.js +22 -0
- package/dist/vega.d.ts +85 -0
- package/dist/vega.js +362 -0
- package/dist/vega.js.map +1 -0
- package/dist/victory.d.ts +107 -0
- package/dist/victory.js +38 -0
- package/dist/victory.js.map +1 -0
- package/dist/wbb-3KHCDYTK.js +5087 -0
- package/dist/wbb-BMX53Q3Q.js +369 -0
- package/dist/wbb-QNRN2CJJ.js +3620 -0
- package/dist/whl-4ATYZWUB.js +97 -0
- package/dist/whl-RVFPL6MH.js +79 -0
- package/dist/whl-Y7ASKYMM.js +28 -0
- package/dist/wnba-FWX5SFVI.js +232 -0
- package/dist/wnba-GX6HZR4B.js +220 -0
- package/dist/wnba-NTMWIPP6.js +20 -0
- package/dist/xfl-43R2JMJK.js +30 -0
- package/dist/xfl-H3BXQPZZ.js +16 -0
- package/dist/xfl-XON7A7FI.js +69 -0
- package/package.json +366 -3
package/dist/vega.js
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { markPlacements, axisLetter, axisPlacements, aspect, imageSources, colorList } from './chunk-UL5M6KDE.js';
|
|
2
|
+
export { embedSources } from './chunk-UL5M6KDE.js';
|
|
3
|
+
import { checkHeight, checkAlpha, placedName } from './chunk-7ULOCCFL.js';
|
|
4
|
+
import './chunk-ZAEQXFJM.js';
|
|
5
|
+
import './chunk-J6R2LEJ7.js';
|
|
6
|
+
import { InputError, UnsupportedTargetError } from './chunk-E7G7VSLV.js';
|
|
7
|
+
|
|
8
|
+
// src/vega.ts
|
|
9
|
+
var DEFAULT_HEIGHT = 300;
|
|
10
|
+
var AXIS_GAP = 6;
|
|
11
|
+
var LABEL_PADDING = 2;
|
|
12
|
+
var URL = "sdvplot_url";
|
|
13
|
+
var TEAM = "sdvplot_team";
|
|
14
|
+
var LABEL = "sdvplot_label";
|
|
15
|
+
var DISCRETE = /* @__PURE__ */ new Set(["nominal", "ordinal"]);
|
|
16
|
+
var UNIT_KEYS = ["mark", "encoding", "transform", "params", "projection", "view", "name"];
|
|
17
|
+
var COMPOSITE = {
|
|
18
|
+
facet: "spec.spec",
|
|
19
|
+
repeat: "spec.spec",
|
|
20
|
+
hconcat: "hconcat[i]",
|
|
21
|
+
vconcat: "vconcat[i]",
|
|
22
|
+
concat: "concat[i]"
|
|
23
|
+
};
|
|
24
|
+
function specOf(target) {
|
|
25
|
+
if (typeof target !== "object" || target === null || Array.isArray(target))
|
|
26
|
+
throw new UnsupportedTargetError(
|
|
27
|
+
`sdvplot/vega draws on a Vega-Lite spec object, got ${target === null ? "null" : typeof target}`
|
|
28
|
+
);
|
|
29
|
+
for (const key of Object.keys(COMPOSITE))
|
|
30
|
+
if (key in target)
|
|
31
|
+
throw new InputError(
|
|
32
|
+
`sdvplot cannot draw on a ${key} spec; draw on one of its charts (${COMPOSITE[key]}), then combine`
|
|
33
|
+
);
|
|
34
|
+
return target;
|
|
35
|
+
}
|
|
36
|
+
var jsonable = (v) => v instanceof Date ? v.toISOString() : typeof v === "bigint" ? Number(v) : v;
|
|
37
|
+
var unescapeField = (f) => f.replace(/\\(.)/g, "$1");
|
|
38
|
+
function units(spec) {
|
|
39
|
+
return [spec, ...(spec.layer ?? []).flatMap((s) => units(s))];
|
|
40
|
+
}
|
|
41
|
+
function unit(spec, channel) {
|
|
42
|
+
for (const u of units(spec)) {
|
|
43
|
+
const e = u.encoding?.[channel];
|
|
44
|
+
if (typeof e === "object" && e !== null && "field" in e) return [u, e];
|
|
45
|
+
}
|
|
46
|
+
return [{}, {}];
|
|
47
|
+
}
|
|
48
|
+
function pixels(h, name) {
|
|
49
|
+
if (typeof h !== "number" || !Number.isFinite(h) || h <= 0)
|
|
50
|
+
throw new InputError(
|
|
51
|
+
`sdvplot sizes marks from the chart height; ${name} must be a positive number of pixels, not ${JSON.stringify(h)}`
|
|
52
|
+
);
|
|
53
|
+
return h;
|
|
54
|
+
}
|
|
55
|
+
function chartHeight(spec) {
|
|
56
|
+
for (const u of units(spec)) if (u.height !== void 0) return pixels(u.height, "height");
|
|
57
|
+
if (DISCRETE.has(String(unit(spec, "y")[1].type)))
|
|
58
|
+
throw new InputError(
|
|
59
|
+
"a discrete y axis is sized by its step; set the chart height in pixels (spec.height)"
|
|
60
|
+
);
|
|
61
|
+
const h = spec.config?.view?.continuousHeight ?? DEFAULT_HEIGHT;
|
|
62
|
+
return pixels(h, "config.view.continuousHeight");
|
|
63
|
+
}
|
|
64
|
+
var STACKED_BY_DEFAULT = /* @__PURE__ */ new Set(["bar", "area", "arc"]);
|
|
65
|
+
function byChannel(sort, u) {
|
|
66
|
+
const desc = sort.startsWith("-");
|
|
67
|
+
const def = u.encoding?.[desc ? sort.slice(1) : sort];
|
|
68
|
+
if (def?.field === void 0 && def?.aggregate === void 0)
|
|
69
|
+
throw new InputError(
|
|
70
|
+
`the sort ${JSON.stringify(sort)} names a channel without a field; sort with an explicit list (sort: [...])`
|
|
71
|
+
);
|
|
72
|
+
const marks = units(u).map(
|
|
73
|
+
(v) => String(typeof v.mark === "object" && v.mark !== null ? v.mark.type : v.mark)
|
|
74
|
+
);
|
|
75
|
+
const stacked = def.type === "quantitative" && !def.bin && ("stack" in def ? Boolean(def.stack) : marks.some((m) => STACKED_BY_DEFAULT.has(m)));
|
|
76
|
+
return {
|
|
77
|
+
...def.field !== void 0 ? { field: def.field } : {},
|
|
78
|
+
op: def.aggregate ?? (stacked ? "sum" : "min"),
|
|
79
|
+
...desc ? { order: "descending" } : {}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function inlineRows(spec, u) {
|
|
83
|
+
const data = u.data ?? spec.data ?? {};
|
|
84
|
+
return data.name !== void 0 ? spec.datasets?.[data.name] : data.values;
|
|
85
|
+
}
|
|
86
|
+
function countOrder(spec, u, enc, order, channel) {
|
|
87
|
+
const rows = inlineRows(spec, u);
|
|
88
|
+
const all = units(spec);
|
|
89
|
+
if (rows === void 0 || new Set(all.map((v) => v.data).filter((d) => d !== void 0)).size > 1 || all.some((v) => v.transform !== void 0))
|
|
90
|
+
throw new InputError(
|
|
91
|
+
`the ${channel} count sort is kept once a layer is added only on inline data with no transform (one data source); sort with an explicit list (sort: [...]), then add the marks`
|
|
92
|
+
);
|
|
93
|
+
const key = unescapeField(String(enc.field));
|
|
94
|
+
const counts = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const r of rows)
|
|
96
|
+
if (r[key] !== null && r[key] !== void 0) counts.set(r[key], (counts.get(r[key]) ?? 0) + 1);
|
|
97
|
+
const sign = order === "descending" ? -1 : 1;
|
|
98
|
+
return [...counts].sort((a, b) => (a[1] - b[1]) * sign).map(([c]) => c);
|
|
99
|
+
}
|
|
100
|
+
function sortOf(spec, enc, channel, u) {
|
|
101
|
+
const given = "sort" in enc ? enc.sort : "ascending";
|
|
102
|
+
const sort = typeof given === "string" && given !== "ascending" && given !== "descending" ? byChannel(given, u) : given;
|
|
103
|
+
const op = String(sort?.op);
|
|
104
|
+
const kept = sort === null || sort === "ascending" || sort === "descending" || Array.isArray(sort) || typeof sort === "object" && ("field" in sort || op === "count") && ["count", "min", "max"].includes(op);
|
|
105
|
+
if (!kept)
|
|
106
|
+
throw new InputError(
|
|
107
|
+
`Vega-Lite drops the ${channel} sort ${JSON.stringify(given)}${given === sort ? "" : ` (${JSON.stringify(sort)})`} once a layer is added; sort with an explicit list (sort: [...]) or by a field with op "count", "min" or "max", then add the marks`
|
|
108
|
+
);
|
|
109
|
+
return op === "count" ? countOrder(spec, u, enc, sort.order, channel) : sort;
|
|
110
|
+
}
|
|
111
|
+
function encodings(spec) {
|
|
112
|
+
const out = {};
|
|
113
|
+
for (const ch of ["x", "y"]) {
|
|
114
|
+
const [u, enc] = unit(spec, ch);
|
|
115
|
+
for (const key of ["aggregate", "bin"]) {
|
|
116
|
+
const v = enc[key];
|
|
117
|
+
if (v !== void 0 && v !== null && v !== false && v !== "binned")
|
|
118
|
+
throw new InputError(
|
|
119
|
+
`the chart's ${ch} encoding has ${key}=${JSON.stringify(v)}, which the logo layer cannot copy; compute it in the data first, encode the result, then add the marks`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const e = { field: enc.field ?? ch, type: enc.type ?? "quantitative" };
|
|
123
|
+
if (enc.timeUnit !== void 0) e.timeUnit = enc.timeUnit;
|
|
124
|
+
if (DISCRETE.has(String(e.type)) && "sort" in enc) e.sort = sortOf(spec, enc, ch, u);
|
|
125
|
+
out[ch] = e;
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
function labelsOf(rows, ps, o) {
|
|
130
|
+
const key = "player" in o ? o.player : o.team;
|
|
131
|
+
return ps.map((p) => placedName(p, o.league, rows[p.index]?.[key]));
|
|
132
|
+
}
|
|
133
|
+
function layerOf(ps, kind, h, chartH, alpha, x, y, labels, embed) {
|
|
134
|
+
const hPx = h * chartH;
|
|
135
|
+
const sources = imageSources(ps, embed);
|
|
136
|
+
const values = ps.map((p, i) => ({
|
|
137
|
+
[unescapeField(String(x.field))]: jsonable(p.x),
|
|
138
|
+
[unescapeField(String(y.field))]: jsonable(p.y),
|
|
139
|
+
[URL]: sources[i],
|
|
140
|
+
[TEAM]: p.id,
|
|
141
|
+
[LABEL]: `${labels[i]} ${kind}`
|
|
142
|
+
}));
|
|
143
|
+
const widest = ps.length ? Math.max(...ps.map(aspect)) : 1;
|
|
144
|
+
return {
|
|
145
|
+
name: `sdvplot_${kind}`,
|
|
146
|
+
data: { values },
|
|
147
|
+
mark: {
|
|
148
|
+
type: "image",
|
|
149
|
+
aria: true,
|
|
150
|
+
width: hPx * widest,
|
|
151
|
+
height: hPx,
|
|
152
|
+
aspect: true,
|
|
153
|
+
tooltip: null,
|
|
154
|
+
opacity: alpha
|
|
155
|
+
},
|
|
156
|
+
encoding: {
|
|
157
|
+
x,
|
|
158
|
+
y,
|
|
159
|
+
url: { field: URL, type: "nominal" },
|
|
160
|
+
description: { field: LABEL, type: "nominal" },
|
|
161
|
+
tooltip: null
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function layered(spec, layer) {
|
|
166
|
+
if (Array.isArray(spec.layer)) {
|
|
167
|
+
const { encoding, transform, ...top2 } = spec;
|
|
168
|
+
if (encoding === void 0 && transform === void 0) return { ...spec, layer: [...spec.layer, layer] };
|
|
169
|
+
const group = {
|
|
170
|
+
...transform !== void 0 ? { transform } : {},
|
|
171
|
+
...encoding !== void 0 ? { encoding } : {}
|
|
172
|
+
};
|
|
173
|
+
return { ...top2, layer: [{ ...group, layer: spec.layer }, layer] };
|
|
174
|
+
}
|
|
175
|
+
const top = {};
|
|
176
|
+
const first = {};
|
|
177
|
+
for (const [k, v] of Object.entries(spec))
|
|
178
|
+
(UNIT_KEYS.includes(k) ? first : top)[k] = v;
|
|
179
|
+
return { ...top, layer: [first, layer] };
|
|
180
|
+
}
|
|
181
|
+
function logoLayer(rows, o) {
|
|
182
|
+
const h = checkHeight(o.height ?? 0.1);
|
|
183
|
+
const a = checkAlpha(o.alpha ?? 1);
|
|
184
|
+
const ps = markPlacements(rows, "logo", o);
|
|
185
|
+
return layerOf(
|
|
186
|
+
ps,
|
|
187
|
+
"logo",
|
|
188
|
+
h,
|
|
189
|
+
o.chartHeight === void 0 ? DEFAULT_HEIGHT : pixels(o.chartHeight, "chartHeight"),
|
|
190
|
+
a,
|
|
191
|
+
{ field: "x", type: o.xType ?? "quantitative" },
|
|
192
|
+
{ field: "y", type: o.yType ?? "quantitative" },
|
|
193
|
+
labelsOf(rows, ps, o),
|
|
194
|
+
o.embed
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
function add(target, rows, kind, o) {
|
|
198
|
+
const h = checkHeight(o.height ?? 0.1);
|
|
199
|
+
const a = checkAlpha(o.alpha ?? 1);
|
|
200
|
+
const spec = specOf(target);
|
|
201
|
+
const enc = encodings(spec);
|
|
202
|
+
const ps = markPlacements(rows, kind, o);
|
|
203
|
+
const base = structuredClone(spec);
|
|
204
|
+
for (const ch of ["x", "y"])
|
|
205
|
+
if (Array.isArray(enc[ch].sort)) targetChannel(base, ch).sort = enc[ch].sort;
|
|
206
|
+
return layered(
|
|
207
|
+
base,
|
|
208
|
+
layerOf(ps, kind, h, chartHeight(spec), a, enc.x, enc.y, labelsOf(rows, ps, o), o.embed)
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
function withLogos(spec, rows, o) {
|
|
212
|
+
return add(spec, rows, "logo", o);
|
|
213
|
+
}
|
|
214
|
+
function withWordmarks(spec, rows, o) {
|
|
215
|
+
return add(spec, rows, "wordmark", o);
|
|
216
|
+
}
|
|
217
|
+
function withHeadshots(spec, rows, o) {
|
|
218
|
+
return add(spec, rows, "headshot", o);
|
|
219
|
+
}
|
|
220
|
+
function named(spec, prefix) {
|
|
221
|
+
return units(spec).filter(
|
|
222
|
+
(u) => typeof u.name === "string" && u.name.startsWith(prefix)
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
function drawnMarks(spec) {
|
|
226
|
+
const s = specOf(spec);
|
|
227
|
+
const ref = chartHeight(s);
|
|
228
|
+
return named(s, "sdvplot_").filter((l) => !l.name.startsWith("sdvplot_axis_")).flatMap((l) => {
|
|
229
|
+
const xk = unescapeField(String(l.encoding.x.field));
|
|
230
|
+
const yk = unescapeField(String(l.encoding.y.field));
|
|
231
|
+
return l.data.values.map(
|
|
232
|
+
(r) => [String(r[TEAM]), r[xk], r[yk], l.mark.height / ref, String(r[URL])]
|
|
233
|
+
);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
var BLANKED = /^indexof\((\[.*?\]), datum\.label\) >= 0/;
|
|
237
|
+
function categoriesOf(spec, u, enc) {
|
|
238
|
+
if (Array.isArray(enc.scale?.domain)) return enc.scale.domain;
|
|
239
|
+
const sort = "sort" in enc ? enc.sort : "ascending";
|
|
240
|
+
const rows = inlineRows(spec, u);
|
|
241
|
+
if (rows === void 0) {
|
|
242
|
+
if (Array.isArray(sort)) return sort;
|
|
243
|
+
throw new InputError(
|
|
244
|
+
"withAxisLogos reads the categories from inline data; give the axis an explicit sort=[...] list"
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const key = unescapeField(String(enc.field));
|
|
248
|
+
const seen = [...new Set(rows.map((r) => r[key]).filter((v) => v !== null && v !== void 0))];
|
|
249
|
+
if (Array.isArray(sort)) return [...sort, ...seen.filter((c) => !sort.includes(c))];
|
|
250
|
+
if (sort === "ascending" || sort === "descending")
|
|
251
|
+
return seen.sort((a, b) => String(a).localeCompare(String(b)) * (sort === "descending" ? -1 : 1));
|
|
252
|
+
return seen;
|
|
253
|
+
}
|
|
254
|
+
function targetChannel(spec, channel) {
|
|
255
|
+
for (const u of units(spec)) {
|
|
256
|
+
const e = u.encoding?.[channel];
|
|
257
|
+
if (typeof e === "object" && e !== null && "field" in e) return e;
|
|
258
|
+
}
|
|
259
|
+
throw new InputError(`the spec has no ${channel} encoding with a field`);
|
|
260
|
+
}
|
|
261
|
+
function withAxisLogos(spec, axis, o) {
|
|
262
|
+
const letter = axisLetter(axis);
|
|
263
|
+
const h = checkHeight(o.height ?? 0.1);
|
|
264
|
+
const s = specOf(spec);
|
|
265
|
+
const [u, enc] = unit(s, letter);
|
|
266
|
+
if (!DISCRETE.has(String(enc.type)))
|
|
267
|
+
throw new InputError(`withAxisLogos needs a nominal or ordinal ${letter} axis (team names on the axis)`);
|
|
268
|
+
if (enc.axis === null) throw new InputError(`the chart's ${letter} axis is hidden (axis: null)`);
|
|
269
|
+
const sort = sortOf(s, enc, letter, u);
|
|
270
|
+
const cats = categoriesOf(s, u, enc);
|
|
271
|
+
const ps = axisPlacements(cats.map(String), letter, o);
|
|
272
|
+
const chartH = chartHeight(s);
|
|
273
|
+
const hPx = h * chartH;
|
|
274
|
+
const widest = ps.length ? Math.max(...ps.map(aspect)) : 1;
|
|
275
|
+
const pos = ps.map((p) => Number(letter === "x" ? p.x : p.y));
|
|
276
|
+
const blank = JSON.stringify(pos.map((i) => String(cats[i])));
|
|
277
|
+
const old = typeof enc.axis === "object" && enc.axis !== null ? enc.axis : {};
|
|
278
|
+
const room = (letter === "x" ? hPx : hPx * widest) + AXIS_GAP;
|
|
279
|
+
const expr = `indexof(${blank}, datum.label) >= 0 ? '' : ${old.labelExpr !== void 0 ? `(${old.labelExpr})` : "datum.label"}`;
|
|
280
|
+
const base = structuredClone(s);
|
|
281
|
+
const target = targetChannel(base, letter);
|
|
282
|
+
target.axis = {
|
|
283
|
+
...old,
|
|
284
|
+
labelExpr: expr,
|
|
285
|
+
labelPadding: (old.labelPadding ?? LABEL_PADDING) + room
|
|
286
|
+
};
|
|
287
|
+
if (Array.isArray(sort)) target.sort = sort;
|
|
288
|
+
const key = unescapeField(String(enc.field));
|
|
289
|
+
const sources = imageSources(ps, o.embed);
|
|
290
|
+
const values = ps.map((p, i) => ({
|
|
291
|
+
[key]: cats[pos[i]],
|
|
292
|
+
[URL]: sources[i],
|
|
293
|
+
[TEAM]: p.id,
|
|
294
|
+
[LABEL]: `${placedName(p, o.league, cats[pos[i]])} ${o.markType ?? "logo"}`
|
|
295
|
+
}));
|
|
296
|
+
const channel = {
|
|
297
|
+
field: enc.field ?? letter,
|
|
298
|
+
type: String(enc.type),
|
|
299
|
+
..."sort" in enc ? { sort } : {}
|
|
300
|
+
};
|
|
301
|
+
const url = { field: URL, type: "nominal" };
|
|
302
|
+
const description = { field: LABEL, type: "nominal" };
|
|
303
|
+
const layer = letter === "x" ? {
|
|
304
|
+
name: "sdvplot_axis_x",
|
|
305
|
+
data: { values },
|
|
306
|
+
mark: {
|
|
307
|
+
type: "image",
|
|
308
|
+
aria: true,
|
|
309
|
+
width: hPx * widest,
|
|
310
|
+
height: hPx,
|
|
311
|
+
aspect: true,
|
|
312
|
+
tooltip: null,
|
|
313
|
+
baseline: "top"
|
|
314
|
+
},
|
|
315
|
+
encoding: { x: channel, y: { value: chartH + AXIS_GAP }, url, description, tooltip: null }
|
|
316
|
+
} : {
|
|
317
|
+
name: "sdvplot_axis_y",
|
|
318
|
+
data: { values },
|
|
319
|
+
mark: {
|
|
320
|
+
type: "image",
|
|
321
|
+
aria: true,
|
|
322
|
+
width: hPx * widest,
|
|
323
|
+
height: hPx,
|
|
324
|
+
aspect: true,
|
|
325
|
+
tooltip: null,
|
|
326
|
+
align: "right"
|
|
327
|
+
},
|
|
328
|
+
encoding: { y: channel, x: { value: -AXIS_GAP }, url, description, tooltip: null }
|
|
329
|
+
};
|
|
330
|
+
return layered(base, layer);
|
|
331
|
+
}
|
|
332
|
+
function teamColorScale(league, teams, o = {}) {
|
|
333
|
+
return {
|
|
334
|
+
domain: teams.map(String),
|
|
335
|
+
range: colorList(league, teams, o).map((c) => c ?? o.fallback ?? "#808080")
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function drawnAxisMarks(spec, axis) {
|
|
339
|
+
const letter = axisLetter(axis);
|
|
340
|
+
const s = specOf(spec);
|
|
341
|
+
const [u, enc] = unit(s, letter);
|
|
342
|
+
const cats = categoriesOf(s, u, enc);
|
|
343
|
+
const ref = chartHeight(s);
|
|
344
|
+
return named(s, `sdvplot_axis_${letter}`).flatMap((l) => {
|
|
345
|
+
const key = unescapeField(String(l.encoding[letter].field));
|
|
346
|
+
return l.data.values.map(
|
|
347
|
+
(r) => [String(r[TEAM]), cats.indexOf(r[key]), l.mark.height / ref]
|
|
348
|
+
);
|
|
349
|
+
}).sort((a, b) => a[1] - b[1]);
|
|
350
|
+
}
|
|
351
|
+
function visibleAxisLabels(spec, axis) {
|
|
352
|
+
const letter = axisLetter(axis);
|
|
353
|
+
const s = specOf(spec);
|
|
354
|
+
const [u, enc] = unit(s, letter);
|
|
355
|
+
const m = BLANKED.exec(String(enc.axis?.labelExpr ?? ""));
|
|
356
|
+
const blanked = new Set(m ? JSON.parse(m[1]) : []);
|
|
357
|
+
return categoriesOf(s, u, enc).map(String).filter((c) => !blanked.has(c));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export { drawnAxisMarks, drawnMarks, logoLayer, teamColorScale, visibleAxisLabels, withAxisLogos, withHeadshots, withLogos, withWordmarks };
|
|
361
|
+
//# sourceMappingURL=vega.js.map
|
|
362
|
+
//# sourceMappingURL=vega.js.map
|
package/dist/vega.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vega.ts"],"names":["top"],"mappings":"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","file":"vega.js","sourcesContent":["/** The Vega-Lite adapter: logos, wordmarks and headshots as a native `image` mark layer on a plain spec object.\n * Pure: vega-lite is never imported at runtime; a NEW layered spec is returned. */\nimport {\n type AxisOptions,\n type HeadshotOptions,\n type MarkOptions,\n type Placement,\n type Row,\n aspect,\n axisLetter,\n axisPlacements,\n checkAlpha,\n checkHeight,\n colorList,\n imageSources,\n markPlacements,\n} from \"./_web.js\";\nimport type { DrawnAxisMark, DrawnMark } from \"./_web.js\";\nimport { InputError, UnsupportedTargetError } from \"./errors.js\";\nimport { placedName } from \"./placement.js\";\nimport type { IdSystem, League, SeasonInput } from \"./types.js\";\nexport type { AxisOptions, DrawnAxisMark, DrawnMark, HeadshotOptions, MarkOptions, Row } from \"./_web.js\";\nexport { embedSources } from \"./_web.js\"; // public: the README tells callers to build `embed` with it\n\n/** Structural types for a Vega-Lite spec: the subset `sdvplot/vega` reads and writes. No runtime import of vega-lite. */\nexport type VegaLiteSpec = Record<string, unknown> & {\n layer?: unknown[];\n encoding?: Record<string, unknown>;\n mark?: unknown;\n width?: unknown;\n height?: unknown;\n config?: Record<string, unknown>;\n data?: unknown;\n datasets?: Record<string, unknown>;\n};\n/** One sdvplot image layer. It never shows a tooltip: `mark.tooltip: null` outranks `config.mark.tooltip` and\n * `config.image.tooltip`, and `encoding.tooltip: null` outranks a parent layer's `encoding.tooltip`. */\nexport interface ImageLayer {\n name: string;\n data: { values: Record<string, unknown>[] };\n mark: {\n type: \"image\";\n aria: true;\n width: number;\n height: number;\n aspect: true;\n tooltip: null;\n opacity?: number;\n align?: \"left\" | \"center\" | \"right\";\n baseline?: \"top\" | \"middle\" | \"bottom\";\n };\n encoding: Record<string, unknown>;\n}\n\nconst DEFAULT_HEIGHT = 300; // px: Vega-Lite's continuous view height when neither chart nor config sets one\nconst AXIS_GAP = 6; // px between the axis line and the axis images (past Vega-Lite's 5 px ticks)\nconst LABEL_PADDING = 2; // px: Vega-Lite's default axis labelPadding\nconst URL = \"sdvplot_url\";\nconst TEAM = \"sdvplot_team\";\nconst LABEL = \"sdvplot_label\"; // the accessible description, e.g. \"KC logo\"; Vega's automatic aria-label would read out the image URL\nconst DISCRETE = new Set([\"nominal\", \"ordinal\"]);\nconst UNIT_KEYS = [\"mark\", \"encoding\", \"transform\", \"params\", \"projection\", \"view\", \"name\"] as const; // what moves into the first layer when a unit spec is wrapped\nconst COMPOSITE: Record<string, string> = {\n facet: \"spec.spec\",\n repeat: \"spec.spec\",\n hconcat: \"hconcat[i]\",\n vconcat: \"vconcat[i]\",\n concat: \"concat[i]\",\n};\n\nexport type VlType = \"quantitative\" | \"nominal\" | \"ordinal\" | \"temporal\";\ntype Enc = Record<string, unknown> & {\n field?: string;\n type?: string;\n sort?: unknown;\n timeUnit?: unknown;\n aggregate?: unknown;\n bin?: unknown;\n stack?: unknown;\n axis?: unknown;\n scale?: { domain?: unknown };\n};\n\nfunction specOf(target: unknown): VegaLiteSpec {\n if (typeof target !== \"object\" || target === null || Array.isArray(target))\n throw new UnsupportedTargetError(\n `sdvplot/vega draws on a Vega-Lite spec object, got ${target === null ? \"null\" : typeof target}`,\n );\n for (const key of Object.keys(COMPOSITE))\n if (key in target)\n throw new InputError(\n `sdvplot cannot draw on a ${key} spec; draw on one of its charts (${COMPOSITE[key]}), then combine`,\n );\n return target as VegaLiteSpec;\n}\nconst jsonable = (v: unknown): unknown =>\n v instanceof Date ? v.toISOString() : typeof v === \"bigint\" ? Number(v) : v;\nconst unescapeField = (f: string): string => f.replace(/\\\\(.)/g, \"$1\"); // \"a\\.b\" → the data column \"a.b\"\n\n/** A spec and every layer inside it, outermost first. */\nfunction units(spec: VegaLiteSpec): VegaLiteSpec[] {\n return [spec, ...(spec.layer ?? []).flatMap((s) => units(s as VegaLiteSpec))];\n}\n/** The first (unit, channel def) encoding `channel` with a field. */\nfunction unit(spec: VegaLiteSpec, channel: \"x\" | \"y\"): [VegaLiteSpec, Enc] {\n for (const u of units(spec)) {\n const e = (u.encoding as Record<string, unknown> | undefined)?.[channel];\n if (typeof e === \"object\" && e !== null && \"field\" in e) return [u, e as Enc];\n }\n return [{}, {}];\n}\nfunction pixels(h: unknown, name: string): number {\n if (typeof h !== \"number\" || !Number.isFinite(h) || h <= 0)\n throw new InputError(\n `sdvplot sizes marks from the chart height; ${name} must be a positive number of pixels, not ${JSON.stringify(h)}`,\n );\n return h;\n}\nfunction chartHeight(spec: VegaLiteSpec): number {\n for (const u of units(spec)) if (u.height !== undefined) return pixels(u.height, \"height\");\n if (DISCRETE.has(String(unit(spec, \"y\")[1].type)))\n throw new InputError(\n \"a discrete y axis is sized by its step; set the chart height in pixels (spec.height)\",\n );\n const h =\n (spec.config?.view as { continuousHeight?: unknown } | undefined)?.continuousHeight ?? DEFAULT_HEIGHT;\n return pixels(h, \"config.view.continuousHeight\");\n}\nconst STACKED_BY_DEFAULT = new Set([\"bar\", \"area\", \"arc\"]); // Vega-Lite stacks a quantitative measure on these marks\n/** Vega-Lite's sort-by-channel shorthand (\"y\", \"-y\") as the field sort it compiles to: the channel's aggregate, else\n * \"sum\" for a stacked measure (a bar, area or arc mark unless the channel sets `stack: null`), else \"min\". */\nfunction byChannel(sort: string, u: VegaLiteSpec): Record<string, unknown> {\n const desc = sort.startsWith(\"-\");\n const def = (u.encoding as Record<string, unknown> | undefined)?.[desc ? sort.slice(1) : sort] as\n | Enc\n | undefined;\n if (def?.field === undefined && def?.aggregate === undefined)\n throw new InputError(\n `the sort ${JSON.stringify(sort)} names a channel without a field; sort with an explicit list (sort: [...])`,\n );\n // a shared encoding on a layered spec is stacked when any layer under it stacks\n const marks = units(u).map((v) =>\n String(typeof v.mark === \"object\" && v.mark !== null ? (v.mark as { type?: unknown }).type : v.mark),\n );\n const stacked =\n def.type === \"quantitative\" &&\n !def.bin &&\n (\"stack\" in def ? Boolean(def.stack) : marks.some((m) => STACKED_BY_DEFAULT.has(m)));\n return {\n ...(def.field !== undefined ? { field: def.field } : {}),\n op: def.aggregate ?? (stacked ? \"sum\" : \"min\"),\n ...(desc ? { order: \"descending\" } : {}),\n };\n}\n/** The rows a unit reads: its own inline values or named dataset, else the top-level ones; undefined for url data. */\nfunction inlineRows(spec: VegaLiteSpec, u: VegaLiteSpec): Record<string, unknown>[] | undefined {\n const data = (u.data ?? spec.data ?? {}) as { name?: string; values?: Record<string, unknown>[] };\n return data.name !== undefined\n ? (spec.datasets?.[data.name] as Record<string, unknown>[] | undefined)\n : data.values;\n}\n/** A count sort as the explicit list Vega-Lite orders the axis by: kept as a count, the image layer's own rows would add\n * to the counts (the layers share the scale). Ties keep their first appearance, as Vega's stable sort does. */\nfunction countOrder(\n spec: VegaLiteSpec,\n u: VegaLiteSpec,\n enc: Enc,\n order: unknown,\n channel: string,\n): unknown[] {\n const rows = inlineRows(spec, u);\n const all = units(spec);\n if (\n rows === undefined ||\n new Set(all.map((v) => v.data).filter((d) => d !== undefined)).size > 1 ||\n all.some((v) => v.transform !== undefined)\n )\n throw new InputError(\n `the ${channel} count sort is kept once a layer is added only on inline data with no transform (one data source); sort with an explicit list (sort: [...]), then add the marks`,\n );\n const key = unescapeField(String(enc.field));\n const counts = new Map<unknown, number>();\n for (const r of rows)\n if (r[key] !== null && r[key] !== undefined) counts.set(r[key], (counts.get(r[key]) ?? 0) + 1);\n const sign = order === \"descending\" ? -1 : 1;\n return [...counts].sort((a, b) => (a[1] - b[1]) * sign).map(([c]) => c);\n}\n/** The discrete axis' sort, when Vega-Lite keeps it once another layer shares the scale (it drops the rest).\n * `u` is the unit encoding the channel: the shorthand (\"-y\") reads its sibling channel and comes back as a field sort,\n * and a count sort comes back as the explicit list (`countOrder`), for both layers. */\nfunction sortOf(spec: VegaLiteSpec, enc: Enc, channel: string, u: VegaLiteSpec): unknown {\n const given = \"sort\" in enc ? enc.sort : \"ascending\";\n const sort =\n typeof given === \"string\" && given !== \"ascending\" && given !== \"descending\"\n ? byChannel(given, u)\n : given;\n const op = String((sort as { op?: unknown } | null)?.op);\n const kept =\n sort === null ||\n sort === \"ascending\" ||\n sort === \"descending\" ||\n Array.isArray(sort) ||\n (typeof sort === \"object\" && (\"field\" in sort || op === \"count\") && [\"count\", \"min\", \"max\"].includes(op));\n if (!kept)\n throw new InputError(\n `Vega-Lite drops the ${channel} sort ${JSON.stringify(given)}${given === sort ? \"\" : ` (${JSON.stringify(sort)})`} once a layer is added; sort with an explicit list (sort: [...]) or by a field with op \"count\", \"min\" or \"max\", then add the marks`,\n );\n return op === \"count\" ? countOrder(spec, u, enc, (sort as { order?: unknown }).order, channel) : sort;\n}\n/** The x and y encodings the layer copies: field, type, timeUnit and (discrete) sort. Aggregate/bin raise. */\nfunction encodings(spec: VegaLiteSpec): { x: Enc; y: Enc } {\n const out = {} as { x: Enc; y: Enc };\n for (const ch of [\"x\", \"y\"] as const) {\n const [u, enc] = unit(spec, ch);\n for (const key of [\"aggregate\", \"bin\"] as const) {\n const v = enc[key];\n if (v !== undefined && v !== null && v !== false && v !== \"binned\")\n throw new InputError(\n `the chart's ${ch} encoding has ${key}=${JSON.stringify(v)}, which the logo layer cannot copy; compute it in the data first, encode the result, then add the marks`,\n );\n }\n const e: Enc = { field: enc.field ?? ch, type: enc.type ?? \"quantitative\" };\n if (enc.timeUnit !== undefined) e.timeUnit = enc.timeUnit;\n if (DISCRETE.has(String(e.type)) && \"sort\" in enc) e.sort = sortOf(spec, enc, ch, u);\n out[ch] = e;\n }\n return out;\n}\n/** What each placed image's accessible description names: the resolved team, or a headshot's own player id (placedName). */\nfunction labelsOf(\n rows: readonly Row[],\n ps: readonly Placement[],\n o: MarkOptions | HeadshotOptions,\n): string[] {\n const key = \"player\" in o ? o.player : o.team;\n return ps.map((p) => placedName(p, o.league, rows[p.index]?.[key]));\n}\nfunction layerOf(\n ps: readonly Placement[],\n kind: string,\n h: number,\n chartH: number,\n alpha: number,\n x: Enc,\n y: Enc,\n labels: readonly string[],\n embed?: ReadonlyMap<string, string>,\n): ImageLayer {\n const hPx = h * chartH;\n const sources = imageSources(ps, embed);\n const values = ps.map((p, i) => ({\n [unescapeField(String(x.field))]: jsonable(p.x),\n [unescapeField(String(y.field))]: jsonable(p.y),\n [URL]: sources[i]!,\n [TEAM]: p.id,\n [LABEL]: `${labels[i]} ${kind}`,\n }));\n const widest = ps.length ? Math.max(...ps.map(aspect)) : 1;\n return {\n name: `sdvplot_${kind}`,\n data: { values },\n mark: {\n type: \"image\",\n aria: true,\n width: hPx * widest,\n height: hPx,\n aspect: true,\n tooltip: null,\n opacity: alpha,\n },\n encoding: {\n x,\n y,\n url: { field: URL, type: \"nominal\" },\n description: { field: LABEL, type: \"nominal\" },\n tooltip: null,\n },\n };\n}\n/** `spec` plus `layer` as a layered spec: a unit spec is wrapped, its unit keys moving into layer[0]; a layered spec\n * gains one layer. A layered spec's top-level encoding and transform move into a group around its own layers, so the\n * image layer inherits neither (a shared colour field would add an empty legend entry for the images). */\nfunction layered(spec: VegaLiteSpec, layer: ImageLayer): VegaLiteSpec {\n if (Array.isArray(spec.layer)) {\n const { encoding, transform, ...top } = spec;\n if (encoding === undefined && transform === undefined) return { ...spec, layer: [...spec.layer, layer] };\n const group = {\n ...(transform !== undefined ? { transform } : {}),\n ...(encoding !== undefined ? { encoding } : {}),\n };\n return { ...top, layer: [{ ...group, layer: spec.layer }, layer] };\n }\n const top: VegaLiteSpec = {};\n const first: VegaLiteSpec = {};\n for (const [k, v] of Object.entries(spec))\n ((UNIT_KEYS as readonly string[]).includes(k) ? first : top)[k] = v;\n return { ...top, layer: [first, layer] };\n}\n\n/** One image layer of team logos to drop into a layer list of your own; its fields are \"x\" and \"y\". It never shows a\n * tooltip, even under `config.mark.tooltip` or a parent layer's `encoding.tooltip`. */\nexport function logoLayer(\n rows: readonly Row[],\n o: MarkOptions & {\n /** The chart height in px that `height` is a fraction of. Default 300 (Vega-Lite's continuous height). */\n chartHeight?: number;\n /** The layer's x encoding type (its field is \"x\"). Default \"quantitative\". */\n xType?: VlType;\n /** The layer's y encoding type (its field is \"y\"). Default \"quantitative\". */\n yType?: VlType;\n },\n): ImageLayer {\n const h = checkHeight(o.height ?? 0.1);\n const a = checkAlpha(o.alpha ?? 1);\n const ps = markPlacements(rows, \"logo\", o);\n return layerOf(\n ps,\n \"logo\",\n h,\n o.chartHeight === undefined ? DEFAULT_HEIGHT : pixels(o.chartHeight, \"chartHeight\"),\n a,\n { field: \"x\", type: o.xType ?? \"quantitative\" },\n { field: \"y\", type: o.yType ?? \"quantitative\" },\n labelsOf(rows, ps, o),\n o.embed,\n );\n}\nfunction add(\n target: unknown,\n rows: readonly Row[],\n kind: \"logo\" | \"wordmark\" | \"headshot\",\n o: MarkOptions | HeadshotOptions,\n): VegaLiteSpec {\n const h = checkHeight(o.height ?? 0.1);\n const a = checkAlpha(o.alpha ?? 1);\n const spec = specOf(target);\n const enc = encodings(spec);\n const ps = markPlacements(rows, kind, o);\n const base = structuredClone(spec);\n for (const ch of [\"x\", \"y\"] as const)\n if (Array.isArray(enc[ch].sort)) targetChannel(base, ch).sort = enc[ch].sort; // a count sort's list (sortOf)\n return layered(\n base,\n layerOf(ps, kind, h, chartHeight(spec), a, enc.x, enc.y, labelsOf(rows, ps, o), o.embed),\n );\n}\n/** Team logos as an image layer at each row's (x, y). The layer never shows a tooltip, even when the spec turns tooltips\n * on for every mark (`config.mark.tooltip`). */\nexport function withLogos(spec: VegaLiteSpec, rows: readonly Row[], o: MarkOptions): VegaLiteSpec;\nexport function withLogos<F extends object>(spec: F, rows: readonly Row[], o: MarkOptions): F;\nexport function withLogos(spec: object, rows: readonly Row[], o: MarkOptions): object {\n return add(spec, rows, \"logo\", o);\n}\n/** Team wordmarks as an image layer at each row's (x, y). The layer never shows a tooltip, even when the spec turns\n * tooltips on for every mark (`config.mark.tooltip`). */\nexport function withWordmarks(spec: VegaLiteSpec, rows: readonly Row[], o: MarkOptions): VegaLiteSpec;\nexport function withWordmarks<F extends object>(spec: F, rows: readonly Row[], o: MarkOptions): F;\nexport function withWordmarks(spec: object, rows: readonly Row[], o: MarkOptions): object {\n return add(spec, rows, \"wordmark\", o);\n}\n/** Player headshots as an image layer at each row's (x, y). The layer never shows a tooltip, even when the spec turns\n * tooltips on for every mark (`config.mark.tooltip`). */\nexport function withHeadshots(spec: VegaLiteSpec, rows: readonly Row[], o: HeadshotOptions): VegaLiteSpec;\nexport function withHeadshots<F extends object>(spec: F, rows: readonly Row[], o: HeadshotOptions): F;\nexport function withHeadshots(spec: object, rows: readonly Row[], o: HeadshotOptions): object {\n return add(spec, rows, \"headshot\", o);\n}\n\nfunction named(spec: VegaLiteSpec, prefix: string): ImageLayer[] {\n return units(spec).filter(\n (u): u is VegaLiteSpec & ImageLayer => typeof u.name === \"string\" && u.name.startsWith(prefix),\n );\n}\n/** Test hook: [teamId, x, y, height, url] per image of the sdvplot layers; height = image px / chart px. */\nexport function drawnMarks(spec: VegaLiteSpec): DrawnMark[] {\n const s = specOf(spec);\n const ref = chartHeight(s);\n return named(s, \"sdvplot_\")\n .filter((l) => !l.name.startsWith(\"sdvplot_axis_\"))\n .flatMap((l) => {\n const xk = unescapeField(String((l.encoding.x as Enc).field));\n const yk = unescapeField(String((l.encoding.y as Enc).field));\n return l.data.values.map(\n (r): DrawnMark => [String(r[TEAM]), r[xk], r[yk], l.mark.height / ref, String(r[URL])],\n );\n });\n}\n\nconst BLANKED = /^indexof\\((\\[.*?\\]), datum\\.label\\) >= 0/;\n\n/** A discrete axis' categories in display order: explicit scale domain or sort list, else the inline data. */\nfunction categoriesOf(spec: VegaLiteSpec, u: VegaLiteSpec, enc: Enc): unknown[] {\n if (Array.isArray(enc.scale?.domain)) return enc.scale.domain;\n const sort = \"sort\" in enc ? enc.sort : \"ascending\";\n const rows = inlineRows(spec, u);\n if (rows === undefined) {\n if (Array.isArray(sort)) return sort;\n throw new InputError(\n \"withAxisLogos reads the categories from inline data; give the axis an explicit sort=[...] list\",\n );\n }\n const key = unescapeField(String(enc.field));\n const seen = [...new Set(rows.map((r) => r[key]).filter((v) => v !== null && v !== undefined))];\n if (Array.isArray(sort)) return [...sort, ...seen.filter((c) => !sort.includes(c))];\n if (sort === \"ascending\" || sort === \"descending\")\n return seen.sort((a, b) => String(a).localeCompare(String(b)) * (sort === \"descending\" ? -1 : 1));\n return seen; // sort null or a field sort: data order\n}\n/** The channel object the spec reads the axis from (the first unit encoding it with a field), inside a deep copy. */\nfunction targetChannel(spec: VegaLiteSpec, channel: \"x\" | \"y\"): Enc {\n for (const u of units(spec)) {\n const e = (u.encoding as Record<string, unknown> | undefined)?.[channel];\n if (typeof e === \"object\" && e !== null && \"field\" in e) return e as Enc;\n }\n throw new InputError(`the spec has no ${channel} encoding with a field`);\n}\n\n/** Team logos (or wordmarks, `markType`) in place of the labels of a nominal or ordinal axis: a `labelExpr` blanks the\n * resolved labels and an image layer draws them. Assumes the default axis orient (x at the bottom, y on the left) and\n * that `height` is the plot height: an axis with `orient: \"top\"` or `\"right\"` gets its logos on the opposite side.\n * The image layer never shows a tooltip, even when the spec turns tooltips on for every mark (`config.mark.tooltip`). */\nexport function withAxisLogos(spec: VegaLiteSpec, axis: \"x\" | \"y\", o: AxisOptions): VegaLiteSpec;\nexport function withAxisLogos<F extends object>(spec: F, axis: \"x\" | \"y\", o: AxisOptions): F;\nexport function withAxisLogos(spec: object, axis: \"x\" | \"y\", o: AxisOptions): object {\n const letter = axisLetter(axis);\n const h = checkHeight(o.height ?? 0.1);\n const s = specOf(spec);\n const [u, enc] = unit(s, letter);\n if (!DISCRETE.has(String(enc.type)))\n throw new InputError(`withAxisLogos needs a nominal or ordinal ${letter} axis (team names on the axis)`);\n if (enc.axis === null) throw new InputError(`the chart's ${letter} axis is hidden (axis: null)`);\n const sort = sortOf(s, enc, letter, u);\n const cats = categoriesOf(s, u, enc);\n const ps = axisPlacements(cats.map(String), letter, o);\n const chartH = chartHeight(s);\n const hPx = h * chartH;\n const widest = ps.length ? Math.max(...ps.map(aspect)) : 1;\n const pos = ps.map((p) => Number(letter === \"x\" ? p.x : p.y));\n const blank = JSON.stringify(pos.map((i) => String(cats[i])));\n const old = (typeof enc.axis === \"object\" && enc.axis !== null ? enc.axis : {}) as Record<\n string,\n unknown\n > & { labelExpr?: string; labelPadding?: number };\n const room = (letter === \"x\" ? hPx : hPx * widest) + AXIS_GAP;\n const expr = `indexof(${blank}, datum.label) >= 0 ? '' : ${old.labelExpr !== undefined ? `(${old.labelExpr})` : \"datum.label\"}`;\n const base = structuredClone(s);\n const target = targetChannel(base, letter);\n target.axis = {\n ...old,\n labelExpr: expr,\n labelPadding: (old.labelPadding ?? LABEL_PADDING) + room,\n };\n if (Array.isArray(sort)) target.sort = sort; // a count sort's list (sortOf)\n const key = unescapeField(String(enc.field));\n const sources = imageSources(ps, o.embed);\n const values = ps.map((p, i) => ({\n [key]: cats[pos[i]!],\n [URL]: sources[i]!,\n [TEAM]: p.id,\n [LABEL]: `${placedName(p, o.league, cats[pos[i]!])} ${o.markType ?? \"logo\"}`,\n }));\n const channel: Enc = {\n field: enc.field ?? letter,\n type: String(enc.type),\n ...(\"sort\" in enc ? { sort } : {}),\n };\n const url = { field: URL, type: \"nominal\" as const };\n const description = { field: LABEL, type: \"nominal\" as const };\n const layer: ImageLayer =\n letter === \"x\"\n ? {\n name: \"sdvplot_axis_x\",\n data: { values },\n mark: {\n type: \"image\",\n aria: true,\n width: hPx * widest,\n height: hPx,\n aspect: true,\n tooltip: null,\n baseline: \"top\",\n },\n encoding: { x: channel, y: { value: chartH + AXIS_GAP }, url, description, tooltip: null },\n }\n : {\n name: \"sdvplot_axis_y\",\n data: { values },\n mark: {\n type: \"image\",\n aria: true,\n width: hPx * widest,\n height: hPx,\n aspect: true,\n tooltip: null,\n align: \"right\",\n },\n encoding: { y: channel, x: { value: -AXIS_GAP }, url, description, tooltip: null },\n };\n return layered(base, layer);\n}\n\n/** `{ domain, range }` for `encoding.color.scale`: the values as given, their team colours. */\nexport function teamColorScale(\n league: League,\n teams: readonly unknown[],\n o: { which?: \"primary\" | \"secondary\"; season?: SeasonInput; idSystem?: IdSystem; fallback?: string } = {},\n): { domain: string[]; range: string[] } {\n return {\n domain: teams.map(String),\n range: colorList(league, teams, o).map((c) => c ?? o.fallback ?? \"#808080\"),\n };\n}\n\n/** Test hook: [teamId, category position, height] per image on `axis`, in tick order. */\nexport function drawnAxisMarks(spec: VegaLiteSpec, axis: \"x\" | \"y\"): DrawnAxisMark[] {\n const letter = axisLetter(axis);\n const s = specOf(spec);\n const [u, enc] = unit(s, letter);\n const cats = categoriesOf(s, u, enc);\n const ref = chartHeight(s);\n return named(s, `sdvplot_axis_${letter}`)\n .flatMap((l) => {\n const key = unescapeField(String((l.encoding[letter] as Enc).field));\n return l.data.values.map(\n (r): DrawnAxisMark => [String(r[TEAM]), cats.indexOf(r[key]), l.mark.height / ref],\n );\n })\n .sort((a, b) => a[1] - b[1]);\n}\n/** Test hook: the labels on `axis` its labelExpr still shows as text. */\nexport function visibleAxisLabels(spec: VegaLiteSpec, axis: \"x\" | \"y\"): string[] {\n const letter = axisLetter(axis);\n const s = specOf(spec);\n const [u, enc] = unit(s, letter);\n const m = BLANKED.exec(String((enc.axis as { labelExpr?: string } | undefined)?.labelExpr ?? \"\"));\n const blanked = new Set<string>(m ? (JSON.parse(m[1]!) as string[]) : []);\n return categoriesOf(s, u, enc)\n .map(String)\n .filter((c) => !blanked.has(c));\n}\n"]}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { W as Which, S as SeasonInput, I as IdSystem, L as League } from './types-C7n6gJF3.js';
|
|
2
|
+
export { e as embedSources } from './_web-D7Aa5Rd8.js';
|
|
3
|
+
|
|
4
|
+
/** `teamColorPalette` options. */
|
|
5
|
+
interface VictoryColorOptions {
|
|
6
|
+
/** "primary" (default) or "secondary" colour. */
|
|
7
|
+
which?: Which;
|
|
8
|
+
/** The season the teams are resolved for (a number or string). */
|
|
9
|
+
season?: SeasonInput;
|
|
10
|
+
/** How the team values are read. Default "auto". */
|
|
11
|
+
idSystem?: IdSystem;
|
|
12
|
+
/** The colour of an unresolved team. Default "#808080". */
|
|
13
|
+
fallback?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The chart's background. Given, a team colour under 3:1 contrast against it is swapped for the team's other
|
|
16
|
+
* colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A
|
|
17
|
+
* colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or
|
|
18
|
+
* the nearest colour to its own (lightness, hue or chroma stepped) that is distinct and still reads; failing that it
|
|
19
|
+
* is kept, with one warning.
|
|
20
|
+
*/
|
|
21
|
+
background?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One colour per team, in order: a `colorScale` for a `VictoryGroup`, `VictoryStack`, `VictoryPie` or
|
|
25
|
+
* `VictoryLegend`, or a series' `style.data.stroke` / `fill`. With `background`, every colour keeps 3:1 contrast
|
|
26
|
+
* against it (dark mode) and aims to stay distinct from the others (when it cannot, it keeps the readable colour and
|
|
27
|
+
* warns once). It has the shape of `sdvplot/echarts`'
|
|
28
|
+
* `teamColorPalette`; `teamTheme` puts the same colours into a Victory theme.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* import { loadLeague } from "@sportsdataverse/sdvplot";
|
|
33
|
+
* import { teamColorPalette } from "@sportsdataverse/sdvplot/victory";
|
|
34
|
+
*
|
|
35
|
+
* await loadLeague("nfl");
|
|
36
|
+
* teamColorPalette("nfl", ["KC", "LAC", "DEN", "LV"], { background: "#181a1b" });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function teamColorPalette(league: League, teams: readonly unknown[], o?: VictoryColorOptions): string[];
|
|
40
|
+
/** `teamTheme` options: the teams, in the order the chart draws them, and an optional theme to build on. */
|
|
41
|
+
interface TeamThemeOptions<T extends object = Record<never, never>> extends VictoryColorOptions {
|
|
42
|
+
/** The league the teams belong to, e.g. "nfl". */
|
|
43
|
+
league: League;
|
|
44
|
+
/** Every team the chart draws, in order: a group's or stack's i-th child takes the i-th colour. */
|
|
45
|
+
teams: readonly unknown[];
|
|
46
|
+
/**
|
|
47
|
+
* The theme to build on, e.g. `VictoryTheme.clean`; its axes, fonts and every other key are kept. Default none: the
|
|
48
|
+
* result then holds only the colours, and Victory draws everything else unstyled.
|
|
49
|
+
*/
|
|
50
|
+
base?: T;
|
|
51
|
+
}
|
|
52
|
+
type Scale = {
|
|
53
|
+
colorScale: string[];
|
|
54
|
+
};
|
|
55
|
+
type Painted<P extends string> = {
|
|
56
|
+
style: {
|
|
57
|
+
data: {
|
|
58
|
+
[K in P]: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/** What `teamTheme` writes into the theme. */
|
|
63
|
+
interface TeamThemeColors {
|
|
64
|
+
group: Scale;
|
|
65
|
+
stack: Scale;
|
|
66
|
+
pie: Scale;
|
|
67
|
+
legend: Scale;
|
|
68
|
+
/** A lone series takes the first team's colour. */
|
|
69
|
+
line: Painted<"stroke">;
|
|
70
|
+
area: Painted<"fill">;
|
|
71
|
+
bar: Painted<"fill">;
|
|
72
|
+
scatter: Painted<"fill">;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A Victory theme from team colours (`teamColorPalette`): the palette as the `colorScale` of every group, stack, pie
|
|
76
|
+
* and legend, so each child of a `VictoryGroup` is drawn in its team's colour, and the first team's colour for a lone
|
|
77
|
+
* line, area, bar or scatter. Built over `base` (a Victory theme), whose other keys and styles are kept. Pass it as a
|
|
78
|
+
* `VictoryChart`'s `theme`. With `background`, every colour keeps 3:1 contrast against it and aims to stay distinct from
|
|
79
|
+
* the others (else the readable colour and one warning); the chart's own background and axis ink are the base theme's to set.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```tsx
|
|
83
|
+
* import { loadLeague } from "@sportsdataverse/sdvplot";
|
|
84
|
+
* import { teamTheme } from "@sportsdataverse/sdvplot/victory";
|
|
85
|
+
* import { VictoryBar, VictoryChart, VictoryGroup, VictoryTheme } from "victory";
|
|
86
|
+
*
|
|
87
|
+
* await loadLeague("nfl");
|
|
88
|
+
* const rows = [
|
|
89
|
+
* { team: "KC", pf: 385 },
|
|
90
|
+
* { team: "BUF", pf: 525 },
|
|
91
|
+
* ];
|
|
92
|
+
* // each of the group's bars in its team's colour
|
|
93
|
+
* <VictoryChart
|
|
94
|
+
* theme={teamTheme({ league: "nfl", teams: rows.map((r) => r.team), base: VictoryTheme.clean })}
|
|
95
|
+
* domainPadding={60}
|
|
96
|
+
* >
|
|
97
|
+
* <VictoryGroup>
|
|
98
|
+
* {rows.map((r) => (
|
|
99
|
+
* <VictoryBar key={r.team} data={[r]} x="team" y="pf" />
|
|
100
|
+
* ))}
|
|
101
|
+
* </VictoryGroup>
|
|
102
|
+
* </VictoryChart>;
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
declare function teamTheme<T extends object = Record<never, never>>(o: TeamThemeOptions<T>): T & TeamThemeColors;
|
|
106
|
+
|
|
107
|
+
export { type TeamThemeColors, type TeamThemeOptions, type VictoryColorOptions, teamColorPalette, teamTheme };
|
package/dist/victory.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { colorPalette } from './chunk-UL5M6KDE.js';
|
|
2
|
+
export { embedSources } from './chunk-UL5M6KDE.js';
|
|
3
|
+
import './chunk-7ULOCCFL.js';
|
|
4
|
+
import './chunk-ZAEQXFJM.js';
|
|
5
|
+
import './chunk-J6R2LEJ7.js';
|
|
6
|
+
import { InputError } from './chunk-E7G7VSLV.js';
|
|
7
|
+
|
|
8
|
+
// src/victory.ts
|
|
9
|
+
function teamColorPalette(league, teams, o = {}) {
|
|
10
|
+
return colorPalette(league, teams, o);
|
|
11
|
+
}
|
|
12
|
+
function teamTheme(o) {
|
|
13
|
+
const { league, teams, base, ...co } = o;
|
|
14
|
+
if (teams.length === 0) throw new InputError("teamTheme needs at least one team");
|
|
15
|
+
const colors = teamColorPalette(league, teams, co);
|
|
16
|
+
const first = colors[0];
|
|
17
|
+
const b = base ?? {};
|
|
18
|
+
const scale = (k) => ({ ...b[k], colorScale: colors });
|
|
19
|
+
const paint = (k, prop) => ({
|
|
20
|
+
...b[k],
|
|
21
|
+
style: { ...b[k]?.style, data: { ...b[k]?.style?.data, [prop]: first } }
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
...b,
|
|
25
|
+
group: scale("group"),
|
|
26
|
+
stack: scale("stack"),
|
|
27
|
+
pie: scale("pie"),
|
|
28
|
+
legend: scale("legend"),
|
|
29
|
+
line: paint("line", "stroke"),
|
|
30
|
+
area: paint("area", "fill"),
|
|
31
|
+
bar: paint("bar", "fill"),
|
|
32
|
+
scatter: paint("scatter", "fill")
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { teamColorPalette, teamTheme };
|
|
37
|
+
//# sourceMappingURL=victory.js.map
|
|
38
|
+
//# sourceMappingURL=victory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/victory.ts"],"names":[],"mappings":";;;;;;;;AA8CO,SAAS,gBAAA,CACd,MAAA,EACA,KAAA,EACA,CAAA,GAAyB,EAAC,EAChB;AACV,EAAA,OAAO,YAAA,CAAa,MAAA,EAAQ,KAAA,EAAO,CAAC,CAAA;AACtC;AA4DO,SAAS,UACd,CAAA,EACqB;AACrB,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,GAAG,IAAG,GAAI,CAAA;AACvC,EAAA,IAAI,MAAM,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,WAAW,mCAAmC,CAAA;AAChF,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,MAAA,EAAQ,KAAA,EAAO,EAAE,CAAA;AACjD,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AAEtB,EAAA,MAAM,CAAA,GAAK,QAAQ,EAAC;AACpB,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,MAAsB,EAAE,GAAG,CAAA,CAAE,CAAC,CAAA,EAAG,UAAA,EAAY,MAAA,EAAO,CAAA;AACnE,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAW,IAAA,MAAoC;AAAA,IAC5D,GAAG,EAAE,CAAC,CAAA;AAAA,IACN,OAAO,EAAE,GAAG,EAAE,CAAC,CAAA,EAAG,OAAO,IAAA,EAAM,EAAE,GAAG,CAAA,CAAE,CAAC,GAAG,KAAA,EAAO,IAAA,EAAM,CAAC,IAAI,GAAG,OAAM;AAAE,GACzE,CAAA;AACA,EAAA,OAAO;AAAA,IACL,GAAG,CAAA;AAAA,IACH,KAAA,EAAO,MAAM,OAAO,CAAA;AAAA,IACpB,KAAA,EAAO,MAAM,OAAO,CAAA;AAAA,IACpB,GAAA,EAAK,MAAM,KAAK,CAAA;AAAA,IAChB,MAAA,EAAQ,MAAM,QAAQ,CAAA;AAAA,IACtB,IAAA,EAAM,KAAA,CAAM,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAC5B,IAAA,EAAM,KAAA,CAAM,MAAA,EAAQ,MAAM,CAAA;AAAA,IAC1B,GAAA,EAAK,KAAA,CAAM,KAAA,EAAO,MAAM,CAAA;AAAA,IACxB,OAAA,EAAS,KAAA,CAAM,SAAA,EAAW,MAAM;AAAA,GAClC;AACF","file":"victory.js","sourcesContent":["/**\n * The Victory adapter: team colours as a Victory theme (`teamTheme`) or as a `colorScale` (`teamColorPalette`). Pure:\n * victory is never imported (the theme is a plain object, typed structurally and checked against victory 37.3's own\n * `VictoryThemeDefinition`). Call after `loadLeague(league)` / `preloadAll()`. The logos are components, `<LogoPoint>`\n * (a scatter's `dataComponent`) and `<LogoTick>` (an axis' `tickLabelComponent`), in `sdvplot/react`.\n */\nimport { colorPalette } from \"./_web.js\";\nimport { InputError } from \"./errors.js\";\nimport type { IdSystem, League, SeasonInput, Which } from \"./types.js\";\nexport { embedSources } from \"./_web.js\"; // public: build `<LogoPoint embed>` / `<LogoTick embed>` with it\n\n/** `teamColorPalette` options. */\nexport interface VictoryColorOptions {\n /** \"primary\" (default) or \"secondary\" colour. */\n which?: Which;\n /** The season the teams are resolved for (a number or string). */\n season?: SeasonInput;\n /** How the team values are read. Default \"auto\". */\n idSystem?: IdSystem;\n /** The colour of an unresolved team. Default \"#808080\". */\n fallback?: string;\n /**\n * The chart's background. Given, a team colour under 3:1 contrast against it is swapped for the team's other\n * colour, else moved towards white (on a dark background) or black (a light one) until it reads: dark mode. A\n * colour that would then sit too close to an earlier team's (CIE76 ΔE under 20) takes the team's other colour, or\n * the nearest colour to its own (lightness, hue or chroma stepped) that is distinct and still reads; failing that it\n * is kept, with one warning.\n */\n background?: string;\n}\n/**\n * One colour per team, in order: a `colorScale` for a `VictoryGroup`, `VictoryStack`, `VictoryPie` or\n * `VictoryLegend`, or a series' `style.data.stroke` / `fill`. With `background`, every colour keeps 3:1 contrast\n * against it (dark mode) and aims to stay distinct from the others (when it cannot, it keeps the readable colour and\n * warns once). It has the shape of `sdvplot/echarts`'\n * `teamColorPalette`; `teamTheme` puts the same colours into a Victory theme.\n *\n * @example\n * ```tsx\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamColorPalette } from \"@sportsdataverse/sdvplot/victory\";\n *\n * await loadLeague(\"nfl\");\n * teamColorPalette(\"nfl\", [\"KC\", \"LAC\", \"DEN\", \"LV\"], { background: \"#181a1b\" });\n * ```\n */\nexport function teamColorPalette(\n league: League,\n teams: readonly unknown[],\n o: VictoryColorOptions = {},\n): string[] {\n return colorPalette(league, teams, o);\n}\n\n/** `teamTheme` options: the teams, in the order the chart draws them, and an optional theme to build on. */\nexport interface TeamThemeOptions<T extends object = Record<never, never>> extends VictoryColorOptions {\n /** The league the teams belong to, e.g. \"nfl\". */\n league: League;\n /** Every team the chart draws, in order: a group's or stack's i-th child takes the i-th colour. */\n teams: readonly unknown[];\n /**\n * The theme to build on, e.g. `VictoryTheme.clean`; its axes, fonts and every other key are kept. Default none: the\n * result then holds only the colours, and Victory draws everything else unstyled.\n */\n base?: T;\n}\ntype Scale = { colorScale: string[] };\ntype Painted<P extends string> = { style: { data: { [K in P]: string } } };\n/** What `teamTheme` writes into the theme. */\nexport interface TeamThemeColors {\n group: Scale;\n stack: Scale;\n pie: Scale;\n legend: Scale;\n /** A lone series takes the first team's colour. */\n line: Painted<\"stroke\">;\n area: Painted<\"fill\">;\n bar: Painted<\"fill\">;\n scatter: Painted<\"fill\">;\n}\n\n/**\n * A Victory theme from team colours (`teamColorPalette`): the palette as the `colorScale` of every group, stack, pie\n * and legend, so each child of a `VictoryGroup` is drawn in its team's colour, and the first team's colour for a lone\n * line, area, bar or scatter. Built over `base` (a Victory theme), whose other keys and styles are kept. Pass it as a\n * `VictoryChart`'s `theme`. With `background`, every colour keeps 3:1 contrast against it and aims to stay distinct from\n * the others (else the readable colour and one warning); the chart's own background and axis ink are the base theme's to set.\n *\n * @example\n * ```tsx\n * import { loadLeague } from \"@sportsdataverse/sdvplot\";\n * import { teamTheme } from \"@sportsdataverse/sdvplot/victory\";\n * import { VictoryBar, VictoryChart, VictoryGroup, VictoryTheme } from \"victory\";\n *\n * await loadLeague(\"nfl\");\n * const rows = [\n * { team: \"KC\", pf: 385 },\n * { team: \"BUF\", pf: 525 },\n * ];\n * // each of the group's bars in its team's colour\n * <VictoryChart\n * theme={teamTheme({ league: \"nfl\", teams: rows.map((r) => r.team), base: VictoryTheme.clean })}\n * domainPadding={60}\n * >\n * <VictoryGroup>\n * {rows.map((r) => (\n * <VictoryBar key={r.team} data={[r]} x=\"team\" y=\"pf\" />\n * ))}\n * </VictoryGroup>\n * </VictoryChart>;\n * ```\n */\nexport function teamTheme<T extends object = Record<never, never>>(\n o: TeamThemeOptions<T>,\n): T & TeamThemeColors {\n const { league, teams, base, ...co } = o;\n if (teams.length === 0) throw new InputError(\"teamTheme needs at least one team\");\n const colors = teamColorPalette(league, teams, co);\n const first = colors[0] as string;\n type Piece = { style?: { data?: object } };\n const b = (base ?? {}) as Record<string, Piece | undefined>;\n const scale = (k: string): Scale => ({ ...b[k], colorScale: colors });\n const paint = (k: string, prop: \"stroke\" | \"fill\"): Piece => ({\n ...b[k],\n style: { ...b[k]?.style, data: { ...b[k]?.style?.data, [prop]: first } },\n });\n return {\n ...b,\n group: scale(\"group\"),\n stack: scale(\"stack\"),\n pie: scale(\"pie\"),\n legend: scale(\"legend\"),\n line: paint(\"line\", \"stroke\"),\n area: paint(\"area\", \"fill\"),\n bar: paint(\"bar\", \"fill\"),\n scatter: paint(\"scatter\", \"fill\"),\n } as T & TeamThemeColors;\n}\n"]}
|