@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,660 @@
|
|
|
1
|
+
import { AXIS_LABEL_LIMIT_EXPR } from "../../lib/vega/axisTicks.js";
|
|
2
|
+
import { arcVegaConfig } from "../../lib/vega/config.js";
|
|
3
|
+
//#region src/components/HighlightCard/HighlightCard.chart.ts
|
|
4
|
+
/** Context plot: every reading, with `hl` and the window's `tone`. */
|
|
5
|
+
const HIGHLIGHT_TABLE_DATASET = "table";
|
|
6
|
+
/** Context plot: the readings outside the window with a `seg` of `before` or `after` — the gray runs. */
|
|
7
|
+
const HIGHLIGHT_OUTSIDE_DATASET = "outside";
|
|
8
|
+
/** Context plot: the readings inside the window — the coloured segment. */
|
|
9
|
+
const HIGHLIGHT_INSIDE_DATASET = "inside";
|
|
10
|
+
/** Context plot: the window's start and end readings — the two dots. */
|
|
11
|
+
const HIGHLIGHT_ENDPOINTS_DATASET = "endpoints";
|
|
12
|
+
/** Context plot: one row `{ start, end, tone }` — the band wash and the axis anchors. */
|
|
13
|
+
const HIGHLIGHT_BAND_DATASET = "band";
|
|
14
|
+
/** Peer strip: one row per compared window, `{ change, isHighlight, … }`. */
|
|
15
|
+
const HIGHLIGHT_PEERS_DATASET = "peers";
|
|
16
|
+
/** Peer strip: one row `{ low, high }` — the typical-range wash. */
|
|
17
|
+
const HIGHLIGHT_TYPICAL_DATASET = "typical";
|
|
18
|
+
/** Peer strip and drivers: one row `{ value: 0 }` — the hairline at no change. */
|
|
19
|
+
const HIGHLIGHT_ZERO_DATASET = "zero";
|
|
20
|
+
/** Drivers: one row per contributor, `{ key, label, value, tone, role }`. */
|
|
21
|
+
const HIGHLIGHT_DRIVERS_DATASET = "drivers";
|
|
22
|
+
/** Context plot: the nearest-reading hover selection. */
|
|
23
|
+
const HIGHLIGHT_HOVER_PARAM = "hover";
|
|
24
|
+
/** Peer strip: the hovered window. */
|
|
25
|
+
const HIGHLIGHT_PEER_HOVER_PARAM = "peer_hover";
|
|
26
|
+
/** Drivers: the hovered bar. */
|
|
27
|
+
const HIGHLIGHT_DRIVER_HOVER_PARAM = "driver_hover";
|
|
28
|
+
/** Context plot: responsive x tick values, recomputed by Vega when the domain or width changes. */
|
|
29
|
+
const HIGHLIGHT_X_TICKS_PARAM = "highlight_x_ticks";
|
|
30
|
+
/** Context plot: the window's snapped bounds, read from the `band` dataset — the x axis labels them. */
|
|
31
|
+
const HIGHLIGHT_START_PARAM = "highlight_start";
|
|
32
|
+
const HIGHLIGHT_END_PARAM = "highlight_end";
|
|
33
|
+
const POINT_SIZE = 64;
|
|
34
|
+
const BAR_WIDTH_EXPR = "min(24, bandwidth('x') * 0.7)";
|
|
35
|
+
/** Bars stay ≤ 24px however tall the rows are. */
|
|
36
|
+
const MAX_DRIVER_BAR_HEIGHT = 24;
|
|
37
|
+
const PLOT_PADDING = 6;
|
|
38
|
+
const BAND_OPACITY = .08;
|
|
39
|
+
const TYPICAL_OPACITY = .14;
|
|
40
|
+
const PEER_OPACITY = .45;
|
|
41
|
+
const RESTING_OPACITY = .75;
|
|
42
|
+
const PX_PER_Y_TICK = 48;
|
|
43
|
+
const MIN_Y_TICKS = 2;
|
|
44
|
+
const DISCRETE_DOMAIN_EXPR = `pluck(data('${HIGHLIGHT_TABLE_DATASET}'), 'x')`;
|
|
45
|
+
const DRIVER_DOMAIN_EXPR = `pluck(data('${HIGHLIGHT_DRIVERS_DATASET}'), 'key')`;
|
|
46
|
+
/**
|
|
47
|
+
* A mark colour that follows a row's polarity — the diverging ends when the
|
|
48
|
+
* move means good or bad (lightness-matched, ≥ 3:1 on both surfaces), the
|
|
49
|
+
* emphasis hue when it is neutral — and `fallback` for rows carrying none
|
|
50
|
+
* (`null`). Kept in the spec as three token values, so the spec stays
|
|
51
|
+
* structural while the data decides.
|
|
52
|
+
*
|
|
53
|
+
* `field` is the row property holding it: the context and driver rows call it
|
|
54
|
+
* `tone`, and a peer row calls it `polarity` because that row is also public
|
|
55
|
+
* API. A mismatch here paints every mark the fallback hue, so the spec tests
|
|
56
|
+
* assert the diverging values are present on each plot.
|
|
57
|
+
*/
|
|
58
|
+
function toneColor(tokens, fallback, field = "tone") {
|
|
59
|
+
return {
|
|
60
|
+
condition: [
|
|
61
|
+
{
|
|
62
|
+
test: `datum.${field} === 'positive'`,
|
|
63
|
+
value: tokens.divergingPositive
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
test: `datum.${field} === 'negative'`,
|
|
67
|
+
value: tokens.divergingNegative
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
test: `datum.${field} === 'neutral'`,
|
|
71
|
+
value: tokens.emphasis
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
value: fallback
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The window inside the whole series: a quiet band washes its extent, the
|
|
79
|
+
* readings outside it draw in the context gray, the window itself draws in its
|
|
80
|
+
* polarity hue, its start and end are dotted, and the x axis labels the
|
|
81
|
+
* window's bounds before the domain's ends. Lines may crop (`scale: "auto"`);
|
|
82
|
+
* areas and bars keep a zero baseline whatever `scale` says — proportional ink
|
|
83
|
+
* is not negotiable. Gaps stay gaps: Vega-Lite's default `invalid` handling
|
|
84
|
+
* breaks the path at a null reading.
|
|
85
|
+
*/
|
|
86
|
+
function buildHighlightContextSpec(options, tokens) {
|
|
87
|
+
const { mark, scale, xType, height, axes, tooltip, xTitle, yTitle, valueFormat, timeFormat, axisTimeFormat } = options;
|
|
88
|
+
const zero = mark !== "line" || scale === "zero";
|
|
89
|
+
const discreteX = mark === "bar" || xType === "ordinal";
|
|
90
|
+
const xTickFormat = xType === "temporal" ? axisTimeFormat : "compact";
|
|
91
|
+
const xTickKind = xType === "temporal" ? "time" : xType === "quantitative" ? "number" : "text";
|
|
92
|
+
const axisArgs = `domain('x'), width, ${discreteX}, ${JSON.stringify(xTickFormat)}, ${JSON.stringify(xTickKind)}`;
|
|
93
|
+
const anchorsArg = `, [${HIGHLIGHT_START_PARAM}, ${HIGHLIGHT_END_PARAM}]`;
|
|
94
|
+
const yTicks = Math.max(MIN_Y_TICKS, Math.round(height / PX_PER_Y_TICK));
|
|
95
|
+
const xAxisLabels = xType === "temporal" ? {
|
|
96
|
+
format: axisTimeFormat,
|
|
97
|
+
formatType: "arcTime"
|
|
98
|
+
} : xType === "quantitative" ? {
|
|
99
|
+
format: "compact",
|
|
100
|
+
formatType: "arcNumber"
|
|
101
|
+
} : {};
|
|
102
|
+
const xAxis = axes ? {
|
|
103
|
+
title: null,
|
|
104
|
+
orient: "bottom",
|
|
105
|
+
domain: true,
|
|
106
|
+
ticks: false,
|
|
107
|
+
grid: false,
|
|
108
|
+
values: { expr: HIGHLIGHT_X_TICKS_PARAM },
|
|
109
|
+
labelAngle: 0,
|
|
110
|
+
labelAlign: { expr: `arcAxisLabelAlign(datum.value, ${axisArgs}${anchorsArg})` },
|
|
111
|
+
labelFlush: false,
|
|
112
|
+
labelOverlap: false,
|
|
113
|
+
labelLimit: { expr: AXIS_LABEL_LIMIT_EXPR },
|
|
114
|
+
labelPadding: 4,
|
|
115
|
+
...xAxisLabels
|
|
116
|
+
} : null;
|
|
117
|
+
const yAxis = axes ? {
|
|
118
|
+
title: null,
|
|
119
|
+
orient: "left",
|
|
120
|
+
domain: false,
|
|
121
|
+
ticks: false,
|
|
122
|
+
grid: true,
|
|
123
|
+
tickCount: yTicks,
|
|
124
|
+
labelOverlap: true,
|
|
125
|
+
labelPadding: 6,
|
|
126
|
+
format: valueFormat,
|
|
127
|
+
formatType: "arcNumber"
|
|
128
|
+
} : null;
|
|
129
|
+
const discreteScale = { scale: { domain: { expr: DISCRETE_DOMAIN_EXPR } } };
|
|
130
|
+
const xField = mark === "bar" ? {
|
|
131
|
+
field: "x",
|
|
132
|
+
type: "ordinal",
|
|
133
|
+
sort: null,
|
|
134
|
+
axis: xAxis,
|
|
135
|
+
...discreteScale
|
|
136
|
+
} : {
|
|
137
|
+
field: "x",
|
|
138
|
+
type: xType,
|
|
139
|
+
axis: xAxis,
|
|
140
|
+
...xType === "ordinal" ? {
|
|
141
|
+
sort: null,
|
|
142
|
+
...discreteScale
|
|
143
|
+
} : { scale: {
|
|
144
|
+
nice: false,
|
|
145
|
+
...xType === "quantitative" ? { zero: false } : {}
|
|
146
|
+
} }
|
|
147
|
+
};
|
|
148
|
+
const yField = {
|
|
149
|
+
field: "y",
|
|
150
|
+
type: "quantitative",
|
|
151
|
+
axis: yAxis,
|
|
152
|
+
scale: {
|
|
153
|
+
zero,
|
|
154
|
+
nice: axes
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const tooltipChannel = [xType === "temporal" ? {
|
|
158
|
+
field: "x",
|
|
159
|
+
type: "temporal",
|
|
160
|
+
title: xTitle,
|
|
161
|
+
format: timeFormat,
|
|
162
|
+
formatType: "arcTime"
|
|
163
|
+
} : xType === "quantitative" ? {
|
|
164
|
+
field: "x",
|
|
165
|
+
type: "quantitative",
|
|
166
|
+
title: xTitle,
|
|
167
|
+
format: "number",
|
|
168
|
+
formatType: "arcNumber"
|
|
169
|
+
} : {
|
|
170
|
+
field: "x",
|
|
171
|
+
type: "nominal",
|
|
172
|
+
title: xTitle
|
|
173
|
+
}, {
|
|
174
|
+
field: "y",
|
|
175
|
+
type: "quantitative",
|
|
176
|
+
title: yTitle,
|
|
177
|
+
format: valueFormat,
|
|
178
|
+
formatType: "arcNumber"
|
|
179
|
+
}];
|
|
180
|
+
const layers = [{
|
|
181
|
+
data: { name: HIGHLIGHT_BAND_DATASET },
|
|
182
|
+
mark: {
|
|
183
|
+
type: "rect",
|
|
184
|
+
opacity: BAND_OPACITY,
|
|
185
|
+
aria: false
|
|
186
|
+
},
|
|
187
|
+
encoding: {
|
|
188
|
+
x: {
|
|
189
|
+
...xField,
|
|
190
|
+
field: "start",
|
|
191
|
+
...discreteX ? { bandPosition: 0 } : {}
|
|
192
|
+
},
|
|
193
|
+
x2: {
|
|
194
|
+
field: "end",
|
|
195
|
+
...discreteX ? { bandPosition: 1 } : {}
|
|
196
|
+
},
|
|
197
|
+
fill: toneColor(tokens, tokens.emphasis)
|
|
198
|
+
}
|
|
199
|
+
}];
|
|
200
|
+
if (mark === "bar") layers.push({
|
|
201
|
+
...tooltip ? { params: [{
|
|
202
|
+
name: HIGHLIGHT_HOVER_PARAM,
|
|
203
|
+
select: {
|
|
204
|
+
type: "point",
|
|
205
|
+
on: "pointerover",
|
|
206
|
+
clear: "pointerout",
|
|
207
|
+
encodings: ["x"]
|
|
208
|
+
}
|
|
209
|
+
}] } : {},
|
|
210
|
+
mark: {
|
|
211
|
+
type: "bar",
|
|
212
|
+
cornerRadiusEnd: 2,
|
|
213
|
+
width: { expr: BAR_WIDTH_EXPR }
|
|
214
|
+
},
|
|
215
|
+
encoding: {
|
|
216
|
+
x: xField,
|
|
217
|
+
y: yField,
|
|
218
|
+
fill: toneColor(tokens, tokens.context),
|
|
219
|
+
...tooltip ? {
|
|
220
|
+
opacity: {
|
|
221
|
+
condition: {
|
|
222
|
+
param: HIGHLIGHT_HOVER_PARAM,
|
|
223
|
+
empty: false,
|
|
224
|
+
value: 1
|
|
225
|
+
},
|
|
226
|
+
value: RESTING_OPACITY
|
|
227
|
+
},
|
|
228
|
+
tooltip: tooltipChannel
|
|
229
|
+
} : {}
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
else {
|
|
233
|
+
const outsideEncoding = {
|
|
234
|
+
x: xField,
|
|
235
|
+
y: yField,
|
|
236
|
+
detail: {
|
|
237
|
+
field: "seg",
|
|
238
|
+
type: "nominal"
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
if (mark === "area") layers.push({
|
|
242
|
+
data: { name: HIGHLIGHT_OUTSIDE_DATASET },
|
|
243
|
+
mark: {
|
|
244
|
+
type: "area",
|
|
245
|
+
fill: tokens.context,
|
|
246
|
+
fillOpacity: .12,
|
|
247
|
+
line: false,
|
|
248
|
+
interpolate: "linear"
|
|
249
|
+
},
|
|
250
|
+
encoding: outsideEncoding
|
|
251
|
+
});
|
|
252
|
+
layers.push({
|
|
253
|
+
data: { name: HIGHLIGHT_OUTSIDE_DATASET },
|
|
254
|
+
mark: {
|
|
255
|
+
type: "line",
|
|
256
|
+
stroke: tokens.context,
|
|
257
|
+
strokeWidth: 2,
|
|
258
|
+
strokeCap: "round",
|
|
259
|
+
strokeJoin: "round",
|
|
260
|
+
interpolate: "linear"
|
|
261
|
+
},
|
|
262
|
+
encoding: outsideEncoding
|
|
263
|
+
});
|
|
264
|
+
if (mark === "area") layers.push({
|
|
265
|
+
data: { name: HIGHLIGHT_INSIDE_DATASET },
|
|
266
|
+
mark: {
|
|
267
|
+
type: "area",
|
|
268
|
+
fillOpacity: .12,
|
|
269
|
+
line: false,
|
|
270
|
+
interpolate: "linear"
|
|
271
|
+
},
|
|
272
|
+
encoding: {
|
|
273
|
+
x: xField,
|
|
274
|
+
y: yField,
|
|
275
|
+
fill: toneColor(tokens, tokens.emphasis)
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
layers.push({
|
|
279
|
+
data: { name: HIGHLIGHT_INSIDE_DATASET },
|
|
280
|
+
mark: {
|
|
281
|
+
type: "line",
|
|
282
|
+
strokeWidth: 2,
|
|
283
|
+
strokeCap: "round",
|
|
284
|
+
strokeJoin: "round",
|
|
285
|
+
interpolate: "linear"
|
|
286
|
+
},
|
|
287
|
+
encoding: {
|
|
288
|
+
x: xField,
|
|
289
|
+
y: yField,
|
|
290
|
+
stroke: toneColor(tokens, tokens.emphasis)
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
const dot = {
|
|
294
|
+
type: "point",
|
|
295
|
+
filled: true,
|
|
296
|
+
size: POINT_SIZE,
|
|
297
|
+
stroke: tokens.background,
|
|
298
|
+
strokeWidth: 1.5,
|
|
299
|
+
opacity: 1,
|
|
300
|
+
aria: false
|
|
301
|
+
};
|
|
302
|
+
layers.push({
|
|
303
|
+
data: { name: HIGHLIGHT_ENDPOINTS_DATASET },
|
|
304
|
+
mark: dot,
|
|
305
|
+
encoding: {
|
|
306
|
+
x: xField,
|
|
307
|
+
y: yField,
|
|
308
|
+
fill: toneColor(tokens, tokens.emphasis)
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
if (tooltip) layers.push({
|
|
312
|
+
params: [{
|
|
313
|
+
name: HIGHLIGHT_HOVER_PARAM,
|
|
314
|
+
select: {
|
|
315
|
+
type: "point",
|
|
316
|
+
on: "pointermove",
|
|
317
|
+
nearest: true,
|
|
318
|
+
clear: "pointerout",
|
|
319
|
+
encodings: ["x"]
|
|
320
|
+
}
|
|
321
|
+
}],
|
|
322
|
+
mark: {
|
|
323
|
+
type: "point",
|
|
324
|
+
filled: true,
|
|
325
|
+
size: POINT_SIZE,
|
|
326
|
+
stroke: tokens.background,
|
|
327
|
+
strokeWidth: 1.5,
|
|
328
|
+
aria: false
|
|
329
|
+
},
|
|
330
|
+
encoding: {
|
|
331
|
+
x: xField,
|
|
332
|
+
y: yField,
|
|
333
|
+
fill: toneColor(tokens, tokens.context),
|
|
334
|
+
opacity: {
|
|
335
|
+
condition: {
|
|
336
|
+
param: HIGHLIGHT_HOVER_PARAM,
|
|
337
|
+
empty: false,
|
|
338
|
+
value: 1
|
|
339
|
+
},
|
|
340
|
+
value: 0
|
|
341
|
+
},
|
|
342
|
+
tooltip: tooltipChannel
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
const params = [{
|
|
347
|
+
name: HIGHLIGHT_START_PARAM,
|
|
348
|
+
expr: `length(data('${HIGHLIGHT_BAND_DATASET}')) ? data('${HIGHLIGHT_BAND_DATASET}')[0].start : null`
|
|
349
|
+
}, {
|
|
350
|
+
name: HIGHLIGHT_END_PARAM,
|
|
351
|
+
expr: `length(data('${HIGHLIGHT_BAND_DATASET}')) ? data('${HIGHLIGHT_BAND_DATASET}')[0].end : null`
|
|
352
|
+
}];
|
|
353
|
+
if (axes) params.push({
|
|
354
|
+
name: HIGHLIGHT_X_TICKS_PARAM,
|
|
355
|
+
expr: `arcAxisTicks(${axisArgs}${anchorsArg})`
|
|
356
|
+
});
|
|
357
|
+
return {
|
|
358
|
+
$schema: "https://vega.github.io/schema/vega-lite/v6.json",
|
|
359
|
+
width: 360,
|
|
360
|
+
height,
|
|
361
|
+
autosize: {
|
|
362
|
+
type: "fit",
|
|
363
|
+
contains: "padding"
|
|
364
|
+
},
|
|
365
|
+
padding: PLOT_PADDING,
|
|
366
|
+
background: "transparent",
|
|
367
|
+
data: { name: HIGHLIGHT_TABLE_DATASET },
|
|
368
|
+
params,
|
|
369
|
+
layer: layers,
|
|
370
|
+
config: arcVegaConfig(tokens, {
|
|
371
|
+
locale: options.locale,
|
|
372
|
+
timeZone: options.timeZone
|
|
373
|
+
})
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Every comparable window's change on ONE shared position scale, as a strip
|
|
378
|
+
* plot: the typical range as a quiet wash, a hairline at no change, one thin
|
|
379
|
+
* tick per compared window in the context gray, and the highlighted window as
|
|
380
|
+
* a solid dot in its polarity hue.
|
|
381
|
+
*
|
|
382
|
+
* A strip plot, not a summary statistic, because showing the peers is the
|
|
383
|
+
* honest way to say "unusual" — the reader sees the spread they are being
|
|
384
|
+
* asked to accept, the crowd near zero and the tail this window sits in.
|
|
385
|
+
* Every tick is also a row in the panel's table, so nothing lives only here.
|
|
386
|
+
*/
|
|
387
|
+
function buildHighlightPeersSpec(options, tokens) {
|
|
388
|
+
const { height, tooltip, windowTitle, changeTitle, changeFormat, typicalTitle } = options;
|
|
389
|
+
const xField = {
|
|
390
|
+
field: "change",
|
|
391
|
+
type: "quantitative",
|
|
392
|
+
axis: {
|
|
393
|
+
title: null,
|
|
394
|
+
orient: "bottom",
|
|
395
|
+
domain: false,
|
|
396
|
+
ticks: false,
|
|
397
|
+
grid: true,
|
|
398
|
+
tickCount: 4,
|
|
399
|
+
labelOverlap: true,
|
|
400
|
+
labelPadding: 4,
|
|
401
|
+
format: changeFormat,
|
|
402
|
+
formatType: "arcNumber"
|
|
403
|
+
},
|
|
404
|
+
scale: {
|
|
405
|
+
zero: true,
|
|
406
|
+
nice: true
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
const tooltipChannel = [{
|
|
410
|
+
field: "rangeText",
|
|
411
|
+
type: "nominal",
|
|
412
|
+
title: windowTitle
|
|
413
|
+
}, {
|
|
414
|
+
field: "change",
|
|
415
|
+
type: "quantitative",
|
|
416
|
+
title: changeTitle,
|
|
417
|
+
format: changeFormat,
|
|
418
|
+
formatType: "arcNumber"
|
|
419
|
+
}];
|
|
420
|
+
const layers = [
|
|
421
|
+
{
|
|
422
|
+
data: { name: HIGHLIGHT_TYPICAL_DATASET },
|
|
423
|
+
mark: {
|
|
424
|
+
type: "rect",
|
|
425
|
+
fill: tokens.brush,
|
|
426
|
+
opacity: TYPICAL_OPACITY,
|
|
427
|
+
aria: false
|
|
428
|
+
},
|
|
429
|
+
encoding: {
|
|
430
|
+
x: {
|
|
431
|
+
...xField,
|
|
432
|
+
field: "low"
|
|
433
|
+
},
|
|
434
|
+
x2: { field: "high" },
|
|
435
|
+
...tooltip ? { tooltip: [{
|
|
436
|
+
field: "low",
|
|
437
|
+
type: "quantitative",
|
|
438
|
+
title: typicalTitle,
|
|
439
|
+
format: changeFormat,
|
|
440
|
+
formatType: "arcNumber"
|
|
441
|
+
}, {
|
|
442
|
+
field: "high",
|
|
443
|
+
type: "quantitative",
|
|
444
|
+
title: "",
|
|
445
|
+
format: changeFormat,
|
|
446
|
+
formatType: "arcNumber"
|
|
447
|
+
}] } : {}
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
data: { name: HIGHLIGHT_ZERO_DATASET },
|
|
452
|
+
mark: {
|
|
453
|
+
type: "rule",
|
|
454
|
+
stroke: tokens.reference,
|
|
455
|
+
strokeWidth: 1,
|
|
456
|
+
opacity: .8,
|
|
457
|
+
aria: false
|
|
458
|
+
},
|
|
459
|
+
encoding: { x: {
|
|
460
|
+
...xField,
|
|
461
|
+
field: "value"
|
|
462
|
+
} }
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
...tooltip ? { params: [{
|
|
466
|
+
name: HIGHLIGHT_PEER_HOVER_PARAM,
|
|
467
|
+
select: {
|
|
468
|
+
type: "point",
|
|
469
|
+
on: "pointerover",
|
|
470
|
+
clear: "pointerout",
|
|
471
|
+
nearest: true
|
|
472
|
+
}
|
|
473
|
+
}] } : {},
|
|
474
|
+
data: { name: HIGHLIGHT_PEERS_DATASET },
|
|
475
|
+
transform: [{ filter: "!datum.isHighlight" }],
|
|
476
|
+
mark: {
|
|
477
|
+
type: "tick",
|
|
478
|
+
thickness: 1.5,
|
|
479
|
+
size: height * .5,
|
|
480
|
+
stroke: tokens.context,
|
|
481
|
+
ariaRoleDescription: "window"
|
|
482
|
+
},
|
|
483
|
+
encoding: {
|
|
484
|
+
x: xField,
|
|
485
|
+
...tooltip ? {
|
|
486
|
+
opacity: {
|
|
487
|
+
condition: {
|
|
488
|
+
param: HIGHLIGHT_PEER_HOVER_PARAM,
|
|
489
|
+
empty: false,
|
|
490
|
+
value: 1
|
|
491
|
+
},
|
|
492
|
+
value: PEER_OPACITY
|
|
493
|
+
},
|
|
494
|
+
tooltip: tooltipChannel
|
|
495
|
+
} : { opacity: { value: PEER_OPACITY } }
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
data: { name: HIGHLIGHT_PEERS_DATASET },
|
|
500
|
+
transform: [{ filter: "datum.isHighlight" }],
|
|
501
|
+
mark: {
|
|
502
|
+
type: "point",
|
|
503
|
+
filled: true,
|
|
504
|
+
size: 88,
|
|
505
|
+
stroke: tokens.background,
|
|
506
|
+
strokeWidth: 1.5,
|
|
507
|
+
opacity: 1,
|
|
508
|
+
ariaRoleDescription: "highlighted window"
|
|
509
|
+
},
|
|
510
|
+
encoding: {
|
|
511
|
+
x: xField,
|
|
512
|
+
fill: toneColor(tokens, tokens.emphasis, "polarity"),
|
|
513
|
+
...tooltip ? { tooltip: tooltipChannel } : {}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
];
|
|
517
|
+
return {
|
|
518
|
+
$schema: "https://vega.github.io/schema/vega-lite/v6.json",
|
|
519
|
+
width: 360,
|
|
520
|
+
height,
|
|
521
|
+
autosize: {
|
|
522
|
+
type: "fit",
|
|
523
|
+
contains: "padding"
|
|
524
|
+
},
|
|
525
|
+
padding: PLOT_PADDING,
|
|
526
|
+
background: "transparent",
|
|
527
|
+
data: { name: HIGHLIGHT_PEERS_DATASET },
|
|
528
|
+
layer: layers,
|
|
529
|
+
config: arcVegaConfig(tokens, {
|
|
530
|
+
locale: options.locale,
|
|
531
|
+
timeZone: options.timeZone
|
|
532
|
+
})
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* The window's change decomposed: one horizontal bar per contributor from a
|
|
537
|
+
* shared zero, positive to the right and negative to the left, in the
|
|
538
|
+
* diverging polarity hues. Sorted by absolute contribution upstream, so the
|
|
539
|
+
* biggest mover is the first row.
|
|
540
|
+
*
|
|
541
|
+
* Bars only — the names, amounts and shares are DOM text beside the plot, so
|
|
542
|
+
* every band has no padding and the bar centers line up with the rows that
|
|
543
|
+
* carry the text. A hairline at zero is always drawn: these values are signed
|
|
544
|
+
* by nature, and the reader must see which side of no-change each one is on.
|
|
545
|
+
*/
|
|
546
|
+
function buildHighlightDriversSpec(options, tokens) {
|
|
547
|
+
const { barHeight, height, tooltip, driverTitle, contributionTitle, shareTitle, valueFormat } = options;
|
|
548
|
+
const xField = {
|
|
549
|
+
field: "value",
|
|
550
|
+
type: "quantitative",
|
|
551
|
+
axis: null,
|
|
552
|
+
scale: {
|
|
553
|
+
zero: true,
|
|
554
|
+
nice: false
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
const yField = {
|
|
558
|
+
field: "key",
|
|
559
|
+
type: "nominal",
|
|
560
|
+
sort: null,
|
|
561
|
+
axis: null,
|
|
562
|
+
scale: {
|
|
563
|
+
domain: { expr: DRIVER_DOMAIN_EXPR },
|
|
564
|
+
paddingInner: 0,
|
|
565
|
+
paddingOuter: 0
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
const tooltipChannel = [
|
|
569
|
+
{
|
|
570
|
+
field: "label",
|
|
571
|
+
type: "nominal",
|
|
572
|
+
title: driverTitle
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
field: "value",
|
|
576
|
+
type: "quantitative",
|
|
577
|
+
title: contributionTitle,
|
|
578
|
+
format: valueFormat,
|
|
579
|
+
formatType: "arcNumber"
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
field: "share",
|
|
583
|
+
type: "quantitative",
|
|
584
|
+
title: shareTitle,
|
|
585
|
+
format: "percent:0",
|
|
586
|
+
formatType: "arcNumber"
|
|
587
|
+
}
|
|
588
|
+
];
|
|
589
|
+
const layers = [{
|
|
590
|
+
...tooltip ? { params: [{
|
|
591
|
+
name: HIGHLIGHT_DRIVER_HOVER_PARAM,
|
|
592
|
+
select: {
|
|
593
|
+
type: "point",
|
|
594
|
+
on: "pointerover",
|
|
595
|
+
clear: "pointerout",
|
|
596
|
+
encodings: ["y"]
|
|
597
|
+
}
|
|
598
|
+
}] } : {},
|
|
599
|
+
mark: {
|
|
600
|
+
type: "bar",
|
|
601
|
+
height: barHeight,
|
|
602
|
+
cornerRadiusEnd: 2
|
|
603
|
+
},
|
|
604
|
+
encoding: {
|
|
605
|
+
x: xField,
|
|
606
|
+
y: yField,
|
|
607
|
+
fill: toneColor(tokens, tokens.emphasis),
|
|
608
|
+
fillOpacity: {
|
|
609
|
+
condition: {
|
|
610
|
+
test: "datum.role === 'residual'",
|
|
611
|
+
value: .35
|
|
612
|
+
},
|
|
613
|
+
value: 1
|
|
614
|
+
},
|
|
615
|
+
...tooltip ? {
|
|
616
|
+
opacity: {
|
|
617
|
+
condition: {
|
|
618
|
+
param: HIGHLIGHT_DRIVER_HOVER_PARAM,
|
|
619
|
+
empty: false,
|
|
620
|
+
value: 1
|
|
621
|
+
},
|
|
622
|
+
value: RESTING_OPACITY
|
|
623
|
+
},
|
|
624
|
+
tooltip: tooltipChannel
|
|
625
|
+
} : {}
|
|
626
|
+
}
|
|
627
|
+
}, {
|
|
628
|
+
data: { name: HIGHLIGHT_ZERO_DATASET },
|
|
629
|
+
mark: {
|
|
630
|
+
type: "rule",
|
|
631
|
+
stroke: tokens.axis,
|
|
632
|
+
strokeWidth: 1,
|
|
633
|
+
opacity: .9,
|
|
634
|
+
aria: false
|
|
635
|
+
},
|
|
636
|
+
encoding: { x: {
|
|
637
|
+
...xField,
|
|
638
|
+
field: "value"
|
|
639
|
+
} }
|
|
640
|
+
}];
|
|
641
|
+
return {
|
|
642
|
+
$schema: "https://vega.github.io/schema/vega-lite/v6.json",
|
|
643
|
+
width: 240,
|
|
644
|
+
height,
|
|
645
|
+
autosize: {
|
|
646
|
+
type: "fit",
|
|
647
|
+
contains: "padding"
|
|
648
|
+
},
|
|
649
|
+
padding: 0,
|
|
650
|
+
background: "transparent",
|
|
651
|
+
data: { name: HIGHLIGHT_DRIVERS_DATASET },
|
|
652
|
+
layer: layers,
|
|
653
|
+
config: arcVegaConfig(tokens, {
|
|
654
|
+
locale: options.locale,
|
|
655
|
+
timeZone: options.timeZone
|
|
656
|
+
})
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
//#endregion
|
|
660
|
+
export { HIGHLIGHT_BAND_DATASET, HIGHLIGHT_DRIVERS_DATASET, HIGHLIGHT_DRIVER_HOVER_PARAM, HIGHLIGHT_ENDPOINTS_DATASET, HIGHLIGHT_END_PARAM, HIGHLIGHT_HOVER_PARAM, HIGHLIGHT_INSIDE_DATASET, HIGHLIGHT_OUTSIDE_DATASET, HIGHLIGHT_PEERS_DATASET, HIGHLIGHT_PEER_HOVER_PARAM, HIGHLIGHT_START_PARAM, HIGHLIGHT_TABLE_DATASET, HIGHLIGHT_TYPICAL_DATASET, HIGHLIGHT_X_TICKS_PARAM, HIGHLIGHT_ZERO_DATASET, MAX_DRIVER_BAR_HEIGHT, buildHighlightContextSpec, buildHighlightDriversSpec, buildHighlightPeersSpec };
|