@open-tomato/charts 0.0.0-stage → 0.1.1
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/README.md +286 -2
- package/dist/engine/BarChart/BarChart.d.ts +4 -0
- package/dist/engine/BarChart/BarChart.option.d.ts +4 -0
- package/dist/engine/BarChart/index.d.ts +2 -0
- package/dist/engine/BoxPlot/BoxPlot.d.ts +4 -0
- package/dist/engine/BoxPlot/BoxPlot.option.d.ts +4 -0
- package/dist/engine/BoxPlot/index.d.ts +2 -0
- package/dist/engine/Bullet/Bullet.d.ts +4 -0
- package/dist/engine/Bullet/Bullet.option.d.ts +4 -0
- package/dist/engine/Bullet/index.d.ts +2 -0
- package/dist/engine/Donut/Donut.d.ts +4 -0
- package/dist/engine/Donut/Donut.option.d.ts +4 -0
- package/dist/engine/Donut/index.d.ts +2 -0
- package/dist/engine/Gauge/Gauge.d.ts +4 -0
- package/dist/engine/Gauge/Gauge.option.d.ts +4 -0
- package/dist/engine/Gauge/index.d.ts +2 -0
- package/dist/engine/HeatmapGrid/HeatmapGrid.d.ts +4 -0
- package/dist/engine/HeatmapGrid/HeatmapGrid.option.d.ts +4 -0
- package/dist/engine/HeatmapGrid/index.d.ts +2 -0
- package/dist/engine/Histogram/Histogram.d.ts +4 -0
- package/dist/engine/Histogram/Histogram.option.d.ts +4 -0
- package/dist/engine/Histogram/index.d.ts +2 -0
- package/dist/engine/LineChart/LineChart.d.ts +19 -0
- package/dist/engine/LineChart/LineChart.option.d.ts +4 -0
- package/dist/engine/LineChart/index.d.ts +2 -0
- package/dist/engine/NetworkGraph/NetworkGraph.d.ts +4 -0
- package/dist/engine/NetworkGraph/NetworkGraph.option.d.ts +8 -0
- package/dist/engine/NetworkGraph/index.d.ts +2 -0
- package/dist/engine/Nightingale/Nightingale.d.ts +4 -0
- package/dist/engine/Nightingale/Nightingale.option.d.ts +4 -0
- package/dist/engine/Nightingale/index.d.ts +2 -0
- package/dist/engine/Radar/Radar.d.ts +4 -0
- package/dist/engine/Radar/Radar.option.d.ts +4 -0
- package/dist/engine/Radar/index.d.ts +2 -0
- package/dist/engine/Sankey/Sankey.d.ts +4 -0
- package/dist/engine/Sankey/Sankey.option.d.ts +6 -0
- package/dist/engine/Sankey/index.d.ts +2 -0
- package/dist/engine/ScatterChart/ScatterChart.d.ts +4 -0
- package/dist/engine/ScatterChart/ScatterChart.option.d.ts +6 -0
- package/dist/engine/ScatterChart/index.d.ts +2 -0
- package/dist/engine/Sunburst/Sunburst.d.ts +4 -0
- package/dist/engine/Sunburst/Sunburst.option.d.ts +19 -0
- package/dist/engine/Sunburst/index.d.ts +2 -0
- package/dist/engine/Treemap/Treemap.d.ts +4 -0
- package/dist/engine/Treemap/Treemap.option.d.ts +4 -0
- package/dist/engine/Treemap/index.d.ts +2 -0
- package/dist/engine/chrome.d.ts +90 -0
- package/dist/engine/core.d.ts +58 -0
- package/dist/engine/echartsEngine.d.ts +3 -0
- package/dist/engine/fixtures.d.ts +61 -0
- package/dist/engine/headless/headless.d.ts +86 -0
- package/dist/engine/headless/index.d.ts +10 -0
- package/dist/engine/headless/index.js +142 -0
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/shared.d.ts +59 -0
- package/dist/engine/shared.variants.d.ts +40 -0
- package/dist/index-4bxmxw89.js +1786 -0
- package/dist/index-85mb21rn.js +69 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +618 -0
- package/dist/lib/cn.d.ts +7 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/seam/ChartEngineProvider.d.ts +12 -0
- package/dist/seam/FormatProvider.d.ts +25 -0
- package/dist/seam/format.d.ts +171 -0
- package/dist/seam/format.schema.d.ts +14 -0
- package/dist/seam/height.d.ts +15 -0
- package/dist/seam/index.d.ts +12 -0
- package/dist/seam/tones.d.ts +49 -0
- package/dist/seam/types.d.ts +322 -0
- package/dist/seam/useResolvedTokens.d.ts +7 -0
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.js +30 -0
- package/dist/theme/tokens.d.ts +40 -0
- package/package.json +82 -4
|
@@ -0,0 +1,1786 @@
|
|
|
1
|
+
import {
|
|
2
|
+
POLE_TOKENS,
|
|
3
|
+
SEQUENTIAL_TOKENS,
|
|
4
|
+
SERIES_TOKENS,
|
|
5
|
+
STATUS_TOKENS,
|
|
6
|
+
SURFACE_TOKENS,
|
|
7
|
+
THEME_TOKENS,
|
|
8
|
+
TOKEN_PREFIX,
|
|
9
|
+
tokenName,
|
|
10
|
+
tokenNames
|
|
11
|
+
} from "./index-85mb21rn.js";
|
|
12
|
+
|
|
13
|
+
// src/seam/tones.ts
|
|
14
|
+
import { cva } from "class-variance-authority";
|
|
15
|
+
var chartTone = cva("", {
|
|
16
|
+
variants: {
|
|
17
|
+
tone: {
|
|
18
|
+
"series-1": "text-series-1",
|
|
19
|
+
"series-2": "text-series-2",
|
|
20
|
+
"series-3": "text-series-3",
|
|
21
|
+
"series-4": "text-series-4",
|
|
22
|
+
"series-5": "text-series-5",
|
|
23
|
+
"series-6": "text-series-6",
|
|
24
|
+
"series-7": "text-series-7",
|
|
25
|
+
"series-8": "text-series-8",
|
|
26
|
+
good: "text-good",
|
|
27
|
+
warning: "text-warning",
|
|
28
|
+
serious: "text-serious",
|
|
29
|
+
critical: "text-critical",
|
|
30
|
+
"pole-ship": "text-pole-ship",
|
|
31
|
+
"pole-ship-core": "text-pole-ship-core",
|
|
32
|
+
"pole-fail": "text-pole-fail",
|
|
33
|
+
"pole-fail-core": "text-pole-fail-core",
|
|
34
|
+
"pole-base": "text-pole-base",
|
|
35
|
+
"pole-base-core": "text-pole-base-core",
|
|
36
|
+
neutral: "text-ink-2",
|
|
37
|
+
muted: "text-muted"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
defaultVariants: { tone: "series-1" }
|
|
41
|
+
});
|
|
42
|
+
var ALL_TONES = [
|
|
43
|
+
...tokenNames(SERIES_TOKENS),
|
|
44
|
+
...tokenNames(STATUS_TOKENS),
|
|
45
|
+
...tokenNames(POLE_TOKENS),
|
|
46
|
+
"neutral",
|
|
47
|
+
"muted"
|
|
48
|
+
];
|
|
49
|
+
var SEQUENTIAL_STEPS = tokenNames(SEQUENTIAL_TOKENS).filter((name) => name.startsWith("seq-"));
|
|
50
|
+
var CHROME_ROLES = tokenNames(SURFACE_TOKENS);
|
|
51
|
+
var NEUTRAL_TOKEN = "ink-2";
|
|
52
|
+
function tokenOfTone(tone) {
|
|
53
|
+
return tone === "neutral" ? NEUTRAL_TOKEN : tone;
|
|
54
|
+
}
|
|
55
|
+
function toneVar(toneOrRole) {
|
|
56
|
+
const token = toneOrRole === "neutral" ? NEUTRAL_TOKEN : toneOrRole;
|
|
57
|
+
return `var(${TOKEN_PREFIX}${token})`;
|
|
58
|
+
}
|
|
59
|
+
function readTokens() {
|
|
60
|
+
const out = {};
|
|
61
|
+
if (typeof document === "undefined")
|
|
62
|
+
return out;
|
|
63
|
+
const style = getComputedStyle(document.documentElement);
|
|
64
|
+
const names = [...ALL_TONES.map(tokenOfTone), ...SEQUENTIAL_STEPS, ...CHROME_ROLES];
|
|
65
|
+
for (const name of names) {
|
|
66
|
+
out[name] = style.getPropertyValue(`${TOKEN_PREFIX}${name}`).trim();
|
|
67
|
+
}
|
|
68
|
+
for (const tone of ALL_TONES) {
|
|
69
|
+
out[tone] = out[tokenOfTone(tone)] ?? "";
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
function tokensFrom(values) {
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const token of THEME_TOKENS) {
|
|
76
|
+
const name = tokenName(token);
|
|
77
|
+
out[name] = values[name];
|
|
78
|
+
}
|
|
79
|
+
for (const tone of ALL_TONES) {
|
|
80
|
+
out[tone] = out[tokenOfTone(tone)] ?? "";
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/seam/height.ts
|
|
86
|
+
var DEFAULT_CHART_HEIGHT = 220;
|
|
87
|
+
function plotHeightOf(height, measured = 0) {
|
|
88
|
+
if (height === "fill") {
|
|
89
|
+
return measured > 0 ? measured : DEFAULT_CHART_HEIGHT;
|
|
90
|
+
}
|
|
91
|
+
return height ?? DEFAULT_CHART_HEIGHT;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/engine/core.ts
|
|
95
|
+
import {
|
|
96
|
+
BarChart,
|
|
97
|
+
BoxplotChart,
|
|
98
|
+
CustomChart,
|
|
99
|
+
GaugeChart,
|
|
100
|
+
GraphChart,
|
|
101
|
+
HeatmapChart,
|
|
102
|
+
LineChart,
|
|
103
|
+
PieChart,
|
|
104
|
+
RadarChart,
|
|
105
|
+
SankeyChart,
|
|
106
|
+
ScatterChart,
|
|
107
|
+
SunburstChart,
|
|
108
|
+
TreemapChart
|
|
109
|
+
} from "echarts/charts";
|
|
110
|
+
import {
|
|
111
|
+
DataZoomInsideComponent,
|
|
112
|
+
DataZoomSliderComponent,
|
|
113
|
+
GraphicComponent,
|
|
114
|
+
GridComponent,
|
|
115
|
+
MarkLineComponent,
|
|
116
|
+
RadarComponent,
|
|
117
|
+
TooltipComponent,
|
|
118
|
+
VisualMapComponent
|
|
119
|
+
} from "echarts/components";
|
|
120
|
+
import { color as zrColor } from "echarts/core";
|
|
121
|
+
import * as echarts from "echarts/core";
|
|
122
|
+
echarts.use([
|
|
123
|
+
BarChart,
|
|
124
|
+
BoxplotChart,
|
|
125
|
+
CustomChart,
|
|
126
|
+
GaugeChart,
|
|
127
|
+
GraphChart,
|
|
128
|
+
HeatmapChart,
|
|
129
|
+
LineChart,
|
|
130
|
+
PieChart,
|
|
131
|
+
RadarChart,
|
|
132
|
+
SankeyChart,
|
|
133
|
+
ScatterChart,
|
|
134
|
+
SunburstChart,
|
|
135
|
+
TreemapChart,
|
|
136
|
+
DataZoomInsideComponent,
|
|
137
|
+
DataZoomSliderComponent,
|
|
138
|
+
GraphicComponent,
|
|
139
|
+
GridComponent,
|
|
140
|
+
MarkLineComponent,
|
|
141
|
+
RadarComponent,
|
|
142
|
+
TooltipComponent,
|
|
143
|
+
VisualMapComponent
|
|
144
|
+
]);
|
|
145
|
+
var DEFAULT_HEIGHT = DEFAULT_CHART_HEIGHT;
|
|
146
|
+
var BAR_MAX_WIDTH = 24;
|
|
147
|
+
var BAR_RADIUS = 4;
|
|
148
|
+
var BLUR_OPACITY = 0.85;
|
|
149
|
+
var TICK_FONT_SIZE = 11;
|
|
150
|
+
var ANIMATION_DURATION = 400;
|
|
151
|
+
var markHover = {
|
|
152
|
+
emphasis: { focus: "self" },
|
|
153
|
+
blur: { itemStyle: { opacity: BLUR_OPACITY } }
|
|
154
|
+
};
|
|
155
|
+
function paint(tokens, toneOrToken) {
|
|
156
|
+
return tokens[toneOrToken] ?? "";
|
|
157
|
+
}
|
|
158
|
+
function withAlpha(colour, alpha) {
|
|
159
|
+
return zrColor.modifyAlpha(colour, alpha);
|
|
160
|
+
}
|
|
161
|
+
function mix(from, to, share) {
|
|
162
|
+
return zrColor.lerp(Math.min(1, Math.max(0, share)), [from, to]);
|
|
163
|
+
}
|
|
164
|
+
function readableOn(tokens, background) {
|
|
165
|
+
const ink = paint(tokens, "ink");
|
|
166
|
+
const surface = paint(tokens, "surface");
|
|
167
|
+
const contrast = (text) => Math.abs(zrColor.lum(text, 0) - zrColor.lum(background, 0));
|
|
168
|
+
return contrast(ink) >= contrast(surface) ? ink : surface;
|
|
169
|
+
}
|
|
170
|
+
var FALLBACK_FONT_FAMILY = "sans-serif";
|
|
171
|
+
function readFontFamily() {
|
|
172
|
+
if (typeof document === "undefined")
|
|
173
|
+
return FALLBACK_FONT_FAMILY;
|
|
174
|
+
const declared = getComputedStyle(document.documentElement).getPropertyValue("--font-sans").trim();
|
|
175
|
+
return declared === "" ? FALLBACK_FONT_FAMILY : declared;
|
|
176
|
+
}
|
|
177
|
+
function finishOption(option, animate) {
|
|
178
|
+
return {
|
|
179
|
+
useUTC: true,
|
|
180
|
+
animation: animate !== false,
|
|
181
|
+
animationDuration: ANIMATION_DURATION,
|
|
182
|
+
...option,
|
|
183
|
+
textStyle: { fontFamily: readFontFamily() }
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/seam/format.ts
|
|
188
|
+
function formatCompact(value) {
|
|
189
|
+
const abs = Math.abs(value);
|
|
190
|
+
if (abs >= 1e6)
|
|
191
|
+
return `${trimZero((value / 1e6).toFixed(1))}M`;
|
|
192
|
+
if (abs >= 1000)
|
|
193
|
+
return `${trimZero((value / 1000).toFixed(1))}K`;
|
|
194
|
+
if (Number.isInteger(value))
|
|
195
|
+
return String(value);
|
|
196
|
+
return trimZero(value.toFixed(1));
|
|
197
|
+
}
|
|
198
|
+
function formatPercent(fraction) {
|
|
199
|
+
return `${Math.round(fraction * 100)}%`;
|
|
200
|
+
}
|
|
201
|
+
function formatMinutes(minutes) {
|
|
202
|
+
if (minutes >= 60)
|
|
203
|
+
return `${trimZero((minutes / 60).toFixed(1))} h`;
|
|
204
|
+
return `${Math.round(minutes)} min`;
|
|
205
|
+
}
|
|
206
|
+
function formatDay(date) {
|
|
207
|
+
return formatDate(date, "day");
|
|
208
|
+
}
|
|
209
|
+
function formatWeek(date) {
|
|
210
|
+
return formatDate(date, "week");
|
|
211
|
+
}
|
|
212
|
+
var ELAPSED_UNITS = [["d", 86400], ["h", 3600], ["m", 60], ["s", 1]];
|
|
213
|
+
function formatElapsed(seconds) {
|
|
214
|
+
let rest = Math.max(0, Math.floor(seconds));
|
|
215
|
+
const parts = [];
|
|
216
|
+
for (const [unit, size] of ELAPSED_UNITS) {
|
|
217
|
+
const count = Math.floor(rest / size);
|
|
218
|
+
rest -= count * size;
|
|
219
|
+
if (count > 0)
|
|
220
|
+
parts.push(`${count}${unit}`);
|
|
221
|
+
}
|
|
222
|
+
return parts.length > 0 ? parts.join(" ") : "0s";
|
|
223
|
+
}
|
|
224
|
+
var MS_PER_HOUR = 3600000;
|
|
225
|
+
var HOURS_PER_DAY = 24;
|
|
226
|
+
var DAYS_PER_WEEK = 7;
|
|
227
|
+
var AVERAGE_DAYS_PER_MONTH = 30.44;
|
|
228
|
+
var AVERAGE_DAYS_PER_YEAR = 365.25;
|
|
229
|
+
function sameUtcDay(a, b) {
|
|
230
|
+
return a.getUTCFullYear() === b.getUTCFullYear() && a.getUTCMonth() === b.getUTCMonth() && a.getUTCDate() === b.getUTCDate();
|
|
231
|
+
}
|
|
232
|
+
function formatRelative(value, now, locale = DEFAULT_FORMAT_CONTEXT.locale) {
|
|
233
|
+
const date = typeof value === "number" ? new Date(value) : value;
|
|
234
|
+
const reference = typeof now === "number" ? new Date(now) : now;
|
|
235
|
+
if (sameUtcDay(date, reference))
|
|
236
|
+
return formatDate(date, "time", locale);
|
|
237
|
+
const relative = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
238
|
+
const diff = date.getTime() - reference.getTime();
|
|
239
|
+
const sign = diff < 0 ? -1 : 1;
|
|
240
|
+
const hours = Math.abs(diff) / MS_PER_HOUR;
|
|
241
|
+
if (hours < HOURS_PER_DAY)
|
|
242
|
+
return relative.format(sign * Math.max(1, Math.floor(hours)), "hour");
|
|
243
|
+
const days = Math.floor(hours / HOURS_PER_DAY);
|
|
244
|
+
if (days < DAYS_PER_WEEK)
|
|
245
|
+
return relative.format(sign * days, "day");
|
|
246
|
+
const months = Math.floor(days / AVERAGE_DAYS_PER_MONTH);
|
|
247
|
+
if (months < 1)
|
|
248
|
+
return relative.format(sign * Math.floor(days / DAYS_PER_WEEK), "week");
|
|
249
|
+
const years = Math.floor(days / AVERAGE_DAYS_PER_YEAR);
|
|
250
|
+
if (years < 1)
|
|
251
|
+
return relative.format(sign * months, "month");
|
|
252
|
+
return relative.format(sign * years, "year");
|
|
253
|
+
}
|
|
254
|
+
function trimZero(text) {
|
|
255
|
+
return text.replace(/\.0$/, "");
|
|
256
|
+
}
|
|
257
|
+
var VALUE_FORMAT_KINDS = ["raw", "number", "compact", "percent", "money", "unit", "duration", "elapsed", "date", "relative", "custom"];
|
|
258
|
+
var DATE_PATTERNS = ["day", "week", "time", "datetime", "month"];
|
|
259
|
+
var DURATION_UNITS = ["minutes", "seconds", "ms"];
|
|
260
|
+
var PERCENT_BASES = ["fraction", "percent"];
|
|
261
|
+
var UNIT_POSITIONS = ["after", "before"];
|
|
262
|
+
var DEFAULT_FORMAT_CONTEXT = {
|
|
263
|
+
locale: "en-GB",
|
|
264
|
+
currency: "USD",
|
|
265
|
+
timeZone: "UTC",
|
|
266
|
+
customFormatters: {}
|
|
267
|
+
};
|
|
268
|
+
function resolveFormatContext(context = {}) {
|
|
269
|
+
return {
|
|
270
|
+
locale: context.locale ?? DEFAULT_FORMAT_CONTEXT.locale,
|
|
271
|
+
currency: context.currency ?? DEFAULT_FORMAT_CONTEXT.currency,
|
|
272
|
+
timeZone: "UTC",
|
|
273
|
+
customFormatters: context.customFormatters ?? DEFAULT_FORMAT_CONTEXT.customFormatters,
|
|
274
|
+
...context.now === undefined ? {} : { now: context.now }
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
var DAY = { day: "numeric", month: "short", timeZone: "UTC" };
|
|
278
|
+
var TIME = { hour: "2-digit", minute: "2-digit", timeZone: "UTC" };
|
|
279
|
+
var MONTH = { month: "short", year: "numeric", timeZone: "UTC" };
|
|
280
|
+
function formatDate(value, pattern, locale = DEFAULT_FORMAT_CONTEXT.locale) {
|
|
281
|
+
const date = typeof value === "number" ? new Date(value) : value;
|
|
282
|
+
switch (pattern) {
|
|
283
|
+
case "day":
|
|
284
|
+
return date.toLocaleDateString(locale, DAY);
|
|
285
|
+
case "week":
|
|
286
|
+
return `w/c ${date.toLocaleDateString(locale, DAY)}`;
|
|
287
|
+
case "time":
|
|
288
|
+
return date.toLocaleTimeString(locale, TIME);
|
|
289
|
+
case "datetime":
|
|
290
|
+
return `${date.toLocaleDateString(locale, DAY)}, ${date.toLocaleTimeString(locale, TIME)}`;
|
|
291
|
+
case "month":
|
|
292
|
+
return date.toLocaleDateString(locale, MONTH);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function fractionDigits(digits) {
|
|
296
|
+
return digits === undefined ? {} : { minimumFractionDigits: digits, maximumFractionDigits: digits };
|
|
297
|
+
}
|
|
298
|
+
var TO_MINUTES = { minutes: 1, seconds: 1 / 60, ms: 1 / 60000 };
|
|
299
|
+
var TO_SECONDS = { minutes: 60, seconds: 1, ms: 1 / 1000 };
|
|
300
|
+
var BUILDERS = {
|
|
301
|
+
raw: ({ digits }) => (value) => digits === undefined ? String(value) : value.toFixed(digits),
|
|
302
|
+
number: ({ digits, grouping }, { locale }) => {
|
|
303
|
+
const intl = new Intl.NumberFormat(locale, { ...fractionDigits(digits), useGrouping: grouping !== false });
|
|
304
|
+
return (value) => intl.format(value);
|
|
305
|
+
},
|
|
306
|
+
compact: () => formatCompact,
|
|
307
|
+
percent: ({ digits, of, signed }, { locale }) => {
|
|
308
|
+
const intl = new Intl.NumberFormat(locale, {
|
|
309
|
+
style: "percent",
|
|
310
|
+
...fractionDigits(digits ?? 0),
|
|
311
|
+
signDisplay: signed === true ? "exceptZero" : "auto"
|
|
312
|
+
});
|
|
313
|
+
const scale = of === "percent" ? 1 / 100 : 1;
|
|
314
|
+
return (value) => intl.format(value * scale);
|
|
315
|
+
},
|
|
316
|
+
money: ({ currency, digits, compact }, context) => {
|
|
317
|
+
const intl = new Intl.NumberFormat(context.locale, {
|
|
318
|
+
style: "currency",
|
|
319
|
+
currency: currency ?? context.currency,
|
|
320
|
+
...compact === true ? { notation: "compact", maximumFractionDigits: digits ?? 1 } : fractionDigits(digits)
|
|
321
|
+
});
|
|
322
|
+
return (value) => intl.format(value);
|
|
323
|
+
},
|
|
324
|
+
unit: ({ unit, position }, { locale }) => {
|
|
325
|
+
const intl = new Intl.NumberFormat(locale);
|
|
326
|
+
return position === "before" ? (value) => `${unit}${intl.format(value)}` : (value) => `${intl.format(value)} ${unit}`;
|
|
327
|
+
},
|
|
328
|
+
duration: ({ from }) => (value) => formatMinutes(value * TO_MINUTES[from]),
|
|
329
|
+
elapsed: ({ from }) => (value) => formatElapsed(value * TO_SECONDS[from]),
|
|
330
|
+
date: ({ pattern }, { locale }) => (value) => formatDate(value, pattern, locale),
|
|
331
|
+
relative: (_spec, { locale, now }) => (value) => formatRelative(value, now ?? Date.now(), locale),
|
|
332
|
+
custom: ({ id }, { customFormatters }) => {
|
|
333
|
+
const registered = Object.hasOwn(customFormatters, id) ? customFormatters[id] : undefined;
|
|
334
|
+
if (registered === undefined) {
|
|
335
|
+
const known = Object.keys(customFormatters);
|
|
336
|
+
const list = known.length === 0 ? "none are registered" : `registered: ${known.join(", ")}`;
|
|
337
|
+
throw new Error(`formatterFor: no custom formatter "${id}" in the format context (${list})`);
|
|
338
|
+
}
|
|
339
|
+
return registered;
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
function formatterFor(spec, context = {}) {
|
|
343
|
+
const kind = spec.kind;
|
|
344
|
+
if (!Object.hasOwn(BUILDERS, kind))
|
|
345
|
+
throw new Error(`formatterFor: unknown format kind "${kind}"`);
|
|
346
|
+
const build = BUILDERS[spec.kind];
|
|
347
|
+
return build(spec, resolveFormatContext(context));
|
|
348
|
+
}
|
|
349
|
+
var UNITLESS_KINDS = new Set(["raw", "number", "compact"]);
|
|
350
|
+
function formatMeasured(measured, context = {}, specFormat) {
|
|
351
|
+
const { value, unit } = measured;
|
|
352
|
+
const format = measured.format ?? specFormat ?? { kind: "number" };
|
|
353
|
+
const text = formatterFor(format, context)(value);
|
|
354
|
+
return unit !== undefined && UNITLESS_KINDS.has(format.kind) ? `${text} ${unit}` : text;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/engine/chrome.ts
|
|
358
|
+
import { format as echartsFormat } from "echarts/core";
|
|
359
|
+
|
|
360
|
+
// src/engine/shared.variants.ts
|
|
361
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
362
|
+
var chartRootVariants = cva2("block w-full", {
|
|
363
|
+
variants: {
|
|
364
|
+
cursor: {
|
|
365
|
+
auto: "",
|
|
366
|
+
default: "[&_*]:cursor-default!"
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
defaultVariants: { cursor: "auto" }
|
|
370
|
+
});
|
|
371
|
+
var chartFrameVariants = cva2("", {
|
|
372
|
+
variants: {
|
|
373
|
+
fill: { true: "h-full", false: "" }
|
|
374
|
+
},
|
|
375
|
+
defaultVariants: { fill: false }
|
|
376
|
+
});
|
|
377
|
+
var tooltipSurfaceVariants = cva2("pointer-events-none rounded-md bg-surface px-2.5 py-2 text-xs text-ink shadow-md shadow-black/10 ring-1 ring-ring");
|
|
378
|
+
var tooltipHeadingVariants = cva2("mb-1 text-ink-2");
|
|
379
|
+
var tooltipRowVariants = cva2("flex items-center gap-1.5 whitespace-nowrap");
|
|
380
|
+
var tooltipValueVariants = cva2("font-semibold text-ink tabular-nums");
|
|
381
|
+
var tooltipLabelVariants = cva2("text-ink-2");
|
|
382
|
+
var tooltipKeyVariants = cva2("inline-block rounded-full", {
|
|
383
|
+
variants: {
|
|
384
|
+
shape: {
|
|
385
|
+
line: "h-0.5 w-3",
|
|
386
|
+
dot: "size-2"
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
defaultVariants: { shape: "dot" }
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// src/engine/chrome.ts
|
|
393
|
+
function plotGrid(room = {}) {
|
|
394
|
+
return {
|
|
395
|
+
top: room.top ?? 12,
|
|
396
|
+
right: room.right ?? 8,
|
|
397
|
+
bottom: room.bottom ?? 4,
|
|
398
|
+
left: room.left ?? 4,
|
|
399
|
+
outerBoundsMode: "same",
|
|
400
|
+
outerBoundsContain: "axisLabel"
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
function tickLabel(tokens) {
|
|
404
|
+
return { color: paint(tokens, "muted"), fontSize: TICK_FONT_SIZE };
|
|
405
|
+
}
|
|
406
|
+
function valueAxis(tokens, format, bounds = {}) {
|
|
407
|
+
return {
|
|
408
|
+
type: "value",
|
|
409
|
+
min: bounds.min,
|
|
410
|
+
max: bounds.max,
|
|
411
|
+
axisLine: { show: false },
|
|
412
|
+
axisTick: { show: false },
|
|
413
|
+
splitLine: { show: true, lineStyle: { color: paint(tokens, "grid"), width: 1, type: "solid" } },
|
|
414
|
+
axisLabel: { ...tickLabel(tokens), formatter: (value) => format(value) }
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
function given(key, value) {
|
|
418
|
+
if (value === undefined)
|
|
419
|
+
return {};
|
|
420
|
+
return { [key]: value };
|
|
421
|
+
}
|
|
422
|
+
function categoryAxis(tokens, data, extra = {}) {
|
|
423
|
+
return {
|
|
424
|
+
type: "category",
|
|
425
|
+
data: [...data],
|
|
426
|
+
...given("inverse", extra.inverse),
|
|
427
|
+
...given("boundaryGap", extra.boundaryGap),
|
|
428
|
+
...given("position", extra.position),
|
|
429
|
+
axisLine: { show: extra.showLine ?? true, lineStyle: { color: paint(tokens, "baseline"), width: 1 } },
|
|
430
|
+
axisTick: { show: false },
|
|
431
|
+
splitLine: { show: false },
|
|
432
|
+
axisLabel: { ...tickLabel(tokens), show: extra.showLabels ?? true, interval: extra.interval ?? "auto", hideOverlap: true }
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
var DAY_MS = 86400000;
|
|
436
|
+
var WEEK_MS = 7 * DAY_MS;
|
|
437
|
+
var DAYS_SINCE_MONDAY = [6, 0, 1, 2, 3, 4, 5];
|
|
438
|
+
function startOfWeekUtc(ms) {
|
|
439
|
+
const date = new Date(ms);
|
|
440
|
+
const dayStart = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
|
|
441
|
+
return dayStart - (DAYS_SINCE_MONDAY[date.getUTCDay()] ?? 0) * DAY_MS;
|
|
442
|
+
}
|
|
443
|
+
function weekStartsUtc(from, to) {
|
|
444
|
+
const starts = [];
|
|
445
|
+
for (let monday = startOfWeekUtc(from);monday <= to; monday += WEEK_MS)
|
|
446
|
+
starts.push(monday);
|
|
447
|
+
return starts;
|
|
448
|
+
}
|
|
449
|
+
function timeAxis(tokens, xFormat, ticks) {
|
|
450
|
+
const formatter = (value) => xFormat(new Date(value));
|
|
451
|
+
const label = { ...tickLabel(tokens), formatter, hideOverlap: true };
|
|
452
|
+
const chrome = {
|
|
453
|
+
axisLine: { show: true, lineStyle: { color: paint(tokens, "baseline"), width: 1 } },
|
|
454
|
+
axisTick: { show: false },
|
|
455
|
+
splitLine: { show: false }
|
|
456
|
+
};
|
|
457
|
+
if (ticks === undefined)
|
|
458
|
+
return { type: "time", ...chrome, axisLabel: label };
|
|
459
|
+
return {
|
|
460
|
+
type: "time",
|
|
461
|
+
min: startOfWeekUtc(ticks.from),
|
|
462
|
+
...chrome,
|
|
463
|
+
axisLabel: { ...label, customValues: weekStartsUtc(ticks.from, ticks.to) }
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function referenceLine(tokens, axis, value, label, labelAt = "end") {
|
|
467
|
+
return {
|
|
468
|
+
silent: true,
|
|
469
|
+
symbol: "none",
|
|
470
|
+
animation: false,
|
|
471
|
+
lineStyle: { color: paint(tokens, "ink-2"), width: 1, type: "solid" },
|
|
472
|
+
label: {
|
|
473
|
+
show: true,
|
|
474
|
+
position: labelAt,
|
|
475
|
+
color: paint(tokens, "ink-2"),
|
|
476
|
+
fontSize: TICK_FONT_SIZE,
|
|
477
|
+
formatter: () => label
|
|
478
|
+
},
|
|
479
|
+
data: [axis === "yAxis" ? { yAxis: value } : { xAxis: value }]
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function referenceLabelRoom(label) {
|
|
483
|
+
return Math.ceil(echartsFormat.getTextRect(label, `${TICK_FONT_SIZE}px ${readFontFamily()}`).width) + 12;
|
|
484
|
+
}
|
|
485
|
+
function tooltipChrome(trigger) {
|
|
486
|
+
return {
|
|
487
|
+
trigger,
|
|
488
|
+
confine: true,
|
|
489
|
+
backgroundColor: "transparent",
|
|
490
|
+
borderWidth: 0,
|
|
491
|
+
padding: 0,
|
|
492
|
+
shadowBlur: 0,
|
|
493
|
+
extraCssText: "box-shadow: none;",
|
|
494
|
+
transitionDuration: 0.1
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function crosshair(tokens) {
|
|
498
|
+
return { type: "line", snap: true, lineStyle: { color: paint(tokens, "grid"), width: 1, type: "solid" }, label: { show: false } };
|
|
499
|
+
}
|
|
500
|
+
function element(tag, className, text) {
|
|
501
|
+
const node = document.createElement(tag);
|
|
502
|
+
node.className = className;
|
|
503
|
+
if (text !== undefined)
|
|
504
|
+
node.textContent = text;
|
|
505
|
+
return node;
|
|
506
|
+
}
|
|
507
|
+
function keyNode(colour, shape) {
|
|
508
|
+
const node = element("span", tooltipKeyVariants({ shape }));
|
|
509
|
+
node.style.background = colour;
|
|
510
|
+
return node;
|
|
511
|
+
}
|
|
512
|
+
function tooltipNode(heading, rows) {
|
|
513
|
+
const root = element("div", tooltipSurfaceVariants());
|
|
514
|
+
if (heading !== undefined)
|
|
515
|
+
root.append(element("div", tooltipHeadingVariants(), heading));
|
|
516
|
+
for (const row of rows) {
|
|
517
|
+
const line = element("div", tooltipRowVariants());
|
|
518
|
+
if (row.colour !== undefined)
|
|
519
|
+
line.append(keyNode(row.colour, row.key ?? "line"));
|
|
520
|
+
line.append(element("strong", tooltipValueVariants(), row.value), element("span", tooltipLabelVariants(), row.label));
|
|
521
|
+
root.append(line);
|
|
522
|
+
}
|
|
523
|
+
return root;
|
|
524
|
+
}
|
|
525
|
+
function firstParam(params) {
|
|
526
|
+
return paramList(params)[0];
|
|
527
|
+
}
|
|
528
|
+
function paramList(params) {
|
|
529
|
+
return Array.isArray(params) ? params : [params];
|
|
530
|
+
}
|
|
531
|
+
function numericAt(value, index) {
|
|
532
|
+
if (Array.isArray(value)) {
|
|
533
|
+
const item = value[index];
|
|
534
|
+
return typeof item === "number" ? item : Number(item);
|
|
535
|
+
}
|
|
536
|
+
return typeof value === "number" ? value : Number(value);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/engine/BarChart/BarChart.option.ts
|
|
540
|
+
function toShares(series, categoryCount) {
|
|
541
|
+
const totals = Array.from({ length: categoryCount }, (_, index) => series.reduce((sum, entry) => sum + (entry.values[index] ?? 0), 0));
|
|
542
|
+
return series.map((entry) => ({
|
|
543
|
+
...entry,
|
|
544
|
+
values: entry.values.map((value, index) => {
|
|
545
|
+
const total = totals[index] ?? 0;
|
|
546
|
+
return total === 0 ? 0 : value / total;
|
|
547
|
+
})
|
|
548
|
+
}));
|
|
549
|
+
}
|
|
550
|
+
function topOfStack(series, categoryCount) {
|
|
551
|
+
return Array.from({ length: categoryCount }, (_, index) => series.reduce((top, entry, seriesIndex) => (entry.values[index] ?? 0) !== 0 ? seriesIndex : top, -1));
|
|
552
|
+
}
|
|
553
|
+
function buildOption(props, tokens) {
|
|
554
|
+
const { categories, mode = "grouped", orientation = "vertical", limit } = props;
|
|
555
|
+
const stacked = mode !== "grouped";
|
|
556
|
+
const format = props.valueFormat ?? (mode === "stacked100" ? formatPercent : formatCompact);
|
|
557
|
+
const drawn = mode === "stacked100" ? toShares(props.series, categories.length) : props.series;
|
|
558
|
+
const tops = topOfStack(drawn, categories.length);
|
|
559
|
+
const horizontal = orientation === "horizontal";
|
|
560
|
+
const dataEnd = horizontal ? [0, BAR_RADIUS, BAR_RADIUS, 0] : [BAR_RADIUS, BAR_RADIUS, 0, 0];
|
|
561
|
+
const square = [0, 0, 0, 0];
|
|
562
|
+
const surface = paint(tokens, "surface");
|
|
563
|
+
const series = drawn.map((entry, seriesIndex) => ({
|
|
564
|
+
type: "bar",
|
|
565
|
+
id: entry.id,
|
|
566
|
+
name: entry.label,
|
|
567
|
+
stack: stacked ? "total" : undefined,
|
|
568
|
+
barMaxWidth: BAR_MAX_WIDTH,
|
|
569
|
+
barGap: 0,
|
|
570
|
+
itemStyle: { color: paint(tokens, entry.tone), borderColor: surface, borderWidth: 1 },
|
|
571
|
+
...markHover,
|
|
572
|
+
data: entry.values.map((value2, index) => ({
|
|
573
|
+
value: value2,
|
|
574
|
+
itemStyle: { borderRadius: !stacked || tops[index] === seriesIndex ? dataEnd : square }
|
|
575
|
+
})),
|
|
576
|
+
markLine: limit && seriesIndex === 0 ? horizontal ? referenceLine(tokens, "xAxis", limit.value, limit.label, "start") : referenceLine(tokens, "yAxis", limit.value, limit.label) : undefined
|
|
577
|
+
}));
|
|
578
|
+
const valueBounds = mode === "stacked100" ? { min: 0, max: 1 } : { max: limit ? (extent) => Math.max(extent.max, limit.value) : undefined };
|
|
579
|
+
const value = valueAxis(tokens, format, valueBounds);
|
|
580
|
+
const category = categoryAxis(tokens, categories, { inverse: horizontal });
|
|
581
|
+
const tooltipFormatter = (params) => {
|
|
582
|
+
const item = firstParam(params);
|
|
583
|
+
const seriesIndex = item?.seriesIndex ?? 0;
|
|
584
|
+
const dataIndex = item?.dataIndex ?? 0;
|
|
585
|
+
const entry = drawn[seriesIndex];
|
|
586
|
+
const raw = props.series[seriesIndex]?.values[dataIndex] ?? 0;
|
|
587
|
+
const shown = entry?.values[dataIndex] ?? 0;
|
|
588
|
+
const rows = [{ value: format(shown), label: entry?.label ?? "", colour: paint(tokens, entry?.tone ?? "series-1"), key: "dot" }];
|
|
589
|
+
const extra = mode === "stacked100" ? [{ value: formatCompact(raw), label: "count" }] : [];
|
|
590
|
+
return tooltipNode(categories[dataIndex], [...rows, ...extra]);
|
|
591
|
+
};
|
|
592
|
+
return {
|
|
593
|
+
grid: plotGrid({ right: limit && !horizontal ? referenceLabelRoom(limit.label) : 12, top: limit && horizontal ? 24 : 12 }),
|
|
594
|
+
xAxis: horizontal ? value : category,
|
|
595
|
+
yAxis: horizontal ? category : value,
|
|
596
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
597
|
+
series
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/engine/BoxPlot/BoxPlot.option.ts
|
|
602
|
+
var BOX_FILL_ALPHA = 0.35;
|
|
603
|
+
var OUTLIER_SIZE = 8;
|
|
604
|
+
function buildOption2(props, tokens) {
|
|
605
|
+
const { groups, unit } = props;
|
|
606
|
+
const format = props.valueFormat ?? formatCompact;
|
|
607
|
+
const tone = paint(tokens, "series-1");
|
|
608
|
+
const ink = paint(tokens, "ink");
|
|
609
|
+
const boxes = {
|
|
610
|
+
type: "boxplot",
|
|
611
|
+
name: unit,
|
|
612
|
+
boxWidth: [BAR_MAX_WIDTH, BAR_MAX_WIDTH],
|
|
613
|
+
itemStyle: { color: withAlpha(tone, BOX_FILL_ALPHA), borderColor: paint(tokens, "ink-2"), borderWidth: 1 },
|
|
614
|
+
...markHover,
|
|
615
|
+
data: groups.map((group) => [group.min, group.q1, group.median, group.q3, group.max])
|
|
616
|
+
};
|
|
617
|
+
const medians = {
|
|
618
|
+
type: "custom",
|
|
619
|
+
name: "median",
|
|
620
|
+
silent: true,
|
|
621
|
+
z: 3,
|
|
622
|
+
renderItem: (_params, api) => {
|
|
623
|
+
const [x = 0, y = 0] = api.coord([api.value(0), api.value(1)]);
|
|
624
|
+
const half = BAR_MAX_WIDTH / 2;
|
|
625
|
+
return {
|
|
626
|
+
type: "line",
|
|
627
|
+
shape: { x1: x - half, y1: y, x2: x + half, y2: y },
|
|
628
|
+
style: { stroke: ink, lineWidth: 2 }
|
|
629
|
+
};
|
|
630
|
+
},
|
|
631
|
+
data: groups.map((group, index) => [index, group.median])
|
|
632
|
+
};
|
|
633
|
+
const outliers = {
|
|
634
|
+
type: "scatter",
|
|
635
|
+
name: "outlier",
|
|
636
|
+
symbolSize: OUTLIER_SIZE,
|
|
637
|
+
itemStyle: { color: tone, borderColor: paint(tokens, "surface"), borderWidth: 2 },
|
|
638
|
+
data: groups.flatMap((group, index) => (group.outliers ?? []).map((value) => [index, value]))
|
|
639
|
+
};
|
|
640
|
+
const tooltipFormatter = (params) => {
|
|
641
|
+
const item = firstParam(params);
|
|
642
|
+
if (item?.seriesType === "scatter") {
|
|
643
|
+
const value = Array.isArray(item.value) ? Number(item.value[1]) : Number(item.value);
|
|
644
|
+
const group2 = groups[Array.isArray(item.value) ? Number(item.value[0]) : 0];
|
|
645
|
+
return tooltipNode(group2?.label, [{ value: `${format(value)} ${unit}`, label: "outlier", colour: tone, key: "dot" }]);
|
|
646
|
+
}
|
|
647
|
+
const group = groups[item?.dataIndex ?? 0];
|
|
648
|
+
if (!group)
|
|
649
|
+
return tooltipNode(undefined, []);
|
|
650
|
+
const row = (value, label) => ({ value: `${format(value)} ${unit}`, label });
|
|
651
|
+
return tooltipNode(group.label, [
|
|
652
|
+
row(group.max, "max"),
|
|
653
|
+
row(group.q3, "q3"),
|
|
654
|
+
row(group.median, "median"),
|
|
655
|
+
row(group.q1, "q1"),
|
|
656
|
+
row(group.min, "min")
|
|
657
|
+
]);
|
|
658
|
+
};
|
|
659
|
+
return {
|
|
660
|
+
grid: plotGrid({ right: 12 }),
|
|
661
|
+
xAxis: categoryAxis(tokens, groups.map((group) => group.label)),
|
|
662
|
+
yAxis: valueAxis(tokens, (value) => format(value), { min: 0 }),
|
|
663
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
664
|
+
series: [boxes, medians, outliers]
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/engine/Bullet/Bullet.option.ts
|
|
669
|
+
var TRACK_HEIGHT = 28;
|
|
670
|
+
var VALUE_BAR_HEIGHT = 8;
|
|
671
|
+
var TEXT_ROOM = 96;
|
|
672
|
+
var AXIS_LABEL_ROOM = 20;
|
|
673
|
+
var VALUE_TO_LABEL = 24;
|
|
674
|
+
var BAND_OPACITY = [0.45, 0.75, 1];
|
|
675
|
+
function buildOption3(props, tokens) {
|
|
676
|
+
const { value, target, max, ranges, label, higherIsBetter = true } = props;
|
|
677
|
+
const fill = props.height === "fill";
|
|
678
|
+
const height = plotHeightOf(props.height);
|
|
679
|
+
const format = props.valueFormat ?? formatCompact;
|
|
680
|
+
const pastTarget = !higherIsBetter && value > target;
|
|
681
|
+
const valueColour = paint(tokens, pastTarget ? "critical" : "series-1");
|
|
682
|
+
const bandEnds = [ranges[0], ranges[1], 1].map((fraction) => fraction * max);
|
|
683
|
+
const bandWidths = bandEnds.map((end, index) => end - (index === 0 ? 0 : bandEnds[index - 1] ?? 0));
|
|
684
|
+
const top = Math.max(0, Math.round((height - TRACK_HEIGHT - AXIS_LABEL_ROOM) / 2));
|
|
685
|
+
const middle = top + TRACK_HEIGHT / 2;
|
|
686
|
+
const valueText = { type: "text", silent: true, style: { text: format(value), fill: paint(tokens, "ink"), fontSize: 20, fontWeight: 600, align: "right" } };
|
|
687
|
+
const labelText = { type: "text", silent: true, style: { text: label, fill: paint(tokens, "muted"), fontSize: TICK_FONT_SIZE, align: "right" } };
|
|
688
|
+
const track = [label];
|
|
689
|
+
const bands = bandWidths.map((width, index) => ({
|
|
690
|
+
type: "bar",
|
|
691
|
+
name: `band-${index}`,
|
|
692
|
+
stack: "bands",
|
|
693
|
+
yAxisIndex: 0,
|
|
694
|
+
barWidth: "100%",
|
|
695
|
+
silent: true,
|
|
696
|
+
itemStyle: { color: paint(tokens, "grid"), opacity: BAND_OPACITY[index] ?? 1 },
|
|
697
|
+
data: [width]
|
|
698
|
+
}));
|
|
699
|
+
const reading = {
|
|
700
|
+
type: "bar",
|
|
701
|
+
name: label,
|
|
702
|
+
yAxisIndex: 1,
|
|
703
|
+
barWidth: VALUE_BAR_HEIGHT,
|
|
704
|
+
itemStyle: { color: valueColour, borderRadius: [0, 2, 2, 0] },
|
|
705
|
+
data: [Math.min(value, max)],
|
|
706
|
+
markLine: {
|
|
707
|
+
silent: true,
|
|
708
|
+
symbol: "none",
|
|
709
|
+
animation: false,
|
|
710
|
+
label: { show: false },
|
|
711
|
+
lineStyle: { color: paint(tokens, "ink"), width: 2, type: "solid" },
|
|
712
|
+
data: [{ xAxis: target }]
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
return {
|
|
716
|
+
grid: { top: fill ? "middle" : top, height: TRACK_HEIGHT, left: 4, right: TEXT_ROOM },
|
|
717
|
+
xAxis: {
|
|
718
|
+
type: "value",
|
|
719
|
+
min: 0,
|
|
720
|
+
max,
|
|
721
|
+
splitLine: { show: false },
|
|
722
|
+
axisLine: { show: false },
|
|
723
|
+
axisTick: { show: false },
|
|
724
|
+
axisLabel: { color: paint(tokens, "muted"), fontSize: TICK_FONT_SIZE, formatter: (tick) => format(tick) }
|
|
725
|
+
},
|
|
726
|
+
yAxis: [
|
|
727
|
+
categoryAxis(tokens, track, { showLine: false, showLabels: false }),
|
|
728
|
+
categoryAxis(tokens, track, { showLine: false, showLabels: false })
|
|
729
|
+
],
|
|
730
|
+
tooltip: {
|
|
731
|
+
...tooltipChrome("item"),
|
|
732
|
+
formatter: () => tooltipNode(label, [
|
|
733
|
+
{ value: format(value), label: "value", colour: valueColour, key: "dot" },
|
|
734
|
+
{ value: format(target), label: "target" }
|
|
735
|
+
])
|
|
736
|
+
},
|
|
737
|
+
graphic: fill ? [{ type: "group", right: 4, top: "middle", children: [{ ...valueText, y: 0 }, { ...labelText, y: VALUE_TO_LABEL }] }] : [
|
|
738
|
+
{ ...valueText, right: 4, top: middle - 18 },
|
|
739
|
+
{ ...labelText, right: 4, top: middle + 6 }
|
|
740
|
+
],
|
|
741
|
+
series: [...bands, reading]
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// src/engine/Donut/Donut.option.ts
|
|
746
|
+
var RADIUS = ["60%", "92%"];
|
|
747
|
+
var RADIUS_WITH_COMPARE = ["65%", "98%"];
|
|
748
|
+
var COMPARE_RADIUS = ["40%", "58%"];
|
|
749
|
+
var COMPARE_ALPHA = 0.6;
|
|
750
|
+
var CURRENT_LABEL = "this period";
|
|
751
|
+
var CENTER_VALUE_SIZE = 24;
|
|
752
|
+
var CENTER_LABEL_SIZE = 12;
|
|
753
|
+
function buildOption4(props, tokens) {
|
|
754
|
+
const { slices, centerValue, centerLabel } = props;
|
|
755
|
+
const format = props.valueFormat ?? formatCompact;
|
|
756
|
+
const total = slices.reduce((sum, slice) => sum + slice.value, 0);
|
|
757
|
+
const centreText = [centerValue === undefined ? "" : `{value|${centerValue}}`, centerLabel === undefined ? "" : `{label|${centerLabel}}`].filter((line) => line !== "").join(`
|
|
758
|
+
`);
|
|
759
|
+
const compare = props.compare;
|
|
760
|
+
const compareTotal = compare ? compare.slices.reduce((sum, slice) => sum + slice.value, 0) : 0;
|
|
761
|
+
const share = (value, of) => formatPercent(of === 0 ? 0 : value / of);
|
|
762
|
+
const tooltipFormatter = (params) => {
|
|
763
|
+
const item = firstParam(params);
|
|
764
|
+
const ring2 = item?.seriesId === "compare" ? compare?.slices : slices;
|
|
765
|
+
const id = ring2?.[item?.dataIndex ?? 0]?.id;
|
|
766
|
+
const current = slices.find((slice) => slice.id === id);
|
|
767
|
+
const previous = compare?.slices.find((slice) => slice.id === id);
|
|
768
|
+
const shown = current ?? previous;
|
|
769
|
+
if (!shown)
|
|
770
|
+
return tooltipNode(undefined, []);
|
|
771
|
+
const colour = paint(tokens, shown.tone);
|
|
772
|
+
const currentRow = current ? [{ value: format(current.value), label: `${CURRENT_LABEL}, ${share(current.value, total)}`, colour, key: "dot" }] : [];
|
|
773
|
+
const previousRow = compare && previous ? [{ value: format(previous.value), label: `${compare.label}, ${share(previous.value, compareTotal)}`, colour: withAlpha(colour, COMPARE_ALPHA), key: "dot" }] : [];
|
|
774
|
+
return tooltipNode(shown.label, compare ? [...currentRow, ...previousRow] : [
|
|
775
|
+
{ value: format(shown.value), label: "value", colour, key: "dot" },
|
|
776
|
+
{ value: share(shown.value, total), label: "share" }
|
|
777
|
+
]);
|
|
778
|
+
};
|
|
779
|
+
const ring = (id, radius, ringSlices, alpha) => ({
|
|
780
|
+
type: "pie",
|
|
781
|
+
id,
|
|
782
|
+
radius,
|
|
783
|
+
center: ["50%", "50%"],
|
|
784
|
+
avoidLabelOverlap: false,
|
|
785
|
+
label: { show: false },
|
|
786
|
+
labelLine: { show: false },
|
|
787
|
+
itemStyle: { borderColor: paint(tokens, "surface"), borderWidth: 2 },
|
|
788
|
+
...markHover,
|
|
789
|
+
emphasis: { ...markHover.emphasis, scale: false },
|
|
790
|
+
data: ringSlices.map((slice) => ({
|
|
791
|
+
name: slice.label,
|
|
792
|
+
value: slice.value,
|
|
793
|
+
itemStyle: { color: alpha === 1 ? paint(tokens, slice.tone) : withAlpha(paint(tokens, slice.tone), alpha) }
|
|
794
|
+
}))
|
|
795
|
+
});
|
|
796
|
+
return {
|
|
797
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
798
|
+
graphic: centreText === "" ? [] : [{
|
|
799
|
+
type: "text",
|
|
800
|
+
left: "center",
|
|
801
|
+
top: "middle",
|
|
802
|
+
silent: true,
|
|
803
|
+
style: {
|
|
804
|
+
text: centreText,
|
|
805
|
+
align: "center",
|
|
806
|
+
rich: {
|
|
807
|
+
value: { fill: paint(tokens, "ink"), fontSize: CENTER_VALUE_SIZE, fontWeight: 600, lineHeight: 30, align: "center" },
|
|
808
|
+
label: { fill: paint(tokens, "muted"), fontSize: CENTER_LABEL_SIZE, lineHeight: 16, align: "center" }
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}],
|
|
812
|
+
series: compare ? [ring("main", RADIUS_WITH_COMPARE, slices, 1), ring("compare", COMPARE_RADIUS, compare.slices, COMPARE_ALPHA)] : [ring("main", RADIUS, slices, 1)]
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// src/engine/Gauge/Gauge.option.ts
|
|
817
|
+
var START_ANGLE = 200;
|
|
818
|
+
var END_ANGLE = -20;
|
|
819
|
+
var RADIUS_SHARE = 0.92;
|
|
820
|
+
var RADIUS2 = `${RADIUS_SHARE * 100}%`;
|
|
821
|
+
var CENTER_Y_SHARE = 0.5 + RADIUS_SHARE / 2 * (1 - Math.sin(20 * Math.PI / 180)) / 2;
|
|
822
|
+
var CENTER = ["50%", `${Math.round(CENTER_Y_SHARE * 1000) / 10}%`];
|
|
823
|
+
var ARC_WIDTH = 12;
|
|
824
|
+
var COMPARE_RADIUS2 = "76%";
|
|
825
|
+
var COMPARE_WIDTH = 4;
|
|
826
|
+
var COMPARE_ALPHA2 = 0.6;
|
|
827
|
+
var MARKER_OVERHANG = 3;
|
|
828
|
+
var VALUE_FONT_SIZE = 28;
|
|
829
|
+
var SUB_FONT_SIZE = 13;
|
|
830
|
+
var LABEL_FONT_SIZE = 12;
|
|
831
|
+
function fillTone(fraction, thresholds) {
|
|
832
|
+
if (fraction > 1)
|
|
833
|
+
return "critical";
|
|
834
|
+
if (!thresholds)
|
|
835
|
+
return "series-1";
|
|
836
|
+
if (fraction >= thresholds.critical)
|
|
837
|
+
return "critical";
|
|
838
|
+
if (fraction >= thresholds.warning)
|
|
839
|
+
return "warning";
|
|
840
|
+
return "series-1";
|
|
841
|
+
}
|
|
842
|
+
function clamp(value, max) {
|
|
843
|
+
return Math.min(Math.max(value, 0), max);
|
|
844
|
+
}
|
|
845
|
+
function arcBase(max) {
|
|
846
|
+
return {
|
|
847
|
+
type: "gauge",
|
|
848
|
+
startAngle: START_ANGLE,
|
|
849
|
+
endAngle: END_ANGLE,
|
|
850
|
+
min: 0,
|
|
851
|
+
max,
|
|
852
|
+
center: CENTER,
|
|
853
|
+
silent: true,
|
|
854
|
+
pointer: { show: false },
|
|
855
|
+
anchor: { show: false },
|
|
856
|
+
axisTick: { show: false },
|
|
857
|
+
splitLine: { show: false },
|
|
858
|
+
axisLabel: { show: false },
|
|
859
|
+
title: { show: false },
|
|
860
|
+
detail: { show: false }
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
function centreText(props, format) {
|
|
864
|
+
const { value, max, label, compare } = props;
|
|
865
|
+
const over = value > max;
|
|
866
|
+
const lines = over ? [`{big|${formatPercent(value / max)}}`, `{sub|${format(value)}}`, `{label|${label}}`] : [`{big|${format(value)}}`, `{label|${label}}`];
|
|
867
|
+
const compareLine = compare ? [`{compare|${compare.label} ${format(compare.value)}}`] : [];
|
|
868
|
+
return [...lines, ...compareLine].join(`
|
|
869
|
+
`);
|
|
870
|
+
}
|
|
871
|
+
function maxMarker(tokens, max) {
|
|
872
|
+
return {
|
|
873
|
+
...arcBase(max),
|
|
874
|
+
startAngle: END_ANGLE,
|
|
875
|
+
endAngle: END_ANGLE,
|
|
876
|
+
radius: RADIUS2,
|
|
877
|
+
splitNumber: 1,
|
|
878
|
+
axisLine: { show: false, lineStyle: { width: 0 } },
|
|
879
|
+
splitLine: {
|
|
880
|
+
show: true,
|
|
881
|
+
distance: -MARKER_OVERHANG,
|
|
882
|
+
length: ARC_WIDTH + 2 * MARKER_OVERHANG,
|
|
883
|
+
lineStyle: { color: paint(tokens, "ink"), width: 2, cap: "butt" }
|
|
884
|
+
},
|
|
885
|
+
z: 3,
|
|
886
|
+
data: [{ value: 0 }]
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
function buildOption5(props, tokens) {
|
|
890
|
+
const { value, max, thresholds, compare } = props;
|
|
891
|
+
const format = props.valueFormat ?? formatCompact;
|
|
892
|
+
const fraction = max === 0 ? 0 : value / max;
|
|
893
|
+
const fill = paint(tokens, fillTone(fraction, thresholds));
|
|
894
|
+
const track = paint(tokens, "grid");
|
|
895
|
+
const main = {
|
|
896
|
+
...arcBase(max),
|
|
897
|
+
radius: RADIUS2,
|
|
898
|
+
progress: { show: true, width: ARC_WIDTH, roundCap: true, itemStyle: { color: fill } },
|
|
899
|
+
axisLine: { roundCap: true, lineStyle: { width: ARC_WIDTH, color: [[1, track]] } },
|
|
900
|
+
detail: {
|
|
901
|
+
show: true,
|
|
902
|
+
valueAnimation: false,
|
|
903
|
+
offsetCenter: [0, compare ? "2%" : "0%"],
|
|
904
|
+
formatter: () => centreText(props, format),
|
|
905
|
+
rich: {
|
|
906
|
+
big: { color: paint(tokens, "ink"), fontSize: VALUE_FONT_SIZE, fontWeight: 600, lineHeight: 34 },
|
|
907
|
+
sub: { color: paint(tokens, "ink-2"), fontSize: SUB_FONT_SIZE, fontWeight: 600, lineHeight: 18 },
|
|
908
|
+
label: { color: paint(tokens, "muted"), fontSize: LABEL_FONT_SIZE, lineHeight: 18 },
|
|
909
|
+
compare: { color: paint(tokens, "ink-2"), fontSize: LABEL_FONT_SIZE, lineHeight: 18 }
|
|
910
|
+
}
|
|
911
|
+
},
|
|
912
|
+
z: 2,
|
|
913
|
+
data: [{ value: clamp(value, max) }]
|
|
914
|
+
};
|
|
915
|
+
const inner = compare ? [{
|
|
916
|
+
...arcBase(max),
|
|
917
|
+
radius: COMPARE_RADIUS2,
|
|
918
|
+
progress: {
|
|
919
|
+
show: true,
|
|
920
|
+
width: COMPARE_WIDTH,
|
|
921
|
+
roundCap: true,
|
|
922
|
+
itemStyle: { color: withAlpha(paint(tokens, "muted"), COMPARE_ALPHA2) }
|
|
923
|
+
},
|
|
924
|
+
axisLine: { roundCap: true, lineStyle: { width: COMPARE_WIDTH, color: [[1, track]] } },
|
|
925
|
+
z: 1,
|
|
926
|
+
data: [{ value: clamp(compare.value, max) }]
|
|
927
|
+
}] : [];
|
|
928
|
+
const marker = value > max ? [maxMarker(tokens, max)] : [];
|
|
929
|
+
return { series: [main, ...inner, ...marker] };
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
// src/engine/HeatmapGrid/HeatmapGrid.option.ts
|
|
933
|
+
var CELL_RADIUS = 2;
|
|
934
|
+
var RING_WIDTH = 2;
|
|
935
|
+
function buildOption6(props, tokens) {
|
|
936
|
+
const { rows, cols, cells, colLabelEvery = 1, unit } = props;
|
|
937
|
+
const format = props.valueFormat ?? formatCompact;
|
|
938
|
+
const ramp = SEQUENTIAL_STEPS.map((step) => paint(tokens, step));
|
|
939
|
+
const { selected } = props;
|
|
940
|
+
const isSelected = (rowIndex, colIndex) => selected?.row === rowIndex && selected.col === colIndex;
|
|
941
|
+
const ring = { borderColor: paint(tokens, "ink"), borderWidth: RING_WIDTH };
|
|
942
|
+
const plain = cells.flatMap((row, rowIndex) => row.map((value, colIndex) => [colIndex, rowIndex, value]).filter((_, colIndex) => !isSelected(rowIndex, colIndex)));
|
|
943
|
+
const picked = selected ? cells[selected.row]?.[selected.col] : undefined;
|
|
944
|
+
const data = picked === undefined || !selected ? plain : [...plain, { value: [selected.col, selected.row, picked], itemStyle: ring }];
|
|
945
|
+
const max = Math.max(1, ...cells.flat());
|
|
946
|
+
const tooltipFormatter = (params) => {
|
|
947
|
+
const value = firstParam(params)?.value;
|
|
948
|
+
const col = cols[numericAt(value, 0)];
|
|
949
|
+
const row = rows[numericAt(value, 1)];
|
|
950
|
+
return tooltipNode(`${row ?? ""} · ${col ?? ""}`, [{ value: format(numericAt(value, 2)), label: unit }]);
|
|
951
|
+
};
|
|
952
|
+
return {
|
|
953
|
+
grid: plotGrid({ right: 4, top: 4 }),
|
|
954
|
+
xAxis: categoryAxis(tokens, cols, { interval: Math.max(0, colLabelEvery - 1), showLine: false, position: "bottom" }),
|
|
955
|
+
yAxis: categoryAxis(tokens, rows, { inverse: true, showLine: false }),
|
|
956
|
+
visualMap: {
|
|
957
|
+
type: "piecewise",
|
|
958
|
+
show: false,
|
|
959
|
+
min: 0,
|
|
960
|
+
max,
|
|
961
|
+
splitNumber: ramp.length,
|
|
962
|
+
inRange: { color: ramp }
|
|
963
|
+
},
|
|
964
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
965
|
+
series: [{
|
|
966
|
+
type: "heatmap",
|
|
967
|
+
name: unit,
|
|
968
|
+
itemStyle: { borderColor: paint(tokens, "surface"), borderWidth: 2, borderRadius: CELL_RADIUS },
|
|
969
|
+
...markHover,
|
|
970
|
+
data
|
|
971
|
+
}]
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// src/engine/Histogram/Histogram.option.ts
|
|
976
|
+
var BIN_GAP_PX = 2;
|
|
977
|
+
function buildOption7(props, tokens) {
|
|
978
|
+
const { bins, unit } = props;
|
|
979
|
+
const format = props.valueFormat ?? formatCompact;
|
|
980
|
+
const fill = paint(tokens, "series-1");
|
|
981
|
+
const edges = [...bins.map((bin) => bin.from), bins.at(-1)?.to ?? 0];
|
|
982
|
+
const edgeLabels = edges.map((edge, index) => index === edges.length - 1 ? `${edge} ${unit}` : String(edge));
|
|
983
|
+
const bands = categoryAxis(tokens, bins.map((bin) => `${bin.from}–${bin.to}`), { showLabels: false });
|
|
984
|
+
const edgeAxis = categoryAxis(tokens, edgeLabels, { showLine: false, boundaryGap: false, position: "bottom" });
|
|
985
|
+
const tooltipFormatter = (params) => {
|
|
986
|
+
const bin = bins[firstParam(params)?.dataIndex ?? 0];
|
|
987
|
+
if (!bin)
|
|
988
|
+
return tooltipNode(undefined, []);
|
|
989
|
+
return tooltipNode(`${bin.from}–${bin.to} ${unit}`, [{ value: format(bin.count), label: "count", colour: fill, key: "dot" }]);
|
|
990
|
+
};
|
|
991
|
+
return {
|
|
992
|
+
grid: plotGrid({ right: 16 }),
|
|
993
|
+
xAxis: [bands, edgeAxis],
|
|
994
|
+
yAxis: valueAxis(tokens, format, { min: 0 }),
|
|
995
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
996
|
+
series: [{
|
|
997
|
+
type: "bar",
|
|
998
|
+
name: "count",
|
|
999
|
+
xAxisIndex: 0,
|
|
1000
|
+
barCategoryGap: BIN_GAP_PX,
|
|
1001
|
+
itemStyle: { color: fill, borderRadius: [BAR_RADIUS, BAR_RADIUS, 0, 0] },
|
|
1002
|
+
...markHover,
|
|
1003
|
+
data: bins.map((bin) => bin.count)
|
|
1004
|
+
}]
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// src/engine/LineChart/LineChart.option.ts
|
|
1009
|
+
var AREA_WASH = 0.1;
|
|
1010
|
+
var HOVER_DOT_SIZE = 10;
|
|
1011
|
+
var SLIDER_HEIGHT = 24;
|
|
1012
|
+
var SLIDER_ROOM = SLIDER_HEIGHT + 12;
|
|
1013
|
+
var SLIDER_FILL_ALPHA = 0.15;
|
|
1014
|
+
function zoomOption(tokens) {
|
|
1015
|
+
const range = { start: 0, end: 100 };
|
|
1016
|
+
const accent = paint(tokens, "series-1");
|
|
1017
|
+
const grid = paint(tokens, "grid");
|
|
1018
|
+
return [
|
|
1019
|
+
{
|
|
1020
|
+
type: "slider",
|
|
1021
|
+
xAxisIndex: 0,
|
|
1022
|
+
filterMode: "none",
|
|
1023
|
+
...range,
|
|
1024
|
+
height: SLIDER_HEIGHT,
|
|
1025
|
+
bottom: 0,
|
|
1026
|
+
left: 8,
|
|
1027
|
+
right: 12,
|
|
1028
|
+
borderColor: paint(tokens, "baseline"),
|
|
1029
|
+
borderRadius: 4,
|
|
1030
|
+
backgroundColor: "transparent",
|
|
1031
|
+
fillerColor: withAlpha(accent, SLIDER_FILL_ALPHA),
|
|
1032
|
+
dataBackground: { lineStyle: { color: grid, width: 1 }, areaStyle: { color: withAlpha(grid, 0.5) } },
|
|
1033
|
+
selectedDataBackground: { lineStyle: { color: accent, width: 1 }, areaStyle: { color: withAlpha(accent, 0.1) } },
|
|
1034
|
+
handleStyle: { color: paint(tokens, "ink-2"), borderColor: paint(tokens, "surface"), borderWidth: 1 },
|
|
1035
|
+
moveHandleSize: 0,
|
|
1036
|
+
brushSelect: false,
|
|
1037
|
+
showDetail: false,
|
|
1038
|
+
emphasis: { handleStyle: { color: paint(tokens, "ink"), borderColor: paint(tokens, "surface") } }
|
|
1039
|
+
},
|
|
1040
|
+
{
|
|
1041
|
+
type: "inside",
|
|
1042
|
+
xAxisIndex: 0,
|
|
1043
|
+
filterMode: "none",
|
|
1044
|
+
...range,
|
|
1045
|
+
zoomOnMouseWheel: "ctrl",
|
|
1046
|
+
moveOnMouseWheel: false,
|
|
1047
|
+
moveOnMouseMove: true
|
|
1048
|
+
}
|
|
1049
|
+
];
|
|
1050
|
+
}
|
|
1051
|
+
function timeTicksOf(props) {
|
|
1052
|
+
if (props.xStep === undefined)
|
|
1053
|
+
return;
|
|
1054
|
+
const times = props.series.flatMap((entry) => entry.points.map((point) => point.x.getTime()));
|
|
1055
|
+
if (times.length === 0)
|
|
1056
|
+
return;
|
|
1057
|
+
return { step: props.xStep, from: Math.min(...times), to: Math.max(...times) };
|
|
1058
|
+
}
|
|
1059
|
+
function buildOption8(props, tokens) {
|
|
1060
|
+
const { variant = "line", baseline } = props;
|
|
1061
|
+
const format = props.valueFormat ?? formatCompact;
|
|
1062
|
+
const xFormat = props.xFormat ?? formatDay;
|
|
1063
|
+
const surface = paint(tokens, "surface");
|
|
1064
|
+
const series = props.series.map((entry, index) => {
|
|
1065
|
+
const colour = paint(tokens, entry.tone);
|
|
1066
|
+
return {
|
|
1067
|
+
type: "line",
|
|
1068
|
+
id: entry.id,
|
|
1069
|
+
name: entry.label,
|
|
1070
|
+
stack: variant === "stacked-area" ? "total" : undefined,
|
|
1071
|
+
symbol: "circle",
|
|
1072
|
+
symbolSize: HOVER_DOT_SIZE,
|
|
1073
|
+
showSymbol: false,
|
|
1074
|
+
lineStyle: { color: colour, width: 2, cap: "round", join: "round" },
|
|
1075
|
+
itemStyle: { color: colour, borderColor: surface, borderWidth: 2 },
|
|
1076
|
+
areaStyle: variant === "line" ? undefined : { color: colour, opacity: AREA_WASH },
|
|
1077
|
+
emphasis: { focus: "none", lineStyle: { width: 2 } },
|
|
1078
|
+
data: entry.points.map((point) => [point.x.getTime(), point.y]),
|
|
1079
|
+
markLine: baseline && index === 0 ? referenceLine(tokens, "yAxis", baseline.value, baseline.label) : undefined
|
|
1080
|
+
};
|
|
1081
|
+
});
|
|
1082
|
+
const tooltipFormatter = (params) => {
|
|
1083
|
+
const items = paramList(params);
|
|
1084
|
+
const time = numericAt(items[0]?.value, 0);
|
|
1085
|
+
const rows = items.map((item) => {
|
|
1086
|
+
const entry = props.series[item.seriesIndex ?? 0];
|
|
1087
|
+
return {
|
|
1088
|
+
value: format(numericAt(item.value, 1)),
|
|
1089
|
+
label: entry?.label ?? "",
|
|
1090
|
+
colour: paint(tokens, entry?.tone ?? "series-1"),
|
|
1091
|
+
key: "line"
|
|
1092
|
+
};
|
|
1093
|
+
});
|
|
1094
|
+
return tooltipNode(Number.isFinite(time) ? xFormat(new Date(time)) : undefined, rows);
|
|
1095
|
+
};
|
|
1096
|
+
const ceiling = baseline ? (extent) => Math.max(extent.max, baseline.value) : undefined;
|
|
1097
|
+
return {
|
|
1098
|
+
grid: plotGrid({ right: baseline ? referenceLabelRoom(baseline.label) : 12, bottom: props.zoom ? SLIDER_ROOM : 4 }),
|
|
1099
|
+
dataZoom: props.zoom ? zoomOption(tokens) : undefined,
|
|
1100
|
+
xAxis: timeAxis(tokens, xFormat, timeTicksOf(props)),
|
|
1101
|
+
yAxis: valueAxis(tokens, format, { min: 0, max: ceiling }),
|
|
1102
|
+
tooltip: { ...tooltipChrome("axis"), axisPointer: crosshair(tokens), formatter: tooltipFormatter },
|
|
1103
|
+
series
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// src/engine/NetworkGraph/NetworkGraph.option.ts
|
|
1108
|
+
var SIZE_FLOOR = 8;
|
|
1109
|
+
var SIZE_STEP = 3;
|
|
1110
|
+
var EDGE_ALPHA = 0.55;
|
|
1111
|
+
var ARROW_SIZE = 6;
|
|
1112
|
+
function sizeOf(node) {
|
|
1113
|
+
return SIZE_FLOOR + (node.value ?? 1) * SIZE_STEP;
|
|
1114
|
+
}
|
|
1115
|
+
function nodeIdOf(data) {
|
|
1116
|
+
return typeof data === "object" && data !== null && "id" in data ? String(data.id) : undefined;
|
|
1117
|
+
}
|
|
1118
|
+
function buildOption9(props, tokens) {
|
|
1119
|
+
const { nodes, links, groupTones } = props;
|
|
1120
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
1121
|
+
const labelOf = (id) => byId.get(id)?.label ?? id;
|
|
1122
|
+
const toneOf = (node) => paint(tokens, groupTones[node.group] ?? "neutral");
|
|
1123
|
+
const dependents = (id) => links.filter((link) => link.source === id).length;
|
|
1124
|
+
const edgeColour = withAlpha(paint(tokens, "muted"), EDGE_ALPHA);
|
|
1125
|
+
const tooltipFormatter = (params) => {
|
|
1126
|
+
const item = firstParam(params);
|
|
1127
|
+
const data = item?.data;
|
|
1128
|
+
if (item?.dataType === "edge" && typeof data === "object" && data !== null && "source" in data && "target" in data) {
|
|
1129
|
+
return tooltipNode(undefined, [{ value: labelOf(String(data.source)), label: `→ ${labelOf(String(data.target))}` }]);
|
|
1130
|
+
}
|
|
1131
|
+
const node = byId.get(nodeIdOf(data) ?? "");
|
|
1132
|
+
if (!node)
|
|
1133
|
+
return tooltipNode(undefined, []);
|
|
1134
|
+
return tooltipNode(node.label, [
|
|
1135
|
+
{ value: String(dependents(node.id)), label: "dependents", colour: toneOf(node), key: "dot" },
|
|
1136
|
+
{ value: node.group, label: "layer" }
|
|
1137
|
+
]);
|
|
1138
|
+
};
|
|
1139
|
+
return {
|
|
1140
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
1141
|
+
series: [{
|
|
1142
|
+
type: "graph",
|
|
1143
|
+
layout: "force",
|
|
1144
|
+
top: 16,
|
|
1145
|
+
bottom: 16,
|
|
1146
|
+
left: 16,
|
|
1147
|
+
right: 96,
|
|
1148
|
+
roam: false,
|
|
1149
|
+
draggable: false,
|
|
1150
|
+
cursor: props.onNodeClick ? "pointer" : "default",
|
|
1151
|
+
force: {
|
|
1152
|
+
initLayout: "circular",
|
|
1153
|
+
repulsion: 420,
|
|
1154
|
+
edgeLength: [80, 150],
|
|
1155
|
+
gravity: 0.08,
|
|
1156
|
+
layoutAnimation: props.animate !== false
|
|
1157
|
+
},
|
|
1158
|
+
edgeSymbol: ["none", "arrow"],
|
|
1159
|
+
edgeSymbolSize: ARROW_SIZE,
|
|
1160
|
+
lineStyle: { color: edgeColour, width: 1, curveness: 0 },
|
|
1161
|
+
itemStyle: { borderColor: paint(tokens, "surface"), borderWidth: 2 },
|
|
1162
|
+
label: {
|
|
1163
|
+
show: true,
|
|
1164
|
+
position: "right",
|
|
1165
|
+
color: paint(tokens, "ink-2"),
|
|
1166
|
+
fontSize: TICK_FONT_SIZE,
|
|
1167
|
+
textBorderColor: paint(tokens, "surface"),
|
|
1168
|
+
textBorderWidth: 2
|
|
1169
|
+
},
|
|
1170
|
+
emphasis: { focus: "adjacency", lineStyle: { width: 1.5, color: paint(tokens, "ink-2") } },
|
|
1171
|
+
blur: { itemStyle: { opacity: 0.3 }, lineStyle: { opacity: 0.15 }, label: { opacity: 0.4 } },
|
|
1172
|
+
data: nodes.map((node) => ({
|
|
1173
|
+
id: node.id,
|
|
1174
|
+
name: node.label,
|
|
1175
|
+
value: node.value ?? 1,
|
|
1176
|
+
symbolSize: sizeOf(node),
|
|
1177
|
+
itemStyle: { color: toneOf(node) }
|
|
1178
|
+
})),
|
|
1179
|
+
links: links.map((link) => ({ source: link.source, target: link.target, value: link.value }))
|
|
1180
|
+
}]
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/engine/Nightingale/Nightingale.option.ts
|
|
1185
|
+
var RADIUS3 = ["8%", "68%"];
|
|
1186
|
+
var LABEL_MIN_SHARE = 0.04;
|
|
1187
|
+
var LABEL_LINE_HEIGHT = 14;
|
|
1188
|
+
function buildOption10(props, tokens) {
|
|
1189
|
+
const { slices, groupTones = {}, unit } = props;
|
|
1190
|
+
const format = props.valueFormat ?? formatCompact;
|
|
1191
|
+
const total = slices.reduce((sum, slice) => sum + slice.value, 0);
|
|
1192
|
+
const shareOf = (value) => total === 0 ? 0 : value / total;
|
|
1193
|
+
const toneOf = (slice) => paint(tokens, slice.tone ?? (slice.group === undefined ? undefined : groupTones[slice.group]) ?? "neutral");
|
|
1194
|
+
const tooltipFormatter = (params) => {
|
|
1195
|
+
const slice = slices[firstParam(params)?.dataIndex ?? -1];
|
|
1196
|
+
if (!slice)
|
|
1197
|
+
return tooltipNode(undefined, []);
|
|
1198
|
+
return tooltipNode(slice.label, [
|
|
1199
|
+
{ value: `${format(slice.value)} ${unit}`, label: slice.group ?? "", colour: toneOf(slice), key: "dot" },
|
|
1200
|
+
{ value: formatPercent(shareOf(slice.value)), label: "of the total" }
|
|
1201
|
+
]);
|
|
1202
|
+
};
|
|
1203
|
+
return {
|
|
1204
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
1205
|
+
series: [{
|
|
1206
|
+
type: "pie",
|
|
1207
|
+
roseType: "area",
|
|
1208
|
+
radius: RADIUS3,
|
|
1209
|
+
center: ["50%", "50%"],
|
|
1210
|
+
cursor: "default",
|
|
1211
|
+
itemStyle: { borderColor: paint(tokens, "surface"), borderWidth: 2 },
|
|
1212
|
+
label: {
|
|
1213
|
+
show: true,
|
|
1214
|
+
position: "outside",
|
|
1215
|
+
color: paint(tokens, "ink-2"),
|
|
1216
|
+
fontSize: TICK_FONT_SIZE,
|
|
1217
|
+
lineHeight: LABEL_LINE_HEIGHT,
|
|
1218
|
+
formatter: (params) => `${params.name}
|
|
1219
|
+
${format(Number(params.value))}`
|
|
1220
|
+
},
|
|
1221
|
+
labelLine: { show: true, length: 6, length2: 6, lineStyle: { color: paint(tokens, "grid"), width: 1 } },
|
|
1222
|
+
...markHover,
|
|
1223
|
+
emphasis: { ...markHover.emphasis, scale: false },
|
|
1224
|
+
data: slices.map((slice) => {
|
|
1225
|
+
const labelled = shareOf(slice.value) >= LABEL_MIN_SHARE;
|
|
1226
|
+
return {
|
|
1227
|
+
id: slice.id,
|
|
1228
|
+
name: slice.label,
|
|
1229
|
+
value: slice.value,
|
|
1230
|
+
itemStyle: { color: toneOf(slice) },
|
|
1231
|
+
label: { show: labelled },
|
|
1232
|
+
labelLine: { show: labelled }
|
|
1233
|
+
};
|
|
1234
|
+
})
|
|
1235
|
+
}]
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// src/engine/Radar/Radar.option.ts
|
|
1240
|
+
var RADIUS_SHARE2 = 0.6;
|
|
1241
|
+
var RADIUS4 = `${RADIUS_SHARE2 * 100}%`;
|
|
1242
|
+
var DEFAULT_MAX = 2;
|
|
1243
|
+
var SPLIT_NUMBER = 4;
|
|
1244
|
+
var START_ANGLE2 = 90;
|
|
1245
|
+
var AREA_ALPHA = 0.1;
|
|
1246
|
+
var HOVER_ALPHA = 0.05;
|
|
1247
|
+
var SYMBOL_SIZE = 6;
|
|
1248
|
+
var POLE_FONT_SIZE = 14;
|
|
1249
|
+
var POLE_LABEL_OFFSET = 52;
|
|
1250
|
+
var AXIS_NAME_GAP = 8;
|
|
1251
|
+
var BASELINE_NAME_GAP = 4;
|
|
1252
|
+
var BAND_COUNT = 12;
|
|
1253
|
+
var RIM_ALPHA = 0.14;
|
|
1254
|
+
var CORE_ALPHA_EMPTY = 0.14;
|
|
1255
|
+
var CORE_ALPHA_FULL = 0.8;
|
|
1256
|
+
var RING_WIDTH_EMPTY = 1;
|
|
1257
|
+
var RING_WIDTH_FULL = 2;
|
|
1258
|
+
var RING_ALPHA_EMPTY = 0.3;
|
|
1259
|
+
var RING_ALPHA_FULL = 0.75;
|
|
1260
|
+
function poleRuns(axes, poles) {
|
|
1261
|
+
return axes.reduce((runs, axis) => {
|
|
1262
|
+
const last = runs.at(-1);
|
|
1263
|
+
if (last && last.id === axis.pole)
|
|
1264
|
+
return [...runs.slice(0, -1), { ...last, count: last.count + 1 }];
|
|
1265
|
+
return [...runs, { id: axis.pole, pole: poles.find((pole) => pole.id === axis.pole), count: 1 }];
|
|
1266
|
+
}, []);
|
|
1267
|
+
}
|
|
1268
|
+
function alignedPie(axisCount, radius = ["0%", RADIUS4]) {
|
|
1269
|
+
const step = 360 / Math.max(1, axisCount);
|
|
1270
|
+
return {
|
|
1271
|
+
type: "pie",
|
|
1272
|
+
radius,
|
|
1273
|
+
center: ["50%", "50%"],
|
|
1274
|
+
startAngle: START_ANGLE2 + step / 2,
|
|
1275
|
+
clockwise: true,
|
|
1276
|
+
avoidLabelOverlap: false,
|
|
1277
|
+
animation: false
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
function confidence(history) {
|
|
1281
|
+
if (!history || history.of <= 0)
|
|
1282
|
+
return 1;
|
|
1283
|
+
return Math.min(1, Math.max(0, history.weeks / history.of));
|
|
1284
|
+
}
|
|
1285
|
+
var lerp = (from, to, share) => from + (to - from) * share;
|
|
1286
|
+
function wedgeBands(runs, axisCount, tokens, baselineShare, history) {
|
|
1287
|
+
const coreAlpha = lerp(CORE_ALPHA_EMPTY, CORE_ALPHA_FULL, history);
|
|
1288
|
+
return Array.from({ length: BAND_COUNT }, (_, band) => {
|
|
1289
|
+
const from = band / BAND_COUNT;
|
|
1290
|
+
const to = (band + 1) / BAND_COUNT;
|
|
1291
|
+
const middle = (from + to) / 2;
|
|
1292
|
+
const inside = middle <= baselineShare;
|
|
1293
|
+
return {
|
|
1294
|
+
...alignedPie(axisCount, [`${from * RADIUS_SHARE2 * 100}%`, `${to * RADIUS_SHARE2 * 100}%`]),
|
|
1295
|
+
id: `band-${band}`,
|
|
1296
|
+
silent: true,
|
|
1297
|
+
z: 0,
|
|
1298
|
+
label: { show: false },
|
|
1299
|
+
labelLine: { show: false },
|
|
1300
|
+
itemStyle: { borderWidth: 0 },
|
|
1301
|
+
data: runs.map((run) => {
|
|
1302
|
+
const core = paint(tokens, run.pole?.coreTone ?? "neutral");
|
|
1303
|
+
const rim = paint(tokens, run.pole?.tone ?? "neutral");
|
|
1304
|
+
return {
|
|
1305
|
+
name: run.id,
|
|
1306
|
+
value: run.count,
|
|
1307
|
+
itemStyle: { color: withAlpha(mix(core, rim, middle), inside ? coreAlpha : RIM_ALPHA) }
|
|
1308
|
+
};
|
|
1309
|
+
})
|
|
1310
|
+
};
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
function buildOption11(props, tokens) {
|
|
1314
|
+
const { axes, poles, series, baseline } = props;
|
|
1315
|
+
const max = props.max ?? DEFAULT_MAX;
|
|
1316
|
+
const format = props.valueFormat ?? formatCompact;
|
|
1317
|
+
const grid = paint(tokens, "grid");
|
|
1318
|
+
const ink = paint(tokens, "ink");
|
|
1319
|
+
const ink2 = paint(tokens, "ink-2");
|
|
1320
|
+
const step = 360 / Math.max(1, axes.length);
|
|
1321
|
+
const history = confidence(props.history);
|
|
1322
|
+
const baselineShare = baseline && baseline.value > 0 && baseline.value <= max ? baseline.value / max : 0;
|
|
1323
|
+
const tooltipFormatter = (params) => {
|
|
1324
|
+
const index = firstParam(params)?.dataIndex ?? -1;
|
|
1325
|
+
const axis = axes[index];
|
|
1326
|
+
if (!axis)
|
|
1327
|
+
return tooltipNode(undefined, []);
|
|
1328
|
+
const pole = poles.find((entry) => entry.id === axis.pole);
|
|
1329
|
+
return tooltipNode([pole?.icon, axis.label].filter(Boolean).join(" "), series.map((entry) => ({
|
|
1330
|
+
value: format(entry.values[index] ?? 0),
|
|
1331
|
+
label: entry.label,
|
|
1332
|
+
colour: paint(tokens, entry.tone),
|
|
1333
|
+
key: "line"
|
|
1334
|
+
})));
|
|
1335
|
+
};
|
|
1336
|
+
const scale = {
|
|
1337
|
+
center: ["50%", "50%"],
|
|
1338
|
+
radius: RADIUS4,
|
|
1339
|
+
startAngle: START_ANGLE2,
|
|
1340
|
+
clockwise: true,
|
|
1341
|
+
shape: "circle",
|
|
1342
|
+
splitNumber: SPLIT_NUMBER,
|
|
1343
|
+
z: 1,
|
|
1344
|
+
indicator: axes.map((axis) => ({ name: axis.label, min: 0, max })),
|
|
1345
|
+
axisName: { color: ink2, fontSize: TICK_FONT_SIZE },
|
|
1346
|
+
axisNameGap: AXIS_NAME_GAP,
|
|
1347
|
+
axisLine: { lineStyle: { color: grid, width: 1 } },
|
|
1348
|
+
splitLine: { lineStyle: { color: grid, width: 1 } },
|
|
1349
|
+
splitArea: { show: false }
|
|
1350
|
+
};
|
|
1351
|
+
const baselineRing = baselineShare > 0 && baseline ? [{
|
|
1352
|
+
center: ["50%", "50%"],
|
|
1353
|
+
radius: `${RADIUS_SHARE2 * 100 * baselineShare}%`,
|
|
1354
|
+
startAngle: START_ANGLE2 + step / 2,
|
|
1355
|
+
shape: "circle",
|
|
1356
|
+
splitNumber: 1,
|
|
1357
|
+
z: 2,
|
|
1358
|
+
indicator: [{ name: baseline.label, min: 0, max: 1 }],
|
|
1359
|
+
axisName: { color: ink2, fontSize: TICK_FONT_SIZE },
|
|
1360
|
+
axisNameGap: BASELINE_NAME_GAP,
|
|
1361
|
+
axisLine: { show: false },
|
|
1362
|
+
splitLine: {
|
|
1363
|
+
lineStyle: {
|
|
1364
|
+
color: withAlpha(ink, lerp(RING_ALPHA_EMPTY, RING_ALPHA_FULL, history)),
|
|
1365
|
+
width: lerp(RING_WIDTH_EMPTY, RING_WIDTH_FULL, history)
|
|
1366
|
+
}
|
|
1367
|
+
},
|
|
1368
|
+
splitArea: { show: false }
|
|
1369
|
+
}] : [];
|
|
1370
|
+
const runs = poleRuns(axes, poles);
|
|
1371
|
+
return {
|
|
1372
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
1373
|
+
radar: [scale, ...baselineRing],
|
|
1374
|
+
series: [
|
|
1375
|
+
...wedgeBands(runs, axes.length, tokens, baselineShare, history),
|
|
1376
|
+
{
|
|
1377
|
+
...alignedPie(axes.length),
|
|
1378
|
+
id: "poles",
|
|
1379
|
+
silent: true,
|
|
1380
|
+
z: 0,
|
|
1381
|
+
itemStyle: { color: "transparent", borderWidth: 0 },
|
|
1382
|
+
label: {
|
|
1383
|
+
show: true,
|
|
1384
|
+
position: "outside",
|
|
1385
|
+
color: ink2,
|
|
1386
|
+
fontSize: POLE_FONT_SIZE,
|
|
1387
|
+
formatter: (params) => {
|
|
1388
|
+
const pole = runs[params.dataIndex]?.pole;
|
|
1389
|
+
return [pole?.icon, pole?.label].filter(Boolean).join(" ");
|
|
1390
|
+
}
|
|
1391
|
+
},
|
|
1392
|
+
labelLine: { show: false, length: POLE_LABEL_OFFSET, length2: 0 },
|
|
1393
|
+
data: runs.map((run) => ({ name: run.id, value: run.count }))
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
type: "radar",
|
|
1397
|
+
id: "shapes",
|
|
1398
|
+
radarIndex: 0,
|
|
1399
|
+
silent: true,
|
|
1400
|
+
z: 3,
|
|
1401
|
+
symbol: "circle",
|
|
1402
|
+
symbolSize: SYMBOL_SIZE,
|
|
1403
|
+
data: series.map((entry) => {
|
|
1404
|
+
const colour = paint(tokens, entry.tone);
|
|
1405
|
+
return {
|
|
1406
|
+
name: entry.label,
|
|
1407
|
+
value: axes.map((_, index) => entry.values[index] ?? 0),
|
|
1408
|
+
itemStyle: { color: colour },
|
|
1409
|
+
lineStyle: { color: colour, width: 2, join: "round", cap: "round" },
|
|
1410
|
+
areaStyle: { color: withAlpha(colour, AREA_ALPHA) }
|
|
1411
|
+
};
|
|
1412
|
+
})
|
|
1413
|
+
},
|
|
1414
|
+
{
|
|
1415
|
+
...alignedPie(axes.length),
|
|
1416
|
+
id: "axes",
|
|
1417
|
+
z: 4,
|
|
1418
|
+
cursor: "default",
|
|
1419
|
+
label: { show: false },
|
|
1420
|
+
labelLine: { show: false },
|
|
1421
|
+
itemStyle: { color: "transparent", borderWidth: 0 },
|
|
1422
|
+
emphasis: { scale: false, itemStyle: { color: withAlpha(ink, HOVER_ALPHA) } },
|
|
1423
|
+
data: axes.map((axis) => ({ name: axis.label, value: 1 }))
|
|
1424
|
+
}
|
|
1425
|
+
]
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
// src/engine/Sankey/Sankey.option.ts
|
|
1430
|
+
var NODE_WIDTH = 10;
|
|
1431
|
+
var NODE_GAP = 10;
|
|
1432
|
+
var LINK_ALPHA = 0.25;
|
|
1433
|
+
var LINK_HOVER_ALPHA = 0.5;
|
|
1434
|
+
var LABEL_GAP = 6;
|
|
1435
|
+
function longestPath(nodes, links) {
|
|
1436
|
+
const memo = new Map;
|
|
1437
|
+
const visiting = new Set;
|
|
1438
|
+
const from = (id) => {
|
|
1439
|
+
const known = memo.get(id);
|
|
1440
|
+
if (known !== undefined)
|
|
1441
|
+
return known;
|
|
1442
|
+
if (visiting.has(id))
|
|
1443
|
+
return 0;
|
|
1444
|
+
visiting.add(id);
|
|
1445
|
+
const length = Math.max(0, ...links.filter((link) => link.source === id).map((link) => 1 + from(link.target)));
|
|
1446
|
+
visiting.delete(id);
|
|
1447
|
+
memo.set(id, length);
|
|
1448
|
+
return length;
|
|
1449
|
+
};
|
|
1450
|
+
return Math.max(0, ...nodes.map((node) => from(node.id)));
|
|
1451
|
+
}
|
|
1452
|
+
function columnsOf(nodes, links, groupOrder) {
|
|
1453
|
+
const present = groupOrder.filter((group) => nodes.some((node) => node.group === group));
|
|
1454
|
+
const span = Math.max(1, longestPath(nodes, links));
|
|
1455
|
+
const step = present.length > 1 ? span / (present.length - 1) : 0;
|
|
1456
|
+
return new Map(nodes.map((node) => [node.id, Math.max(0, present.indexOf(node.group)) * step]));
|
|
1457
|
+
}
|
|
1458
|
+
function buildOption12(props, tokens) {
|
|
1459
|
+
const { nodes, links, groupTones, groupOrder } = props;
|
|
1460
|
+
const format = props.valueFormat ?? formatCompact;
|
|
1461
|
+
const columns = columnsOf(nodes, links, groupOrder);
|
|
1462
|
+
const lastColumn = Math.max(0, ...columns.values());
|
|
1463
|
+
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
1464
|
+
const labelOf = (id) => byId.get(id)?.label ?? id;
|
|
1465
|
+
const toneOf = (node) => paint(tokens, groupTones[node.group] ?? "neutral");
|
|
1466
|
+
const tooltipFormatter = (params) => {
|
|
1467
|
+
const item = firstParam(params);
|
|
1468
|
+
const data = item?.data;
|
|
1469
|
+
if (item?.dataType === "edge" && typeof data === "object" && data !== null && "source" in data && "target" in data) {
|
|
1470
|
+
const source = String(data.source);
|
|
1471
|
+
const target = String(data.target);
|
|
1472
|
+
const value = "value" in data ? Number(data.value) : 0;
|
|
1473
|
+
const sourceNode = byId.get(source);
|
|
1474
|
+
return tooltipNode(`${labelOf(source)} → ${labelOf(target)}`, [
|
|
1475
|
+
{ value: format(value), label: "dependency", colour: sourceNode ? toneOf(sourceNode) : undefined, key: "line" }
|
|
1476
|
+
]);
|
|
1477
|
+
}
|
|
1478
|
+
const id = typeof data === "object" && data !== null && "name" in data ? String(data.name) : "";
|
|
1479
|
+
const node = byId.get(id);
|
|
1480
|
+
if (!node)
|
|
1481
|
+
return tooltipNode(undefined, []);
|
|
1482
|
+
const outgoing = links.filter((link) => link.source === id).length;
|
|
1483
|
+
const incoming = links.filter((link) => link.target === id).length;
|
|
1484
|
+
return tooltipNode(node.label, [
|
|
1485
|
+
{ value: String(outgoing), label: "dependents", colour: toneOf(node), key: "dot" },
|
|
1486
|
+
{ value: String(incoming), label: "dependencies" },
|
|
1487
|
+
{ value: node.group, label: "layer" }
|
|
1488
|
+
]);
|
|
1489
|
+
};
|
|
1490
|
+
return {
|
|
1491
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
1492
|
+
series: [{
|
|
1493
|
+
type: "sankey",
|
|
1494
|
+
orient: "horizontal",
|
|
1495
|
+
top: 8,
|
|
1496
|
+
bottom: 8,
|
|
1497
|
+
left: 4,
|
|
1498
|
+
right: 4,
|
|
1499
|
+
nodeWidth: NODE_WIDTH,
|
|
1500
|
+
nodeGap: NODE_GAP,
|
|
1501
|
+
nodeAlign: "justify",
|
|
1502
|
+
draggable: false,
|
|
1503
|
+
layoutIterations: 32,
|
|
1504
|
+
label: {
|
|
1505
|
+
color: paint(tokens, "ink-2"),
|
|
1506
|
+
fontSize: TICK_FONT_SIZE,
|
|
1507
|
+
position: "right",
|
|
1508
|
+
distance: LABEL_GAP,
|
|
1509
|
+
textBorderColor: paint(tokens, "surface"),
|
|
1510
|
+
textBorderWidth: 2
|
|
1511
|
+
},
|
|
1512
|
+
itemStyle: { borderWidth: 0 },
|
|
1513
|
+
lineStyle: { color: "source", opacity: LINK_ALPHA, curveness: 0.5 },
|
|
1514
|
+
emphasis: { focus: "adjacency", lineStyle: { opacity: LINK_HOVER_ALPHA } },
|
|
1515
|
+
blur: { itemStyle: { opacity: 0.4 }, lineStyle: { opacity: 0.1 } },
|
|
1516
|
+
data: nodes.map((node) => {
|
|
1517
|
+
const column = columns.get(node.id) ?? 0;
|
|
1518
|
+
return {
|
|
1519
|
+
name: node.id,
|
|
1520
|
+
depth: column,
|
|
1521
|
+
itemStyle: { color: toneOf(node) },
|
|
1522
|
+
label: {
|
|
1523
|
+
formatter: () => node.label,
|
|
1524
|
+
position: column === lastColumn ? "left" : "right"
|
|
1525
|
+
}
|
|
1526
|
+
};
|
|
1527
|
+
}),
|
|
1528
|
+
links: links.map((link) => ({ source: link.source, target: link.target, value: link.value }))
|
|
1529
|
+
}]
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// src/engine/ScatterChart/ScatterChart.option.ts
|
|
1534
|
+
var DOT_SIZE = 10;
|
|
1535
|
+
var HIT_SIZE = 24;
|
|
1536
|
+
var DOT_OPACITY = 0.7;
|
|
1537
|
+
var DOTS_SERIES = "points";
|
|
1538
|
+
var HIT_SERIES = "points-hit";
|
|
1539
|
+
function buildOption13(props, tokens) {
|
|
1540
|
+
const format = props.valueFormat ?? formatCompact;
|
|
1541
|
+
const xFormat = props.xFormat ?? formatDay;
|
|
1542
|
+
const dot = paint(tokens, "series-1");
|
|
1543
|
+
const data = props.points.map((point) => [point.x.getTime(), point.y]);
|
|
1544
|
+
const dots = {
|
|
1545
|
+
type: "scatter",
|
|
1546
|
+
id: DOTS_SERIES,
|
|
1547
|
+
name: props.pointsLabel,
|
|
1548
|
+
symbolSize: DOT_SIZE,
|
|
1549
|
+
silent: true,
|
|
1550
|
+
itemStyle: { color: dot, opacity: DOT_OPACITY, borderColor: paint(tokens, "surface"), borderWidth: 2 },
|
|
1551
|
+
emphasis: { scale: 1.2, itemStyle: { opacity: 1 } },
|
|
1552
|
+
data,
|
|
1553
|
+
z: 3
|
|
1554
|
+
};
|
|
1555
|
+
const hits = {
|
|
1556
|
+
type: "scatter",
|
|
1557
|
+
id: HIT_SERIES,
|
|
1558
|
+
name: props.pointsLabel,
|
|
1559
|
+
symbolSize: HIT_SIZE,
|
|
1560
|
+
itemStyle: { opacity: 0 },
|
|
1561
|
+
emphasis: { disabled: true },
|
|
1562
|
+
data,
|
|
1563
|
+
z: 6
|
|
1564
|
+
};
|
|
1565
|
+
const trend = props.trend ? [{
|
|
1566
|
+
type: "line",
|
|
1567
|
+
id: "trend",
|
|
1568
|
+
name: props.trendLabel ?? "trend",
|
|
1569
|
+
silent: true,
|
|
1570
|
+
showSymbol: false,
|
|
1571
|
+
symbol: "none",
|
|
1572
|
+
lineStyle: { color: paint(tokens, "series-2"), width: 2, cap: "round", join: "round" },
|
|
1573
|
+
data: props.trend.map((point) => [point.x.getTime(), point.y]),
|
|
1574
|
+
z: 5
|
|
1575
|
+
}] : [];
|
|
1576
|
+
const tooltipFormatter = (params) => {
|
|
1577
|
+
const index = firstParam(params)?.dataIndex ?? 0;
|
|
1578
|
+
const point = props.points[index];
|
|
1579
|
+
if (!point)
|
|
1580
|
+
return tooltipNode(undefined, []);
|
|
1581
|
+
return tooltipNode(point.label, [
|
|
1582
|
+
{ value: format(point.y), label: props.yLabel, colour: dot, key: "dot" },
|
|
1583
|
+
{ value: xFormat(point.x), label: "day" }
|
|
1584
|
+
]);
|
|
1585
|
+
};
|
|
1586
|
+
return {
|
|
1587
|
+
grid: plotGrid({ right: 12 }),
|
|
1588
|
+
xAxis: timeAxis(tokens, xFormat),
|
|
1589
|
+
yAxis: valueAxis(tokens, format, { min: 0 }),
|
|
1590
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
1591
|
+
series: [...trend, dots, hits]
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// src/engine/Sunburst/Sunburst.option.ts
|
|
1596
|
+
var INNER_RING = [0.25, 0.55];
|
|
1597
|
+
var OUTER_RING = [0.57, 0.9];
|
|
1598
|
+
var LABEL_PADDING = 4;
|
|
1599
|
+
var LABEL_HEIGHT = TICK_FONT_SIZE * 1.2 + 2;
|
|
1600
|
+
var LABEL_MIN_ANGLE_FLOOR = 3;
|
|
1601
|
+
var DEGREES_PER_RADIAN = 180 / Math.PI;
|
|
1602
|
+
function labelMinAngle(inner, viewRadius) {
|
|
1603
|
+
const innerRadius = inner * viewRadius;
|
|
1604
|
+
if (innerRadius <= 0)
|
|
1605
|
+
return LABEL_MIN_ANGLE_FLOOR;
|
|
1606
|
+
return Math.max(LABEL_MIN_ANGLE_FLOOR, LABEL_HEIGHT / innerRadius * DEGREES_PER_RADIAN);
|
|
1607
|
+
}
|
|
1608
|
+
var PATH_SEPARATOR = " › ";
|
|
1609
|
+
function pathsById(nodes, above = []) {
|
|
1610
|
+
return new Map(nodes.flatMap((node) => {
|
|
1611
|
+
const path = [...above, node.id];
|
|
1612
|
+
return [[node.id, path], ...pathsById(node.children ?? [], path)];
|
|
1613
|
+
}));
|
|
1614
|
+
}
|
|
1615
|
+
function treePathOf(item) {
|
|
1616
|
+
if (typeof item !== "object" || item === null || !("treePathInfo" in item) || !Array.isArray(item.treePathInfo))
|
|
1617
|
+
return [];
|
|
1618
|
+
return item.treePathInfo.filter((step) => typeof step === "object" && step !== null && ("name" in step));
|
|
1619
|
+
}
|
|
1620
|
+
var percent = (share) => `${Math.round(share * 1e4) / 100}%`;
|
|
1621
|
+
function buildOption14(props, tokens, width = 0, measuredHeight = 0) {
|
|
1622
|
+
const { nodes, groupTones = {}, unit, onNodeClick } = props;
|
|
1623
|
+
const format = props.valueFormat ?? formatCompact;
|
|
1624
|
+
const surface = paint(tokens, "surface");
|
|
1625
|
+
const fillOf = (node) => paint(tokens, node.tone ?? (node.group === undefined ? undefined : groupTones[node.group]) ?? "neutral");
|
|
1626
|
+
const toItem = (node) => {
|
|
1627
|
+
const fill = fillOf(node);
|
|
1628
|
+
return {
|
|
1629
|
+
id: node.id,
|
|
1630
|
+
name: node.label,
|
|
1631
|
+
value: node.children && node.children.length > 0 ? undefined : node.value,
|
|
1632
|
+
itemStyle: { color: fill },
|
|
1633
|
+
label: { color: readableOn(tokens, fill) },
|
|
1634
|
+
children: node.children?.map(toItem)
|
|
1635
|
+
};
|
|
1636
|
+
};
|
|
1637
|
+
const tooltipFormatter = (params) => {
|
|
1638
|
+
const item = firstParam(params);
|
|
1639
|
+
const steps = treePathOf(item);
|
|
1640
|
+
const path = steps.slice(1);
|
|
1641
|
+
const value = Number(item?.value ?? 0);
|
|
1642
|
+
const parentValue = Number(steps.at(-2)?.value ?? 0);
|
|
1643
|
+
const colour = typeof item?.color === "string" ? item.color : undefined;
|
|
1644
|
+
return tooltipNode(path.map((step) => step.name).join(PATH_SEPARATOR), [
|
|
1645
|
+
{ value: `${format(value)} ${unit}`, label: "", colour, key: "dot" },
|
|
1646
|
+
{ value: formatPercent(parentValue === 0 ? 0 : value / parentValue), label: path.length > 1 ? `of ${path.at(-2)?.name ?? ""}` : "of the total" }
|
|
1647
|
+
]);
|
|
1648
|
+
};
|
|
1649
|
+
const height = plotHeightOf(props.height, measuredHeight);
|
|
1650
|
+
const viewRadius = Math.min(width > 0 ? width : height, height) / 2;
|
|
1651
|
+
const ring = ([inner, outer]) => ({
|
|
1652
|
+
radius: [percent(inner), percent(outer)],
|
|
1653
|
+
label: {
|
|
1654
|
+
rotate: "radial",
|
|
1655
|
+
fontSize: TICK_FONT_SIZE,
|
|
1656
|
+
minAngle: labelMinAngle(inner, viewRadius),
|
|
1657
|
+
width: Math.max(0, (outer - inner) * viewRadius - 2 * LABEL_PADDING),
|
|
1658
|
+
overflow: "truncate"
|
|
1659
|
+
}
|
|
1660
|
+
});
|
|
1661
|
+
return {
|
|
1662
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
1663
|
+
series: [{
|
|
1664
|
+
type: "sunburst",
|
|
1665
|
+
center: ["50%", "50%"],
|
|
1666
|
+
nodeClick: false,
|
|
1667
|
+
cursor: onNodeClick ? "pointer" : "default",
|
|
1668
|
+
sort: (a, b) => a.dataIndex - b.dataIndex,
|
|
1669
|
+
itemStyle: { borderColor: surface, borderWidth: 2 },
|
|
1670
|
+
emphasis: { focus: "ancestor" },
|
|
1671
|
+
blur: { itemStyle: { opacity: BLUR_OPACITY } },
|
|
1672
|
+
levels: [
|
|
1673
|
+
{},
|
|
1674
|
+
ring(INNER_RING),
|
|
1675
|
+
ring(OUTER_RING)
|
|
1676
|
+
],
|
|
1677
|
+
data: nodes.map(toItem)
|
|
1678
|
+
}]
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
// src/engine/Treemap/Treemap.option.ts
|
|
1683
|
+
import { format as echartsFormat2 } from "echarts/core";
|
|
1684
|
+
var NODE_ALPHA = 0.85;
|
|
1685
|
+
var LABEL_FONT_SIZE2 = 12;
|
|
1686
|
+
var LABEL_LINE_HEIGHT2 = 16;
|
|
1687
|
+
var LABEL_PADDING2 = 6;
|
|
1688
|
+
var OFF_CANVAS = -1e4;
|
|
1689
|
+
function hideUnfitLabel(fontFamily) {
|
|
1690
|
+
return (params) => {
|
|
1691
|
+
const textWidth = echartsFormat2.getTextRect(params.text, `${LABEL_FONT_SIZE2}px ${fontFamily}`).width;
|
|
1692
|
+
const fitsWidth = textWidth + 2 * LABEL_PADDING2 <= params.rect.width;
|
|
1693
|
+
const fitsHeight = LABEL_LINE_HEIGHT2 + 2 * LABEL_PADDING2 <= params.rect.height;
|
|
1694
|
+
return fitsWidth && fitsHeight ? {} : { x: OFF_CANVAS, y: OFF_CANVAS };
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
function buildOption15(props, tokens) {
|
|
1698
|
+
const { nodes, groupTones, unit } = props;
|
|
1699
|
+
const format = props.valueFormat ?? formatCompact;
|
|
1700
|
+
const surface = paint(tokens, "surface");
|
|
1701
|
+
const fontFamily = readFontFamily();
|
|
1702
|
+
const fillOf = (group) => paint(tokens, groupTones[group] ?? "neutral");
|
|
1703
|
+
const tooltipFormatter = (params) => {
|
|
1704
|
+
const item = firstParam(params);
|
|
1705
|
+
const data = item?.data;
|
|
1706
|
+
const id = typeof data === "object" && data !== null && "id" in data ? String(data.id) : undefined;
|
|
1707
|
+
const match = nodes.find((entry) => entry.id === id) ?? nodes.find((entry) => entry.label === item?.name);
|
|
1708
|
+
if (!match)
|
|
1709
|
+
return tooltipNode(undefined, []);
|
|
1710
|
+
return tooltipNode(match.label, [
|
|
1711
|
+
{ value: `${format(match.value)} ${unit}`, label: match.group, colour: fillOf(match.group), key: "dot" }
|
|
1712
|
+
]);
|
|
1713
|
+
};
|
|
1714
|
+
return {
|
|
1715
|
+
tooltip: { ...tooltipChrome("item"), formatter: tooltipFormatter },
|
|
1716
|
+
series: [{
|
|
1717
|
+
type: "treemap",
|
|
1718
|
+
top: 0,
|
|
1719
|
+
right: 0,
|
|
1720
|
+
bottom: 0,
|
|
1721
|
+
left: 0,
|
|
1722
|
+
roam: false,
|
|
1723
|
+
nodeClick: false,
|
|
1724
|
+
breadcrumb: { show: false },
|
|
1725
|
+
leafDepth: 1,
|
|
1726
|
+
itemStyle: { borderColor: surface, borderWidth: 0, gapWidth: 2 },
|
|
1727
|
+
levels: [{ itemStyle: { borderColor: surface, borderWidth: 0, gapWidth: 2 } }],
|
|
1728
|
+
label: {
|
|
1729
|
+
show: true,
|
|
1730
|
+
position: "insideTopLeft",
|
|
1731
|
+
padding: LABEL_PADDING2,
|
|
1732
|
+
fontSize: LABEL_FONT_SIZE2,
|
|
1733
|
+
lineHeight: LABEL_LINE_HEIGHT2,
|
|
1734
|
+
formatter: (params) => params.name
|
|
1735
|
+
},
|
|
1736
|
+
labelLayout: hideUnfitLabel(fontFamily),
|
|
1737
|
+
emphasis: { focus: "self", itemStyle: { borderColor: surface } },
|
|
1738
|
+
blur: { itemStyle: { opacity: 0.85 } },
|
|
1739
|
+
data: nodes.map((node) => {
|
|
1740
|
+
const fill = withAlpha(fillOf(node.group), NODE_ALPHA);
|
|
1741
|
+
return {
|
|
1742
|
+
id: node.id,
|
|
1743
|
+
name: node.label,
|
|
1744
|
+
value: node.value,
|
|
1745
|
+
itemStyle: { color: fill },
|
|
1746
|
+
label: { color: readableOn(tokens, fillOf(node.group)) }
|
|
1747
|
+
};
|
|
1748
|
+
})
|
|
1749
|
+
}]
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
// src/seam/format.schema.ts
|
|
1754
|
+
import { z } from "zod";
|
|
1755
|
+
var MAX_DIGITS = 20;
|
|
1756
|
+
var digits = z.number().int().min(0).max(MAX_DIGITS).optional();
|
|
1757
|
+
var currency = z.string().regex(/^[A-Za-z]{3}$/, "a currency is a three-letter ISO 4217 code");
|
|
1758
|
+
function isLocale(tag) {
|
|
1759
|
+
try {
|
|
1760
|
+
return Intl.getCanonicalLocales(tag).length === 1;
|
|
1761
|
+
} catch {
|
|
1762
|
+
return false;
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
var valueFormatSchema = z.discriminatedUnion("kind", [
|
|
1766
|
+
z.object({ kind: z.literal("raw"), digits }),
|
|
1767
|
+
z.object({ kind: z.literal("number"), digits, grouping: z.boolean().optional() }),
|
|
1768
|
+
z.object({ kind: z.literal("compact") }),
|
|
1769
|
+
z.object({ kind: z.literal("percent"), digits, of: z.enum(PERCENT_BASES).optional(), signed: z.boolean().optional() }),
|
|
1770
|
+
z.object({ kind: z.literal("money"), currency: currency.optional(), digits, compact: z.boolean().optional() }),
|
|
1771
|
+
z.object({ kind: z.literal("unit"), unit: z.string().min(1), position: z.enum(UNIT_POSITIONS).optional() }),
|
|
1772
|
+
z.object({ kind: z.literal("duration"), from: z.enum(DURATION_UNITS) }),
|
|
1773
|
+
z.object({ kind: z.literal("elapsed"), from: z.enum(DURATION_UNITS) }),
|
|
1774
|
+
z.object({ kind: z.literal("date"), pattern: z.enum(DATE_PATTERNS) }),
|
|
1775
|
+
z.object({ kind: z.literal("relative") }),
|
|
1776
|
+
z.object({ kind: z.literal("custom"), id: z.string().min(1) })
|
|
1777
|
+
]);
|
|
1778
|
+
var formatContextSchema = z.object({
|
|
1779
|
+
locale: z.string().refine(isLocale, "a locale is a BCP 47 tag Intl accepts").optional(),
|
|
1780
|
+
currency: currency.optional(),
|
|
1781
|
+
timeZone: z.literal("UTC").optional(),
|
|
1782
|
+
customFormatters: z.record(z.string(), z.custom((value) => typeof value === "function", "a custom formatter is a function")).optional(),
|
|
1783
|
+
now: z.number().optional()
|
|
1784
|
+
});
|
|
1785
|
+
|
|
1786
|
+
export { chartTone, ALL_TONES, SEQUENTIAL_STEPS, CHROME_ROLES, toneVar, readTokens, tokensFrom, DEFAULT_CHART_HEIGHT, plotHeightOf, DEFAULT_HEIGHT, finishOption, chartRootVariants, chartFrameVariants, formatCompact, formatPercent, formatMinutes, formatDay, formatWeek, formatElapsed, formatRelative, VALUE_FORMAT_KINDS, DATE_PATTERNS, DURATION_UNITS, PERCENT_BASES, UNIT_POSITIONS, DEFAULT_FORMAT_CONTEXT, resolveFormatContext, formatDate, formatterFor, formatMeasured, buildOption, buildOption2 as buildOption1, buildOption3 as buildOption2, buildOption4 as buildOption3, buildOption5 as buildOption4, buildOption6 as buildOption5, buildOption7 as buildOption6, buildOption8 as buildOption7, nodeIdOf, buildOption9 as buildOption8, buildOption10 as buildOption9, buildOption11 as buildOption10, buildOption12 as buildOption11, DOTS_SERIES, HIT_SERIES, buildOption13 as buildOption12, pathsById, buildOption14 as buildOption13, buildOption15 as buildOption14, valueFormatSchema, formatContextSchema };
|