@arcfusionz/arc-analytic-ui 0.0.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/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/components/AnomalyCard/AnomalyCard.chart.d.ts +64 -0
- package/dist/components/AnomalyCard/AnomalyCard.chart.js +341 -0
- package/dist/components/AnomalyCard/AnomalyCard.d.ts +169 -0
- package/dist/components/AnomalyCard/AnomalyCard.js +1019 -0
- package/dist/components/AnomalyCard/AnomalyCard.model.d.ts +508 -0
- package/dist/components/AnomalyCard/AnomalyCard.model.js +553 -0
- package/dist/components/AnomalyCard/index.d.ts +4 -0
- package/dist/components/AnomalyCard/index.js +4 -0
- package/dist/components/ChartCard/ChartCard.chart.d.ts +72 -0
- package/dist/components/ChartCard/ChartCard.chart.js +1333 -0
- package/dist/components/ChartCard/ChartCard.d.ts +206 -0
- package/dist/components/ChartCard/ChartCard.js +718 -0
- package/dist/components/ChartCard/ChartCard.model.d.ts +452 -0
- package/dist/components/ChartCard/ChartCard.model.js +1223 -0
- package/dist/components/ChartCard/index.d.ts +4 -0
- package/dist/components/ChartCard/index.js +4 -0
- package/dist/components/ComparisonCard/ComparisonCard.chart.d.ts +80 -0
- package/dist/components/ComparisonCard/ComparisonCard.chart.js +337 -0
- package/dist/components/ComparisonCard/ComparisonCard.d.ts +200 -0
- package/dist/components/ComparisonCard/ComparisonCard.js +1325 -0
- package/dist/components/ComparisonCard/ComparisonCard.model.d.ts +309 -0
- package/dist/components/ComparisonCard/ComparisonCard.model.js +263 -0
- package/dist/components/ComparisonCard/index.d.ts +4 -0
- package/dist/components/ComparisonCard/index.js +4 -0
- package/dist/components/ForecastCard/ForecastCard.chart.d.ts +82 -0
- package/dist/components/ForecastCard/ForecastCard.chart.js +416 -0
- package/dist/components/ForecastCard/ForecastCard.d.ts +148 -0
- package/dist/components/ForecastCard/ForecastCard.js +1029 -0
- package/dist/components/ForecastCard/ForecastCard.model.d.ts +497 -0
- package/dist/components/ForecastCard/ForecastCard.model.js +554 -0
- package/dist/components/ForecastCard/index.d.ts +4 -0
- package/dist/components/ForecastCard/index.js +4 -0
- package/dist/components/HighlightCard/HighlightCard.chart.d.ts +122 -0
- package/dist/components/HighlightCard/HighlightCard.chart.js +660 -0
- package/dist/components/HighlightCard/HighlightCard.d.ts +202 -0
- package/dist/components/HighlightCard/HighlightCard.js +1286 -0
- package/dist/components/HighlightCard/HighlightCard.model.d.ts +692 -0
- package/dist/components/HighlightCard/HighlightCard.model.js +875 -0
- package/dist/components/HighlightCard/index.d.ts +4 -0
- package/dist/components/HighlightCard/index.js +4 -0
- package/dist/components/InsightCard/InsightCard.chart.d.ts +91 -0
- package/dist/components/InsightCard/InsightCard.chart.js +471 -0
- package/dist/components/InsightCard/InsightCard.d.ts +161 -0
- package/dist/components/InsightCard/InsightCard.js +961 -0
- package/dist/components/InsightCard/InsightCard.model.d.ts +405 -0
- package/dist/components/InsightCard/InsightCard.model.js +421 -0
- package/dist/components/InsightCard/index.d.ts +4 -0
- package/dist/components/InsightCard/index.js +4 -0
- package/dist/components/MetricCard/MetricCard.chart.d.ts +79 -0
- package/dist/components/MetricCard/MetricCard.chart.js +435 -0
- package/dist/components/MetricCard/MetricCard.d.ts +227 -0
- package/dist/components/MetricCard/MetricCard.js +1293 -0
- package/dist/components/MetricCard/MetricCard.model.d.ts +521 -0
- package/dist/components/MetricCard/MetricCard.model.js +627 -0
- package/dist/components/MetricCard/index.d.ts +4 -0
- package/dist/components/MetricCard/index.js +4 -0
- package/dist/components/ProfileCard/ProfileCard.chart.d.ts +64 -0
- package/dist/components/ProfileCard/ProfileCard.chart.js +427 -0
- package/dist/components/ProfileCard/ProfileCard.d.ts +140 -0
- package/dist/components/ProfileCard/ProfileCard.js +735 -0
- package/dist/components/ProfileCard/ProfileCard.model.d.ts +279 -0
- package/dist/components/ProfileCard/ProfileCard.model.js +244 -0
- package/dist/components/ProfileCard/index.d.ts +4 -0
- package/dist/components/ProfileCard/index.js +4 -0
- package/dist/components/ProgressCard/ProgressCard.chart.d.ts +73 -0
- package/dist/components/ProgressCard/ProgressCard.chart.js +373 -0
- package/dist/components/ProgressCard/ProgressCard.d.ts +137 -0
- package/dist/components/ProgressCard/ProgressCard.js +908 -0
- package/dist/components/ProgressCard/ProgressCard.model.d.ts +385 -0
- package/dist/components/ProgressCard/ProgressCard.model.js +389 -0
- package/dist/components/ProgressCard/index.d.ts +4 -0
- package/dist/components/ProgressCard/index.js +4 -0
- package/dist/components/ReportCard/ReportCard.chart.d.ts +45 -0
- package/dist/components/ReportCard/ReportCard.chart.js +231 -0
- package/dist/components/ReportCard/ReportCard.d.ts +153 -0
- package/dist/components/ReportCard/ReportCard.js +1118 -0
- package/dist/components/ReportCard/ReportCard.model.d.ts +392 -0
- package/dist/components/ReportCard/ReportCard.model.js +399 -0
- package/dist/components/ReportCard/index.d.ts +4 -0
- package/dist/components/ReportCard/index.js +4 -0
- package/dist/components/SankeyCard/SankeyCard.chart.d.ts +75 -0
- package/dist/components/SankeyCard/SankeyCard.chart.js +249 -0
- package/dist/components/SankeyCard/SankeyCard.d.ts +185 -0
- package/dist/components/SankeyCard/SankeyCard.js +788 -0
- package/dist/components/SankeyCard/SankeyCard.model.d.ts +501 -0
- package/dist/components/SankeyCard/SankeyCard.model.js +789 -0
- package/dist/components/SankeyCard/index.d.ts +4 -0
- package/dist/components/SankeyCard/index.js +4 -0
- package/dist/components/StatusCard/StatusCard.chart.d.ts +60 -0
- package/dist/components/StatusCard/StatusCard.chart.js +188 -0
- package/dist/components/StatusCard/StatusCard.d.ts +176 -0
- package/dist/components/StatusCard/StatusCard.js +989 -0
- package/dist/components/StatusCard/StatusCard.model.d.ts +555 -0
- package/dist/components/StatusCard/StatusCard.model.js +776 -0
- package/dist/components/StatusCard/index.d.ts +4 -0
- package/dist/components/StatusCard/index.js +4 -0
- package/dist/components/TableCard/TableCard.chart.d.ts +53 -0
- package/dist/components/TableCard/TableCard.chart.js +192 -0
- package/dist/components/TableCard/TableCard.d.ts +140 -0
- package/dist/components/TableCard/TableCard.js +811 -0
- package/dist/components/TableCard/TableCard.model.d.ts +381 -0
- package/dist/components/TableCard/TableCard.model.js +475 -0
- package/dist/components/TableCard/index.d.ts +4 -0
- package/dist/components/TableCard/index.js +4 -0
- package/dist/components/TargetCard/TargetCard.chart.d.ts +52 -0
- package/dist/components/TargetCard/TargetCard.chart.js +273 -0
- package/dist/components/TargetCard/TargetCard.d.ts +143 -0
- package/dist/components/TargetCard/TargetCard.js +910 -0
- package/dist/components/TargetCard/TargetCard.model.d.ts +468 -0
- package/dist/components/TargetCard/TargetCard.model.js +581 -0
- package/dist/components/TargetCard/index.d.ts +4 -0
- package/dist/components/TargetCard/index.js +4 -0
- package/dist/components/TreeCard/TreeCard.chart.d.ts +80 -0
- package/dist/components/TreeCard/TreeCard.chart.js +178 -0
- package/dist/components/TreeCard/TreeCard.d.ts +182 -0
- package/dist/components/TreeCard/TreeCard.js +1187 -0
- package/dist/components/TreeCard/TreeCard.model.d.ts +330 -0
- package/dist/components/TreeCard/TreeCard.model.js +401 -0
- package/dist/components/TreeCard/index.d.ts +4 -0
- package/dist/components/TreeCard/index.js +4 -0
- package/dist/components/TrendCard/TrendCard.chart.d.ts +75 -0
- package/dist/components/TrendCard/TrendCard.chart.js +393 -0
- package/dist/components/TrendCard/TrendCard.d.ts +224 -0
- package/dist/components/TrendCard/TrendCard.js +1053 -0
- package/dist/components/TrendCard/TrendCard.model.d.ts +545 -0
- package/dist/components/TrendCard/TrendCard.model.js +623 -0
- package/dist/components/TrendCard/index.d.ts +4 -0
- package/dist/components/TrendCard/index.js +4 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.js +57 -0
- package/dist/lib/vega/ArcVegaChart.d.ts +24 -0
- package/dist/lib/vega/ArcVegaChart.js +42 -0
- package/dist/lib/vega/ArcVegaSurface.d.ts +13 -0
- package/dist/lib/vega/ArcVegaSurface.js +38 -0
- package/dist/lib/vega/axisTicks.js +156 -0
- package/dist/lib/vega/config.d.ts +29 -0
- package/dist/lib/vega/config.js +113 -0
- package/dist/lib/vega/embed.d.ts +29 -0
- package/dist/lib/vega/embed.js +29 -0
- package/dist/lib/vega/engine.d.ts +10 -0
- package/dist/lib/vega/engine.js +6 -0
- package/dist/lib/vega/formatters.d.ts +125 -0
- package/dist/lib/vega/formatters.js +277 -0
- package/dist/lib/vega/index.d.ts +11 -0
- package/dist/lib/vega/load.d.ts +13 -0
- package/dist/lib/vega/load.js +21 -0
- package/dist/lib/vega/time.d.ts +45 -0
- package/dist/lib/vega/time.js +105 -0
- package/dist/lib/vega/tokens.d.ts +73 -0
- package/dist/lib/vega/tokens.js +137 -0
- package/dist/lib/vega/tooltip.d.ts +45 -0
- package/dist/lib/vega/tooltip.js +124 -0
- package/dist/lib/vega/useArcVega.d.ts +43 -0
- package/dist/lib/vega/useArcVega.js +121 -0
- package/package.json +60 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { formatDate, formatDelta, formatNumber, parseArcNumberFormat } from "../../lib/vega/formatters.js";
|
|
2
|
+
//#region src/components/InsightCard/InsightCard.model.ts
|
|
3
|
+
const isFinite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
4
|
+
/** Default severity ladders, per scale. Sigma takes the conventional 2σ / 3σ; a band counts half-widths, so 1 is the edge. */
|
|
5
|
+
const DEFAULT_SEVERITY_THRESHOLDS = {
|
|
6
|
+
sigma: {
|
|
7
|
+
notable: 2,
|
|
8
|
+
critical: 3
|
|
9
|
+
},
|
|
10
|
+
band: {
|
|
11
|
+
notable: 1,
|
|
12
|
+
critical: 2
|
|
13
|
+
},
|
|
14
|
+
relative: {
|
|
15
|
+
notable: .1,
|
|
16
|
+
critical: .25
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/** Confidence at or above these reads as high, then moderate; below, low. */
|
|
20
|
+
const CONFIDENCE_BOUNDS = {
|
|
21
|
+
high: .9,
|
|
22
|
+
moderate: .7
|
|
23
|
+
};
|
|
24
|
+
/** Buckets a 0–1 confidence for the provenance line. `null` for anything outside the range. */
|
|
25
|
+
function insightConfidenceLevel(confidence) {
|
|
26
|
+
if (!isFinite(confidence) || confidence < 0 || confidence > 1) return null;
|
|
27
|
+
if (confidence >= CONFIDENCE_BOUNDS.high) return "high";
|
|
28
|
+
if (confidence >= CONFIDENCE_BOUNDS.moderate) return "moderate";
|
|
29
|
+
return "low";
|
|
30
|
+
}
|
|
31
|
+
/** Guesses the axis kind from the first reading that has an `x`. */
|
|
32
|
+
function inferInsightXType(points) {
|
|
33
|
+
const first = (points ?? []).find((point) => point.x != null);
|
|
34
|
+
if (!first) return "temporal";
|
|
35
|
+
if (first.x instanceof Date) return "temporal";
|
|
36
|
+
if (typeof first.x === "number") return Number.isFinite(first.x) ? "quantitative" : "temporal";
|
|
37
|
+
return Number.isNaN(new Date(first.x).getTime()) ? "ordinal" : "temporal";
|
|
38
|
+
}
|
|
39
|
+
function normalizeX(x, xType) {
|
|
40
|
+
if (xType === "temporal") {
|
|
41
|
+
const time = x instanceof Date ? x.getTime() : new Date(x).getTime();
|
|
42
|
+
return Number.isNaN(time) ? null : time;
|
|
43
|
+
}
|
|
44
|
+
if (xType === "quantitative") return isFinite(x) ? x : null;
|
|
45
|
+
return String(x);
|
|
46
|
+
}
|
|
47
|
+
/** How the deviation is measured, given what the detector actually reported. */
|
|
48
|
+
function resolveStrength(value, expected, lower, upper, sd) {
|
|
49
|
+
if (value == null || expected == null) return {
|
|
50
|
+
strength: null,
|
|
51
|
+
kind: null
|
|
52
|
+
};
|
|
53
|
+
const deviation = Math.abs(value - expected);
|
|
54
|
+
if (isFinite(sd) && sd > 0) return {
|
|
55
|
+
strength: deviation / sd,
|
|
56
|
+
kind: "sigma"
|
|
57
|
+
};
|
|
58
|
+
if (isFinite(lower) && isFinite(upper) && upper > lower) return {
|
|
59
|
+
strength: deviation / ((upper - lower) / 2),
|
|
60
|
+
kind: "band"
|
|
61
|
+
};
|
|
62
|
+
if (expected !== 0) return {
|
|
63
|
+
strength: deviation / Math.abs(expected),
|
|
64
|
+
kind: "relative"
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
strength: null,
|
|
68
|
+
kind: null
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** The severity the strength supports. Never guesses from a scale the data does not establish. */
|
|
72
|
+
function deriveInsightSeverity(strength, kind, overrides) {
|
|
73
|
+
if (strength == null || kind == null) return "info";
|
|
74
|
+
const base = DEFAULT_SEVERITY_THRESHOLDS[kind];
|
|
75
|
+
const critical = overrides?.critical ?? base.critical;
|
|
76
|
+
const notable = overrides?.notable ?? base.notable;
|
|
77
|
+
if (strength >= critical) return "critical";
|
|
78
|
+
if (strength >= notable) return "notable";
|
|
79
|
+
return "info";
|
|
80
|
+
}
|
|
81
|
+
/** How a deviation reads once the measure's good direction is applied. */
|
|
82
|
+
function deriveInsightPolarity(direction, goodDirection) {
|
|
83
|
+
if (goodDirection === "none" || direction === "flat") return "neutral";
|
|
84
|
+
return direction === (goodDirection === "up" ? "up" : "down") ? "positive" : "negative";
|
|
85
|
+
}
|
|
86
|
+
const STRIP_PADDING = .1;
|
|
87
|
+
/**
|
|
88
|
+
* Resolves the finding: which reading is flagged, what was expected of it,
|
|
89
|
+
* how far off it is and on which scale, how that reads as severity and
|
|
90
|
+
* polarity, which evidence form the data can carry, and the rows each form
|
|
91
|
+
* draws. Returns `null` when there is neither a reading nor a history to
|
|
92
|
+
* speak of.
|
|
93
|
+
*/
|
|
94
|
+
function normalizeInsight({ observation, points, xType: xTypeProp, goodDirection = "none", evidence = "auto", severity: severityOverride, severityThresholds, tokens }) {
|
|
95
|
+
const source = points ?? [];
|
|
96
|
+
const xType = xTypeProp ?? inferInsightXType(source);
|
|
97
|
+
const atX = observation?.at != null ? normalizeX(observation.at, xType) : null;
|
|
98
|
+
const rows = [];
|
|
99
|
+
const flags = [];
|
|
100
|
+
source.forEach((point) => {
|
|
101
|
+
const x = normalizeX(point.x, xType);
|
|
102
|
+
if (x == null) return;
|
|
103
|
+
rows.push({
|
|
104
|
+
x,
|
|
105
|
+
y: isFinite(point.y) ? point.y : null,
|
|
106
|
+
e: isFinite(point.expected) ? point.expected : null,
|
|
107
|
+
lo: isFinite(point.lower) ? point.lower : null,
|
|
108
|
+
hi: isFinite(point.upper) ? point.upper : null
|
|
109
|
+
});
|
|
110
|
+
flags.push(point.flagged === true);
|
|
111
|
+
});
|
|
112
|
+
if (xType !== "ordinal") {
|
|
113
|
+
const order = rows.map((_, index) => index).sort((a, b) => rows[a].x - rows[b].x);
|
|
114
|
+
const sortedRows = order.map((index) => rows[index]);
|
|
115
|
+
const sortedFlags = order.map((index) => flags[index]);
|
|
116
|
+
rows.length = 0;
|
|
117
|
+
rows.push(...sortedRows);
|
|
118
|
+
flags.length = 0;
|
|
119
|
+
flags.push(...sortedFlags);
|
|
120
|
+
}
|
|
121
|
+
let flaggedIndex = flags.findIndex(Boolean);
|
|
122
|
+
if (flaggedIndex < 0 && atX != null) flaggedIndex = rows.findIndex((row) => row.x === atX);
|
|
123
|
+
if (flaggedIndex < 0) {
|
|
124
|
+
for (let index = rows.length - 1; index >= 0; index -= 1) if (rows[index].y != null) {
|
|
125
|
+
flaggedIndex = index;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const flaggedRow = flaggedIndex >= 0 ? rows[flaggedIndex] : void 0;
|
|
130
|
+
const value = isFinite(observation?.value) ? observation.value : flaggedRow?.y ?? null;
|
|
131
|
+
if (value == null && rows.length === 0) return null;
|
|
132
|
+
const lower = isFinite(observation?.lower) ? observation.lower : flaggedRow?.lo ?? null;
|
|
133
|
+
const upper = isFinite(observation?.upper) ? observation.upper : flaggedRow?.hi ?? null;
|
|
134
|
+
const midpoint = isFinite(lower) && isFinite(upper) ? (lower + upper) / 2 : null;
|
|
135
|
+
const expected = isFinite(observation?.expected) ? observation.expected : flaggedRow?.e ?? midpoint;
|
|
136
|
+
const sd = isFinite(observation?.sd) ? observation.sd : null;
|
|
137
|
+
const deviation = value != null && expected != null ? value - expected : null;
|
|
138
|
+
const relative = deviation != null && expected != null && expected !== 0 ? deviation / Math.abs(expected) : null;
|
|
139
|
+
const outside = value != null && (isFinite(lower) && value < lower || isFinite(upper) && value > upper);
|
|
140
|
+
const direction = deviation == null || deviation === 0 ? "flat" : deviation > 0 ? "up" : "down";
|
|
141
|
+
const polarity = deriveInsightPolarity(direction, goodDirection);
|
|
142
|
+
const { strength, kind } = resolveStrength(value, expected, lower, upper, sd);
|
|
143
|
+
const severity = severityOverride ?? deriveInsightSeverity(strength, kind, severityThresholds);
|
|
144
|
+
const color = polarity === "positive" ? tokens?.positive ?? "" : polarity === "negative" ? tokens?.negative ?? "" : tokens?.emphasis ?? "";
|
|
145
|
+
const finite = rows.filter((row) => row.y != null).length;
|
|
146
|
+
const insufficient = finite < 2;
|
|
147
|
+
const hasBand = rows.filter((row) => row.lo != null && row.hi != null).length >= 2;
|
|
148
|
+
const hasExpectedLine = rows.filter((row) => row.e != null).length >= 2;
|
|
149
|
+
const canSpark = finite >= 2;
|
|
150
|
+
const canRange = value != null && (isFinite(lower) || isFinite(upper) || isFinite(expected));
|
|
151
|
+
const resolvedEvidence = evidence === "none" ? "none" : evidence === "spark" ? canSpark ? "spark" : canRange ? "range" : "none" : evidence === "range" ? canRange ? "range" : "none" : canSpark ? "spark" : canRange ? "range" : "none";
|
|
152
|
+
const pointRows = rows.map((row, index) => ({
|
|
153
|
+
...row,
|
|
154
|
+
f: index === flaggedIndex,
|
|
155
|
+
c: color
|
|
156
|
+
}));
|
|
157
|
+
const interval = resolvedEvidence === "spark" && !hasBand && flaggedRow && isFinite(lower) && isFinite(upper) ? [{
|
|
158
|
+
x: flaggedRow.x,
|
|
159
|
+
lo: lower,
|
|
160
|
+
hi: upper
|
|
161
|
+
}] : [];
|
|
162
|
+
const strip = [];
|
|
163
|
+
if (resolvedEvidence === "range" && value != null) {
|
|
164
|
+
const marks = [
|
|
165
|
+
value,
|
|
166
|
+
expected,
|
|
167
|
+
lower,
|
|
168
|
+
upper
|
|
169
|
+
].filter(isFinite);
|
|
170
|
+
let d0 = Math.min(...marks);
|
|
171
|
+
let d1 = Math.max(...marks);
|
|
172
|
+
if (d1 === d0) {
|
|
173
|
+
const pad = Math.max(Math.abs(d0) * STRIP_PADDING, 1);
|
|
174
|
+
d0 -= pad;
|
|
175
|
+
d1 += pad;
|
|
176
|
+
} else {
|
|
177
|
+
const pad = (d1 - d0) * STRIP_PADDING;
|
|
178
|
+
d0 -= pad;
|
|
179
|
+
d1 += pad;
|
|
180
|
+
}
|
|
181
|
+
strip.push({
|
|
182
|
+
lo: lower,
|
|
183
|
+
hi: upper,
|
|
184
|
+
e: expected,
|
|
185
|
+
v: value,
|
|
186
|
+
d0,
|
|
187
|
+
d1,
|
|
188
|
+
c: color
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
value,
|
|
193
|
+
expected,
|
|
194
|
+
lower,
|
|
195
|
+
upper,
|
|
196
|
+
sd,
|
|
197
|
+
deviation,
|
|
198
|
+
relative,
|
|
199
|
+
outside,
|
|
200
|
+
strength,
|
|
201
|
+
strengthKind: kind,
|
|
202
|
+
direction,
|
|
203
|
+
polarity,
|
|
204
|
+
severity,
|
|
205
|
+
color,
|
|
206
|
+
evidence: resolvedEvidence,
|
|
207
|
+
xType,
|
|
208
|
+
points: resolvedEvidence === "spark" ? pointRows : [],
|
|
209
|
+
interval,
|
|
210
|
+
strip,
|
|
211
|
+
flaggedX: flaggedRow?.x ?? null,
|
|
212
|
+
at: observation?.at ?? null,
|
|
213
|
+
count: finite,
|
|
214
|
+
hasBand,
|
|
215
|
+
hasExpectedLine,
|
|
216
|
+
insufficient
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function createInsightFormatters({ format, locale, deltaMode, formatValue, labels }) {
|
|
220
|
+
const value = (input) => isFinite(input) ? formatValue ? formatValue(input) : formatNumber(input, format, locale) : "—";
|
|
221
|
+
return {
|
|
222
|
+
formatValue: value,
|
|
223
|
+
formatRange: (lower, upper) => isFinite(lower) && isFinite(upper) ? labels.rangeText(value(lower), value(upper)) : null,
|
|
224
|
+
formatDeviation: (current, expected) => formatDelta(current, expected, {
|
|
225
|
+
mode: deltaMode,
|
|
226
|
+
format,
|
|
227
|
+
locale
|
|
228
|
+
}).text,
|
|
229
|
+
formatStrength: (strength, kind) => {
|
|
230
|
+
if (strength == null || kind == null) return null;
|
|
231
|
+
if (kind === "sigma") return labels.sigmaText(formatNumber(strength, "number:1", locale));
|
|
232
|
+
if (kind === "band") return labels.bandText(formatNumber(strength, "number:1", locale));
|
|
233
|
+
return labels.relativeText(formatNumber(strength, "percent:0", locale));
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const DEFAULT_INSIGHT_LABELS = {
|
|
238
|
+
noData: "No insight",
|
|
239
|
+
noMatch: "No matching insight",
|
|
240
|
+
clearFilters: "Clear filters",
|
|
241
|
+
error: "Couldn't load this insight",
|
|
242
|
+
retry: "Try again",
|
|
243
|
+
stale: "Stale",
|
|
244
|
+
asOf: "As of",
|
|
245
|
+
observed: "Observed",
|
|
246
|
+
expected: "Expected",
|
|
247
|
+
deviation: "vs expected",
|
|
248
|
+
rangeText: (lower, upper) => `${lower} – ${upper}`,
|
|
249
|
+
outsideRange: (range) => `Outside the expected ${range}.`,
|
|
250
|
+
insideRange: (range) => `Within the expected ${range}.`,
|
|
251
|
+
sigmaText: (value) => `${value}σ from expected`,
|
|
252
|
+
bandText: (value) => `${value}× the expected range`,
|
|
253
|
+
relativeText: (value) => `${value} from expected`,
|
|
254
|
+
detected: (when) => `Detected ${when}`,
|
|
255
|
+
sample: (count) => `${count} readings`,
|
|
256
|
+
confidence: (level, percent) => `${level} confidence (${percent})`,
|
|
257
|
+
confidenceNames: {
|
|
258
|
+
high: "High",
|
|
259
|
+
moderate: "Moderate",
|
|
260
|
+
low: "Low"
|
|
261
|
+
},
|
|
262
|
+
kindNames: {
|
|
263
|
+
anomaly: "Anomaly",
|
|
264
|
+
trend: "Trend",
|
|
265
|
+
threshold: "Threshold",
|
|
266
|
+
outlier: "Outlier",
|
|
267
|
+
correlation: "Correlation",
|
|
268
|
+
forecast: "Forecast",
|
|
269
|
+
milestone: "Milestone",
|
|
270
|
+
note: "Note"
|
|
271
|
+
},
|
|
272
|
+
severityNames: {
|
|
273
|
+
info: "Info",
|
|
274
|
+
notable: "Notable",
|
|
275
|
+
critical: "Critical"
|
|
276
|
+
},
|
|
277
|
+
badge: (severity, kind, key) => key === "info" ? kind : `${severity} ${kind.toLowerCase()}`,
|
|
278
|
+
directionWords: {
|
|
279
|
+
up: "up",
|
|
280
|
+
down: "down",
|
|
281
|
+
flat: "unchanged"
|
|
282
|
+
},
|
|
283
|
+
dismiss: (name) => `Dismiss ${name}`,
|
|
284
|
+
helpful: "Helpful",
|
|
285
|
+
notHelpful: "Not helpful",
|
|
286
|
+
feedbackGroup: (name) => `Was ${name} helpful?`,
|
|
287
|
+
showTable: (name) => `Show the data behind ${name}`,
|
|
288
|
+
hideTable: (name) => `Hide the data behind ${name}`,
|
|
289
|
+
about: (name) => `About ${name}`,
|
|
290
|
+
loading: (name) => `Loading ${name}`,
|
|
291
|
+
tableCaption: (name) => `Data behind ${name}`,
|
|
292
|
+
tablePeriod: "Period",
|
|
293
|
+
tableValue: "Reading",
|
|
294
|
+
tableExpected: "Expected",
|
|
295
|
+
tableRange: "Expected range",
|
|
296
|
+
tableFlagged: "Flagged",
|
|
297
|
+
flagged: "flagged",
|
|
298
|
+
needsHistory: "Not enough history to plot a trend.",
|
|
299
|
+
evidenceNames: {
|
|
300
|
+
spark: "Sparkline",
|
|
301
|
+
range: "Range strip"
|
|
302
|
+
},
|
|
303
|
+
chartDescription: ({ evidence, name, readings, observed, expected, range, at }) => `${evidence} of ${name}${readings > 0 ? `, ${readings} ${readings === 1 ? "reading" : "readings"}` : ""}. Flagged reading ${observed}${at ? ` at ${at}` : ""}.` + (expected ? ` Expected ${expected}.` : "") + (range ? ` Expected range ${range}.` : ""),
|
|
304
|
+
claim: ({ kind, name, observed, expected, deviation }) => `${kind} in ${name}: ${observed}` + (expected ? ` against an expected ${expected}` : "") + (deviation ? ` (${deviation})` : "") + ".",
|
|
305
|
+
insightMark: "Insight"
|
|
306
|
+
};
|
|
307
|
+
function resolveInsightLabels(overrides) {
|
|
308
|
+
return overrides ? {
|
|
309
|
+
...DEFAULT_INSIGHT_LABELS,
|
|
310
|
+
...overrides
|
|
311
|
+
} : DEFAULT_INSIGHT_LABELS;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* The state machine. Error wins; loading over an existing finding is a
|
|
315
|
+
* refresh (the previous render stays under the veil); a finding with too
|
|
316
|
+
* little history to plot is `insufficient`, not `ready` — the claim still
|
|
317
|
+
* reads, only the time plot degrades; nothing to say is `no-match` when the
|
|
318
|
+
* consumer's filter caused it and `empty` otherwise.
|
|
319
|
+
*/
|
|
320
|
+
function deriveInsightState({ status, hasFinding, hasData, insufficient, filtered }) {
|
|
321
|
+
if (status === "error") return "error";
|
|
322
|
+
if (status === "loading") return hasData ? "refreshing" : "loading";
|
|
323
|
+
if (!hasFinding) return filtered ? "no-match" : "empty";
|
|
324
|
+
return insufficient ? "insufficient" : "ready";
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* The figure's generated description: what kind of finding this is, how much
|
|
328
|
+
* it matters, the claim, the evidence that supports it, where the reading sits
|
|
329
|
+
* against the expected range, and the provenance — because a machine claim
|
|
330
|
+
* without provenance is not honest data.
|
|
331
|
+
*/
|
|
332
|
+
function buildInsightDescription({ name, state, statement, kind, severity, summary, formatters, provenance, asOfText, labels }) {
|
|
333
|
+
if (state === "loading") return labels.loading(name);
|
|
334
|
+
if (state === "error") return `${name}: ${labels.error}`;
|
|
335
|
+
if (state === "empty") return `${name}: ${labels.noData}`;
|
|
336
|
+
if (state === "no-match") return `${name}: ${labels.noMatch}`;
|
|
337
|
+
const parts = [`${labels.badge(labels.severityNames[severity], labels.kindNames[kind], severity)}. ${name}.`];
|
|
338
|
+
const observed = summary?.value != null ? formatters.formatValue(summary.value) : null;
|
|
339
|
+
const expected = summary?.expected != null ? formatters.formatValue(summary.expected) : null;
|
|
340
|
+
const deviation = summary?.value != null && summary.expected != null ? formatters.formatDeviation(summary.value, summary.expected) : null;
|
|
341
|
+
if (statement) parts.push(statement.endsWith(".") ? statement : `${statement}.`);
|
|
342
|
+
else if (observed) parts.push(labels.claim({
|
|
343
|
+
kind: labels.kindNames[kind],
|
|
344
|
+
name,
|
|
345
|
+
observed,
|
|
346
|
+
expected,
|
|
347
|
+
deviation
|
|
348
|
+
}));
|
|
349
|
+
const range = summary ? formatters.formatRange(summary.lower, summary.upper) : null;
|
|
350
|
+
if (range) parts.push(summary?.outside ? labels.outsideRange(range) : labels.insideRange(range));
|
|
351
|
+
const strength = summary ? formatters.formatStrength(summary.strength, summary.strengthKind) : null;
|
|
352
|
+
if (strength && !range) parts.push(`${strength}.`);
|
|
353
|
+
if (state === "insufficient") parts.push(labels.needsHistory);
|
|
354
|
+
if (provenance && provenance.length > 0) parts.push(`${provenance.join(" · ")}.`);
|
|
355
|
+
if (asOfText) parts.push(`${labels.asOf} ${asOfText}.`);
|
|
356
|
+
return parts.join(" ");
|
|
357
|
+
}
|
|
358
|
+
/** The plot's own `aria-label` — the form, what is on it, and where the flagged reading sits. */
|
|
359
|
+
function buildInsightChartDescription({ name, summary, formatters, atText, labels }) {
|
|
360
|
+
const evidence = summary.evidence === "none" ? labels.evidenceNames.range : labels.evidenceNames[summary.evidence];
|
|
361
|
+
return labels.chartDescription({
|
|
362
|
+
evidence,
|
|
363
|
+
name,
|
|
364
|
+
readings: summary.evidence === "spark" ? summary.count : 0,
|
|
365
|
+
observed: formatters.formatValue(summary.value),
|
|
366
|
+
expected: summary.expected != null ? formatters.formatValue(summary.expected) : null,
|
|
367
|
+
range: formatters.formatRange(summary.lower, summary.upper),
|
|
368
|
+
at: atText ?? null
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* The provenance parts, in reading order — method, confidence, sample size,
|
|
373
|
+
* detection time. Empty when the consumer reported none, which is itself
|
|
374
|
+
* worth seeing: an unattributed claim looks unattributed.
|
|
375
|
+
*/
|
|
376
|
+
function buildInsightProvenance({ method, confidence, sampleSize, detectedAtText, locale, labels }) {
|
|
377
|
+
const parts = [];
|
|
378
|
+
if (method) parts.push(method);
|
|
379
|
+
const level = insightConfidenceLevel(confidence);
|
|
380
|
+
if (level && confidence != null) parts.push(labels.confidence(labels.confidenceNames[level], formatNumber(confidence, "percent:0", locale)));
|
|
381
|
+
if (isFinite(sampleSize) && sampleSize > 0) parts.push(labels.sample(formatNumber(sampleSize, "integer", locale)));
|
|
382
|
+
if (detectedAtText) parts.push(labels.detected(detectedAtText));
|
|
383
|
+
return parts;
|
|
384
|
+
}
|
|
385
|
+
/** Writes a row's period the way the axis and the tooltip write it, so the table never disagrees with the plot. */
|
|
386
|
+
function formatInsightX(x, { xType, granularity = "day", locale, timeZone }) {
|
|
387
|
+
if (x == null) return "—";
|
|
388
|
+
if (xType === "temporal" && typeof x === "number") return formatDate(x, {
|
|
389
|
+
granularity,
|
|
390
|
+
locale,
|
|
391
|
+
timeZone
|
|
392
|
+
});
|
|
393
|
+
if (xType === "quantitative" && typeof x === "number") return formatNumber(x, "number", locale);
|
|
394
|
+
return String(x);
|
|
395
|
+
}
|
|
396
|
+
/** Whether a measure's own format is a percentage, so an absolute delta is written in points rather than percent. */
|
|
397
|
+
function insightFormatIsPercent(format) {
|
|
398
|
+
return parseArcNumberFormat(format).kind === "percent";
|
|
399
|
+
}
|
|
400
|
+
const DAY_MS = 864e5;
|
|
401
|
+
/**
|
|
402
|
+
* The granularity an axis tick may use, given the one the card reads dates at
|
|
403
|
+
* and how long the plotted window is. An axis label has a pixel budget and
|
|
404
|
+
* ellipsizes past it, so the tooltip's full form is never the axis's form: a
|
|
405
|
+
* date drops its year, a month drops its year, and a datetime drops its clock
|
|
406
|
+
* — except across a window shorter than two days, where a bare date would
|
|
407
|
+
* print the same label at both ends and the hour is the part that separates
|
|
408
|
+
* them. The hour is in the tooltip and the table either way.
|
|
409
|
+
*/
|
|
410
|
+
function insightAxisGranularity(granularity, spanMs) {
|
|
411
|
+
switch (granularity) {
|
|
412
|
+
case "day": return "day-short";
|
|
413
|
+
case "month": return "month-short";
|
|
414
|
+
case "datetime":
|
|
415
|
+
case "day-time": return spanMs != null && spanMs < 2 * DAY_MS ? "day-time" : "day-short";
|
|
416
|
+
case "time": return spanMs != null && spanMs >= 2 * DAY_MS ? "day-short" : "time";
|
|
417
|
+
default: return granularity;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
//#endregion
|
|
421
|
+
export { CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BuildInsightDescriptionInput, CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, DeriveInsightStateInput, InsightCardLabels, InsightCardSize, InsightCardState, InsightCardStatus, InsightConfidenceLevel, InsightDeltaMode, InsightEvidence, InsightFeedback, InsightGoodDirection, InsightIntervalRow, InsightKind, InsightObservation, InsightPoint, InsightPolarity, InsightRow, InsightSeverity, InsightSeverityThresholds, InsightStrengthKind, InsightStripRow, InsightSummary, InsightTextFormatters, InsightXType, NormalizeInsightOptions, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels } from "./InsightCard.model.js";
|
|
2
|
+
import { INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, InsightAxes, InsightSparkSpecOptions, InsightStripSpecOptions, buildInsightSparkSpec, buildInsightStripSpec } from "./InsightCard.chart.js";
|
|
3
|
+
import { InsightCard, InsightCardProps } from "./InsightCard.js";
|
|
4
|
+
export { type BuildInsightDescriptionInput, CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, type DeriveInsightStateInput, INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, type InsightAxes, InsightCard, type InsightCardLabels, type InsightCardProps, type InsightCardSize, type InsightCardState, type InsightCardStatus, type InsightConfidenceLevel, type InsightDeltaMode, type InsightEvidence, type InsightFeedback, type InsightGoodDirection, type InsightIntervalRow, type InsightKind, type InsightObservation, type InsightPoint, type InsightPolarity, type InsightRow, type InsightSeverity, type InsightSeverityThresholds, type InsightSparkSpecOptions, type InsightStrengthKind, type InsightStripRow, type InsightStripSpecOptions, type InsightSummary, type InsightTextFormatters, type InsightXType, type NormalizeInsightOptions, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, buildInsightSparkSpec, buildInsightStripSpec, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, buildInsightSparkSpec, buildInsightStripSpec } from "./InsightCard.chart.js";
|
|
2
|
+
import { CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels } from "./InsightCard.model.js";
|
|
3
|
+
import { InsightCard } from "./InsightCard.js";
|
|
4
|
+
export { CONFIDENCE_BOUNDS, DEFAULT_INSIGHT_LABELS, DEFAULT_SEVERITY_THRESHOLDS, INSIGHT_FLAG_PARAM, INSIGHT_HOVER_PARAM, INSIGHT_INTERVAL_DATASET, INSIGHT_POINTS_DATASET, INSIGHT_STRIP_DATASET, INSIGHT_X_TICKS_PARAM, InsightCard, buildInsightChartDescription, buildInsightDescription, buildInsightProvenance, buildInsightSparkSpec, buildInsightStripSpec, createInsightFormatters, deriveInsightPolarity, deriveInsightSeverity, deriveInsightState, formatInsightX, inferInsightXType, insightAxisGranularity, insightConfidenceLevel, insightFormatIsPercent, normalizeInsight, resolveInsightLabels };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ChartTokens } from "../../lib/vega/tokens.js";
|
|
2
|
+
import { MetricTrendAxes, MetricTrendMark, MetricTrendScale, MetricTrendXType } from "./MetricCard.model.js";
|
|
3
|
+
import { TopLevelSpec } from "vega-lite";
|
|
4
|
+
//#region src/components/MetricCard/MetricCard.chart.d.ts
|
|
5
|
+
/** The trend rows: `{ x, y }` per `MetricTrendRow` (plus `hl` and `tone` in the highlight variant). */
|
|
6
|
+
declare const METRIC_TREND_DATASET = "table";
|
|
7
|
+
/** Zero or one row `{ value }` — the target reference line. */
|
|
8
|
+
declare const METRIC_REFERENCE_DATASET = "reference";
|
|
9
|
+
/** Zero or one row — the latest valid reading, marked with a dot. */
|
|
10
|
+
declare const METRIC_LATEST_DATASET = "latest";
|
|
11
|
+
/** Highlight variant: the readings outside the window with a `seg` of `before` or `after` — the gray context runs. */
|
|
12
|
+
declare const METRIC_CONTEXT_DATASET = "context";
|
|
13
|
+
/** Highlight variant: the readings inside the window — the coloured segment. */
|
|
14
|
+
declare const METRIC_HIGHLIGHT_ROWS_DATASET = "highlightRows";
|
|
15
|
+
/** Highlight variant: the window's start and end readings — the two dots. */
|
|
16
|
+
declare const METRIC_HIGHLIGHT_POINTS_DATASET = "highlightPoints";
|
|
17
|
+
/** Highlight variant: one row `{ start, end, startY, endY, tone }` — the band behind a line and the axis anchors. */
|
|
18
|
+
declare const METRIC_HIGHLIGHT_DATASET = "highlight";
|
|
19
|
+
/** The nearest-point hover selection. */
|
|
20
|
+
declare const METRIC_HOVER_PARAM = "hover";
|
|
21
|
+
/** Responsive x tick values, recomputed by Vega when the domain or width changes. */
|
|
22
|
+
declare const METRIC_X_TICKS_PARAM = "metric_x_ticks";
|
|
23
|
+
/** Highlight variant: the window's snapped bounds, read from the `highlight` dataset — the x axis labels them. */
|
|
24
|
+
declare const METRIC_HIGHLIGHT_START_PARAM = "metric_hl_start";
|
|
25
|
+
declare const METRIC_HIGHLIGHT_END_PARAM = "metric_hl_end";
|
|
26
|
+
interface MetricTrendSpecOptions {
|
|
27
|
+
mark: MetricTrendMark;
|
|
28
|
+
scale: MetricTrendScale;
|
|
29
|
+
xType: MetricTrendXType;
|
|
30
|
+
/** Which axes to draw, default `x`. Axes share the plot's box (`autosize: fit`), so the caller reserves height for the x labels. */
|
|
31
|
+
axes?: MetricTrendAxes;
|
|
32
|
+
height: number;
|
|
33
|
+
/** Draw the target reference rule (the `reference` dataset carries the value). */
|
|
34
|
+
reference: boolean;
|
|
35
|
+
/** Wire the nearest-point hover selection and tooltip channel. */
|
|
36
|
+
tooltip: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The highlight variant: wash a band behind the window, paint the readings
|
|
39
|
+
* outside it in the context gray and the window in its polarity hue (each
|
|
40
|
+
* row's `tone`), dot its start and end, and label the window's bounds on the
|
|
41
|
+
* x axis. Reads the `context`, `highlightRows`, `highlightPoints` and
|
|
42
|
+
* `highlight` datasets and skips the `latest` dot. Pair it with `tooltip`:
|
|
43
|
+
* the hover layer is what keeps the `table` dataset in the compiled spec for
|
|
44
|
+
* a line or an area.
|
|
45
|
+
*/
|
|
46
|
+
highlight?: boolean;
|
|
47
|
+
/** Tooltip titles. */
|
|
48
|
+
xTitle: string;
|
|
49
|
+
yTitle: string;
|
|
50
|
+
/** Localised title for the target reference line's hover value. */
|
|
51
|
+
targetTitle?: string;
|
|
52
|
+
/** `arcNumber` grammar for values (`compact@en-US`). */
|
|
53
|
+
valueFormat: string;
|
|
54
|
+
/** `arcTime` grammar for temporal x in tooltips (`day@en-US@Asia/Bangkok`). */
|
|
55
|
+
timeFormat: string;
|
|
56
|
+
/** `arcTime` grammar for x-axis tick labels — the axis-length form (`day-short@en-US@Asia/Bangkok`). */
|
|
57
|
+
axisTimeFormat: string;
|
|
58
|
+
locale?: string;
|
|
59
|
+
timeZone?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Builds the sparkline: a line (or an area with a crisp line on top, or bars),
|
|
63
|
+
* an optional hairline target rule that joins the y-domain, the latest reading
|
|
64
|
+
* as a dot, a nearest-point hover layer carrying the tooltip, and — when
|
|
65
|
+
* `axes` asks for them — quiet x and/or y axes labelled through the card's own
|
|
66
|
+
* formats. Lines may crop (`scale: "auto"`); areas and bars keep a zero
|
|
67
|
+
* baseline whatever `scale` says — proportional ink is not negotiable. Gaps
|
|
68
|
+
* stay gaps: Vega-Lite's default `invalid` handling breaks the path at a null
|
|
69
|
+
* reading.
|
|
70
|
+
*
|
|
71
|
+
* With `highlight`, the series recedes to the context gray and the window is
|
|
72
|
+
* the subject: a quiet band washes its extent, its readings draw in the
|
|
73
|
+
* polarity hue (bars inside it take the hue), its start and end are dotted,
|
|
74
|
+
* and the x axis labels the window's bounds (flanking the band) before the
|
|
75
|
+
* domain ends.
|
|
76
|
+
*/
|
|
77
|
+
declare function buildMetricTrendSpec(options: MetricTrendSpecOptions, tokens: ChartTokens): TopLevelSpec;
|
|
78
|
+
//#endregion
|
|
79
|
+
export { METRIC_CONTEXT_DATASET, METRIC_HIGHLIGHT_DATASET, METRIC_HIGHLIGHT_END_PARAM, METRIC_HIGHLIGHT_POINTS_DATASET, METRIC_HIGHLIGHT_ROWS_DATASET, METRIC_HIGHLIGHT_START_PARAM, METRIC_HOVER_PARAM, METRIC_LATEST_DATASET, METRIC_REFERENCE_DATASET, METRIC_TREND_DATASET, METRIC_X_TICKS_PARAM, MetricTrendSpecOptions, buildMetricTrendSpec };
|