@astryxdesign/lab 0.1.4-canary.37c19d3 → 0.1.4-canary.39ffd21
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/ChartV2/Chart.d.ts +32 -0
- package/dist/ChartV2/Chart.d.ts.map +1 -0
- package/dist/ChartV2/Chart.js +281 -0
- package/dist/ChartV2/ChartAxis.d.ts +36 -0
- package/dist/ChartV2/ChartAxis.d.ts.map +1 -0
- package/dist/ChartV2/ChartAxis.js +161 -0
- package/dist/ChartV2/ChartGrid.d.ts +20 -0
- package/dist/ChartV2/ChartGrid.d.ts.map +1 -0
- package/dist/ChartV2/ChartGrid.js +76 -0
- package/dist/ChartV2/ChartLegend.d.ts +14 -0
- package/dist/ChartV2/ChartLegend.d.ts.map +1 -0
- package/dist/ChartV2/ChartLegend.js +54 -0
- package/dist/ChartV2/ChartSwatch.d.ts +36 -0
- package/dist/ChartV2/ChartSwatch.d.ts.map +1 -0
- package/dist/ChartV2/ChartSwatch.js +82 -0
- package/dist/ChartV2/ChartTooltip.d.ts +46 -0
- package/dist/ChartV2/ChartTooltip.d.ts.map +1 -0
- package/dist/ChartV2/ChartTooltip.js +267 -0
- package/dist/ChartV2/ChartV2Context.d.ts +4 -0
- package/dist/ChartV2/ChartV2Context.d.ts.map +1 -0
- package/dist/ChartV2/ChartV2Context.js +12 -0
- package/dist/ChartV2/index.d.ts +13 -0
- package/dist/ChartV2/index.d.ts.map +1 -0
- package/dist/ChartV2/index.js +10 -0
- package/dist/ChartV2/layout.d.ts +25 -0
- package/dist/ChartV2/layout.d.ts.map +1 -0
- package/dist/ChartV2/layout.js +195 -0
- package/dist/ChartV2/legend.d.ts +18 -0
- package/dist/ChartV2/legend.d.ts.map +1 -0
- package/dist/ChartV2/legend.js +24 -0
- package/dist/ChartV2/marks/area.d.ts +19 -0
- package/dist/ChartV2/marks/area.d.ts.map +1 -0
- package/dist/ChartV2/marks/area.js +109 -0
- package/dist/ChartV2/marks/band.d.ts +9 -0
- package/dist/ChartV2/marks/band.d.ts.map +1 -0
- package/dist/ChartV2/marks/band.js +59 -0
- package/dist/ChartV2/marks/bar.d.ts +17 -0
- package/dist/ChartV2/marks/bar.d.ts.map +1 -0
- package/dist/ChartV2/marks/bar.js +120 -0
- package/dist/ChartV2/marks/candlestick.d.ts +15 -0
- package/dist/ChartV2/marks/candlestick.d.ts.map +1 -0
- package/dist/ChartV2/marks/candlestick.js +83 -0
- package/dist/ChartV2/marks/dot.d.ts +15 -0
- package/dist/ChartV2/marks/dot.d.ts.map +1 -0
- package/dist/ChartV2/marks/dot.js +65 -0
- package/dist/ChartV2/marks/dotGL.d.ts +16 -0
- package/dist/ChartV2/marks/dotGL.d.ts.map +1 -0
- package/dist/ChartV2/marks/dotGL.js +178 -0
- package/dist/ChartV2/marks/dotGLInteractive.d.ts +30 -0
- package/dist/ChartV2/marks/dotGLInteractive.d.ts.map +1 -0
- package/dist/ChartV2/marks/dotGLInteractive.js +464 -0
- package/dist/ChartV2/marks/errorBar.d.ts +27 -0
- package/dist/ChartV2/marks/errorBar.d.ts.map +1 -0
- package/dist/ChartV2/marks/errorBar.js +87 -0
- package/dist/ChartV2/marks/heatmapGL.d.ts +23 -0
- package/dist/ChartV2/marks/heatmapGL.d.ts.map +1 -0
- package/dist/ChartV2/marks/heatmapGL.js +242 -0
- package/dist/ChartV2/marks/index.d.ts +13 -0
- package/dist/ChartV2/marks/index.d.ts.map +1 -0
- package/dist/ChartV2/marks/index.js +14 -0
- package/dist/ChartV2/marks/line.d.ts +18 -0
- package/dist/ChartV2/marks/line.d.ts.map +1 -0
- package/dist/ChartV2/marks/line.js +76 -0
- package/dist/ChartV2/marks/referenceLine.d.ts +35 -0
- package/dist/ChartV2/marks/referenceLine.d.ts.map +1 -0
- package/dist/ChartV2/marks/referenceLine.js +186 -0
- package/dist/ChartV2/marks/streamGL.d.ts +36 -0
- package/dist/ChartV2/marks/streamGL.d.ts.map +1 -0
- package/dist/ChartV2/marks/streamGL.js +204 -0
- package/dist/ChartV2/tooltip.d.ts +38 -0
- package/dist/ChartV2/tooltip.d.ts.map +1 -0
- package/dist/ChartV2/tooltip.js +54 -0
- package/dist/ChartV2/types.d.ts +115 -0
- package/dist/ChartV2/types.d.ts.map +1 -0
- package/dist/ChartV2/types.js +35 -0
- package/dist/CodeEditor/CodeEditor.d.ts +1 -4
- package/dist/CodeEditor/CodeEditor.d.ts.map +1 -1
- package/dist/CodeEditor/CodeEditor.js +0 -3
- package/dist/Sankey/SankeyChart.d.ts.map +1 -1
- package/dist/Sankey/SankeyChart.js +0 -3
- package/dist/Schedule/ListView.d.ts.map +1 -1
- package/dist/Schedule/ListView.js +4 -7
- package/dist/Schedule/MonthlyView.js +2 -3
- package/dist/Schedule/Schedule.d.ts +1 -3
- package/dist/Schedule/Schedule.d.ts.map +1 -1
- package/dist/Schedule/Schedule.js +4 -9
- package/dist/Schedule/TimeGridView.js +2 -3
- package/dist/Schedule/context.d.ts +0 -2
- package/dist/Schedule/context.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -5
- package/dist/lab.css +15 -6
- package/package.json +2 -2
- package/src/ChartV2/Chart.tsx +348 -0
- package/src/ChartV2/ChartAxis.tsx +209 -0
- package/src/ChartV2/ChartGrid.tsx +99 -0
- package/src/ChartV2/ChartLegend.tsx +69 -0
- package/src/ChartV2/ChartSwatch.doc.mjs +17 -0
- package/src/ChartV2/ChartSwatch.tsx +86 -0
- package/src/ChartV2/ChartTooltip.tsx +382 -0
- package/src/ChartV2/ChartV2.doc.mjs +16 -0
- package/src/ChartV2/ChartV2Context.ts +15 -0
- package/src/ChartV2/index.ts +62 -0
- package/src/ChartV2/layout.ts +223 -0
- package/src/ChartV2/legend.ts +32 -0
- package/src/ChartV2/marks/area.tsx +122 -0
- package/src/ChartV2/marks/band.tsx +70 -0
- package/src/ChartV2/marks/bar.tsx +159 -0
- package/src/ChartV2/marks/candlestick.tsx +106 -0
- package/src/ChartV2/marks/dot.tsx +64 -0
- package/src/ChartV2/marks/dotGL.tsx +202 -0
- package/src/ChartV2/marks/dotGLInteractive.tsx +546 -0
- package/src/ChartV2/marks/errorBar.tsx +89 -0
- package/src/ChartV2/marks/heatmapGL.tsx +299 -0
- package/src/ChartV2/marks/index.ts +14 -0
- package/src/ChartV2/marks/line.tsx +94 -0
- package/src/ChartV2/marks/referenceLine.tsx +224 -0
- package/src/ChartV2/marks/streamGL.tsx +251 -0
- package/src/ChartV2/tooltip.ts +70 -0
- package/src/ChartV2/types.ts +129 -0
- package/src/CodeEditor/CodeEditor.tsx +0 -5
- package/src/Sankey/SankeyChart.tsx +0 -3
- package/src/Schedule/ListView.tsx +2 -5
- package/src/Schedule/MonthlyView.tsx +2 -2
- package/src/Schedule/Schedule.test.tsx +0 -39
- package/src/Schedule/Schedule.tsx +0 -8
- package/src/Schedule/TimeGridView.tsx +2 -2
- package/src/Schedule/context.tsx +0 -2
- package/src/index.ts +46 -5
- package/dist/InfoTip/InfoTip.d.ts +0 -58
- package/dist/InfoTip/InfoTip.d.ts.map +0 -1
- package/dist/InfoTip/InfoTip.js +0 -91
- package/dist/InfoTip/index.d.ts +0 -6
- package/dist/InfoTip/index.d.ts.map +0 -1
- package/dist/InfoTip/index.js +0 -8
- package/src/CodeEditor/CodeEditor.test.tsx +0 -21
- package/src/InfoTip/InfoTip.doc.mjs +0 -97
- package/src/InfoTip/InfoTip.test.tsx +0 -169
- package/src/InfoTip/InfoTip.tsx +0 -155
- package/src/InfoTip/index.ts +0 -10
- package/src/Sankey/SankeyChart.test.tsx +0 -77
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file layout.ts
|
|
5
|
+
* @output Computes scales, stacking, grouping, then delegates to each series.resolve()
|
|
6
|
+
* @position Called by Chart root — the single layout pass
|
|
7
|
+
*
|
|
8
|
+
* The layout engine does NOT know about specific mark types.
|
|
9
|
+
* It handles cross-series coordination (scales, stacking, grouping)
|
|
10
|
+
* then calls each series' own resolve() method.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { scaleLinear, scaleBand } from 'd3-scale';
|
|
14
|
+
import { stack as d3Stack, stackOrderNone, stackOffsetNone } from 'd3-shape';
|
|
15
|
+
export function computeLayout({
|
|
16
|
+
data,
|
|
17
|
+
xKey,
|
|
18
|
+
series,
|
|
19
|
+
width,
|
|
20
|
+
height
|
|
21
|
+
}) {
|
|
22
|
+
// ─── 1. X scale ──────────────────────────────────────────────────────
|
|
23
|
+
const xValues = data.map(d => d[xKey]);
|
|
24
|
+
const isNumericX = xValues.length > 0 && xValues.every(v => typeof v === 'number');
|
|
25
|
+
let xScale;
|
|
26
|
+
if (isNumericX) {
|
|
27
|
+
const nums = xValues;
|
|
28
|
+
xScale = scaleLinear().domain([Math.min(...nums), Math.max(...nums)]).range([0, width]).nice();
|
|
29
|
+
} else {
|
|
30
|
+
xScale = scaleBand().domain(xValues.map(String)).range([0, width]).padding(0.2);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ─── 2. Y domain from all series dataKeys ────────────────────────────
|
|
34
|
+
const allKeys = new Set();
|
|
35
|
+
let includeZero = false;
|
|
36
|
+
for (const s of series) {
|
|
37
|
+
for (const k of s.dataKeys) {
|
|
38
|
+
allKeys.add(k);
|
|
39
|
+
}
|
|
40
|
+
if (s.layout.includeZero) {
|
|
41
|
+
includeZero = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Collect which keys are stacked together so we can compute stacked extents
|
|
46
|
+
const stackGroupKeys = new Map();
|
|
47
|
+
for (const s of series) {
|
|
48
|
+
if (s.layout.stack) {
|
|
49
|
+
const group = stackGroupKeys.get(s.layout.stack) ?? [];
|
|
50
|
+
group.push(s.dataKeys[0]);
|
|
51
|
+
stackGroupKeys.set(s.layout.stack, group);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
let yMin = Infinity,
|
|
55
|
+
yMax = -Infinity;
|
|
56
|
+
|
|
57
|
+
// For stacked series, compute the sum at each data point
|
|
58
|
+
const stackedKeys = new Set();
|
|
59
|
+
for (const [, keys] of stackGroupKeys) {
|
|
60
|
+
for (const k of keys) {
|
|
61
|
+
stackedKeys.add(k);
|
|
62
|
+
}
|
|
63
|
+
for (const d of data) {
|
|
64
|
+
let sum = 0;
|
|
65
|
+
for (const k of keys) {
|
|
66
|
+
const v = d[k];
|
|
67
|
+
if (typeof v === 'number') {
|
|
68
|
+
sum += v;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (sum > yMax) {
|
|
72
|
+
yMax = sum;
|
|
73
|
+
}
|
|
74
|
+
if (sum < yMin) {
|
|
75
|
+
yMin = sum;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// For non-stacked series, use individual values
|
|
81
|
+
for (const d of data) {
|
|
82
|
+
for (const k of allKeys) {
|
|
83
|
+
if (stackedKeys.has(k)) {
|
|
84
|
+
continue;
|
|
85
|
+
} // already handled above
|
|
86
|
+
const v = d[k];
|
|
87
|
+
if (typeof v === 'number') {
|
|
88
|
+
if (v < yMin) {
|
|
89
|
+
yMin = v;
|
|
90
|
+
}
|
|
91
|
+
if (v > yMax) {
|
|
92
|
+
yMax = v;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (includeZero) {
|
|
98
|
+
if (yMin > 0) {
|
|
99
|
+
yMin = 0;
|
|
100
|
+
}
|
|
101
|
+
if (yMax < 0) {
|
|
102
|
+
yMax = 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const yScale = scaleLinear().domain([yMin, yMax]).range([height, 0]).nice();
|
|
106
|
+
|
|
107
|
+
// ─── 3. Stacking ─────────────────────────────────────────────────────
|
|
108
|
+
const stackGroups = new Map();
|
|
109
|
+
for (const s of series) {
|
|
110
|
+
if (s.layout.stack) {
|
|
111
|
+
const group = stackGroups.get(s.layout.stack) ?? [];
|
|
112
|
+
group.push(s.dataKeys[0]);
|
|
113
|
+
stackGroups.set(s.layout.stack, group);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const stackedData = new Map();
|
|
117
|
+
for (const [, keys] of stackGroups) {
|
|
118
|
+
const stackGen = d3Stack().keys(keys).order(stackOrderNone).offset(stackOffsetNone);
|
|
119
|
+
const stacked = stackGen(data);
|
|
120
|
+
for (const layer of stacked) {
|
|
121
|
+
stackedData.set(layer.key, layer.map(d => ({
|
|
122
|
+
y0: d[0],
|
|
123
|
+
y1: d[1]
|
|
124
|
+
})));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── 4. Bar grouping ─────────────────────────────────────────────────
|
|
129
|
+
// Bars can be grouped (side-by-side) whether or not they are stacked.
|
|
130
|
+
// For grouped stacks, each unique stack group name within the same bar
|
|
131
|
+
// group gets its own sub-band. For ungrouped non-stacked bars with a
|
|
132
|
+
// group key, each series gets its own sub-band.
|
|
133
|
+
const barGroups = new Map();
|
|
134
|
+
for (const s of series) {
|
|
135
|
+
if (s.type === 'bar' && s.layout.group) {
|
|
136
|
+
const group = barGroups.get(s.layout.group) ?? [];
|
|
137
|
+
// For grouped stacks: use the stack name as the group slot identifier
|
|
138
|
+
// so all series in the same stack share one slot.
|
|
139
|
+
const slotKey = s.layout.stack ?? s.key;
|
|
140
|
+
if (!group.includes(slotKey)) {
|
|
141
|
+
group.push(slotKey);
|
|
142
|
+
}
|
|
143
|
+
barGroups.set(s.layout.group, group);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ─── 5. Resolve each series ──────────────────────────────────────────
|
|
148
|
+
const ctx = {
|
|
149
|
+
data,
|
|
150
|
+
xKey,
|
|
151
|
+
xScale,
|
|
152
|
+
yScale,
|
|
153
|
+
width,
|
|
154
|
+
height
|
|
155
|
+
};
|
|
156
|
+
const resolved = new Map();
|
|
157
|
+
|
|
158
|
+
// Determine which series is the topmost in each stack group
|
|
159
|
+
const stackTopKeys = new Set();
|
|
160
|
+
for (const [, keys] of stackGroups) {
|
|
161
|
+
// Last key in the stack group is rendered on top
|
|
162
|
+
if (keys.length > 0) {
|
|
163
|
+
stackTopKeys.add(keys[keys.length - 1]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const s of series) {
|
|
167
|
+
const stackOffsets = stackedData.get(s.dataKeys[0]);
|
|
168
|
+
|
|
169
|
+
// Mark whether this series is the topmost in its stack
|
|
170
|
+
if (s.layout.stack) {
|
|
171
|
+
s._isTopOfStack = stackTopKeys.has(s.dataKeys[0]);
|
|
172
|
+
} else {
|
|
173
|
+
s._isTopOfStack = true;
|
|
174
|
+
}
|
|
175
|
+
let groupInfo;
|
|
176
|
+
if (s.layout.group) {
|
|
177
|
+
const groupKeys = barGroups.get(s.layout.group);
|
|
178
|
+
if (groupKeys) {
|
|
179
|
+
// For grouped stacks, the slot key is the stack name
|
|
180
|
+
const slotKey = s.layout.stack ?? s.key;
|
|
181
|
+
groupInfo = {
|
|
182
|
+
index: groupKeys.indexOf(slotKey),
|
|
183
|
+
count: groupKeys.length
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const points = s.resolve(ctx, stackOffsets, groupInfo);
|
|
188
|
+
resolved.set(s.key, points);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
xScale,
|
|
192
|
+
yScale,
|
|
193
|
+
resolved
|
|
194
|
+
};
|
|
195
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file legend.ts
|
|
3
|
+
* @output Legend utility — derives legend items from series definitions
|
|
4
|
+
* @position Used by Chart to bridge series → legend items
|
|
5
|
+
*/
|
|
6
|
+
import { type SeriesDef } from './types';
|
|
7
|
+
export interface LegendItem {
|
|
8
|
+
label: string;
|
|
9
|
+
color: string;
|
|
10
|
+
/** Mark type — determines swatch shape (square for bar, line for everything else) */
|
|
11
|
+
type?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Derive legend items from series definitions.
|
|
15
|
+
* Skips utility marks and series without a color.
|
|
16
|
+
*/
|
|
17
|
+
export declare function deriveLegendItems(series: readonly SeriesDef[]): LegendItem[];
|
|
18
|
+
//# sourceMappingURL=legend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legend.d.ts","sourceRoot":"","sources":["../../src/ChartV2/legend.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,UAAU,EAAE,CAI5E"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file legend.ts
|
|
5
|
+
* @output Legend utility — derives legend items from series definitions
|
|
6
|
+
* @position Used by Chart to bridge series → legend items
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { isUtilityMarkType } from "./types.js";
|
|
10
|
+
function hasLegendColor(series) {
|
|
11
|
+
return !isUtilityMarkType(series.type) && series.color != null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Derive legend items from series definitions.
|
|
16
|
+
* Skips utility marks and series without a color.
|
|
17
|
+
*/
|
|
18
|
+
export function deriveLegendItems(series) {
|
|
19
|
+
return series.filter(hasLegendColor).map(s => ({
|
|
20
|
+
label: s.label ?? s.key,
|
|
21
|
+
color: s.color,
|
|
22
|
+
type: s.type
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SeriesDef } from '../types';
|
|
2
|
+
declare const CURVES: {
|
|
3
|
+
readonly linear: import("d3-shape").CurveFactory;
|
|
4
|
+
readonly monotone: import("d3-shape").CurveFactory;
|
|
5
|
+
readonly natural: import("d3-shape").CurveFactory;
|
|
6
|
+
readonly step: import("d3-shape").CurveFactory;
|
|
7
|
+
};
|
|
8
|
+
export interface AreaOptions {
|
|
9
|
+
color?: string;
|
|
10
|
+
opacity?: number;
|
|
11
|
+
curve?: keyof typeof CURVES;
|
|
12
|
+
stack?: string;
|
|
13
|
+
gradient?: boolean;
|
|
14
|
+
stroke?: boolean;
|
|
15
|
+
label?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function area(dataKey: string, options?: AreaOptions): SeriesDef;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=area.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/area.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAGvD,QAAA,MAAM,MAAM;;;;;CAKF,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,OAAO,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,SAAS,CAsF1E"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file marks/area.tsx
|
|
5
|
+
* @output Area series — fill under line with stacking + gradient support
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { area as d3Area, curveLinear, curveMonotoneX, curveNatural, curveStep } from 'd3-shape';
|
|
9
|
+
import { line as d3Line } from 'd3-shape';
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
+
const CURVES = {
|
|
12
|
+
linear: curveLinear,
|
|
13
|
+
monotone: curveMonotoneX,
|
|
14
|
+
natural: curveNatural,
|
|
15
|
+
step: curveStep
|
|
16
|
+
};
|
|
17
|
+
export function area(dataKey, options = {}) {
|
|
18
|
+
const color = options.color ?? 'var(--color-chart-1)';
|
|
19
|
+
const opacity = options.opacity ?? 0.3;
|
|
20
|
+
const curve = options.curve ?? 'monotone';
|
|
21
|
+
const gradient = options.gradient ?? false;
|
|
22
|
+
const stroke = options.stroke ?? true;
|
|
23
|
+
return {
|
|
24
|
+
type: 'area',
|
|
25
|
+
key: dataKey,
|
|
26
|
+
dataKeys: [dataKey],
|
|
27
|
+
color,
|
|
28
|
+
label: options.label ?? dataKey,
|
|
29
|
+
layout: {
|
|
30
|
+
stack: options.stack,
|
|
31
|
+
includeZero: true
|
|
32
|
+
},
|
|
33
|
+
resolve(ctx, stackOffsets) {
|
|
34
|
+
const {
|
|
35
|
+
data,
|
|
36
|
+
xKey,
|
|
37
|
+
xScale,
|
|
38
|
+
yScale
|
|
39
|
+
} = ctx;
|
|
40
|
+
const points = [];
|
|
41
|
+
for (let i = 0; i < data.length; i++) {
|
|
42
|
+
const d = data[i];
|
|
43
|
+
let px;
|
|
44
|
+
if ('bandwidth' in xScale) {
|
|
45
|
+
px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
|
|
46
|
+
} else {
|
|
47
|
+
px = xScale(d[xKey]);
|
|
48
|
+
}
|
|
49
|
+
let py, py0;
|
|
50
|
+
if (stackOffsets) {
|
|
51
|
+
py = yScale(stackOffsets[i].y1);
|
|
52
|
+
py0 = yScale(stackOffsets[i].y0);
|
|
53
|
+
} else {
|
|
54
|
+
const v = typeof d[dataKey] === 'number' ? d[dataKey] : 0;
|
|
55
|
+
py = yScale(v);
|
|
56
|
+
py0 = yScale(0);
|
|
57
|
+
}
|
|
58
|
+
points.push({
|
|
59
|
+
px,
|
|
60
|
+
py,
|
|
61
|
+
py0,
|
|
62
|
+
dataIndex: i
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return points;
|
|
66
|
+
},
|
|
67
|
+
render(resolved) {
|
|
68
|
+
if (resolved.length === 0) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const curveFactory = CURVES[curve];
|
|
72
|
+
const areaGen = d3Area().x(d => d.px).y0(d => d.py0).y1(d => d.py).curve(curveFactory);
|
|
73
|
+
const pathD = areaGen(resolved) ?? '';
|
|
74
|
+
const lineGen = d3Line().x(d => d.px).y(d => d.py).curve(curveFactory);
|
|
75
|
+
const strokeD = lineGen(resolved) ?? '';
|
|
76
|
+
const gradientId = `area-grad-${dataKey}`;
|
|
77
|
+
return /*#__PURE__*/_jsxs("g", {
|
|
78
|
+
children: [gradient && /*#__PURE__*/_jsx("defs", {
|
|
79
|
+
children: /*#__PURE__*/_jsxs("linearGradient", {
|
|
80
|
+
id: gradientId,
|
|
81
|
+
x1: "0",
|
|
82
|
+
y1: "0",
|
|
83
|
+
x2: "0",
|
|
84
|
+
y2: "1",
|
|
85
|
+
children: [/*#__PURE__*/_jsx("stop", {
|
|
86
|
+
offset: "0%",
|
|
87
|
+
stopColor: color,
|
|
88
|
+
stopOpacity: opacity
|
|
89
|
+
}), /*#__PURE__*/_jsx("stop", {
|
|
90
|
+
offset: "100%",
|
|
91
|
+
stopColor: color,
|
|
92
|
+
stopOpacity: 0
|
|
93
|
+
})]
|
|
94
|
+
})
|
|
95
|
+
}), /*#__PURE__*/_jsx("path", {
|
|
96
|
+
d: pathD,
|
|
97
|
+
fill: gradient ? `url(#${gradientId})` : color,
|
|
98
|
+
fillOpacity: gradient ? 1 : opacity,
|
|
99
|
+
stroke: "none"
|
|
100
|
+
}), stroke && /*#__PURE__*/_jsx("path", {
|
|
101
|
+
d: strokeD,
|
|
102
|
+
fill: "none",
|
|
103
|
+
stroke: color,
|
|
104
|
+
strokeWidth: 2
|
|
105
|
+
})]
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"band.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/band.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAGvD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAmDpD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file marks/band.tsx
|
|
5
|
+
* @output Band (confidence interval) series
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { area as d3Area, curveMonotoneX } from 'd3-shape';
|
|
9
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
|
+
export function band(options) {
|
|
11
|
+
const color = options.color ?? 'var(--color-chart-1)';
|
|
12
|
+
const opacity = options.opacity ?? 0.15;
|
|
13
|
+
return {
|
|
14
|
+
type: 'band',
|
|
15
|
+
key: `band-${options.upper}-${options.lower}`,
|
|
16
|
+
dataKeys: [options.upper, options.lower],
|
|
17
|
+
layout: {},
|
|
18
|
+
resolve(ctx) {
|
|
19
|
+
const {
|
|
20
|
+
data,
|
|
21
|
+
xKey,
|
|
22
|
+
xScale,
|
|
23
|
+
yScale
|
|
24
|
+
} = ctx;
|
|
25
|
+
const points = [];
|
|
26
|
+
for (let i = 0; i < data.length; i++) {
|
|
27
|
+
const d = data[i];
|
|
28
|
+
let px;
|
|
29
|
+
if ('bandwidth' in xScale) {
|
|
30
|
+
px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
|
|
31
|
+
} else {
|
|
32
|
+
px = xScale(d[xKey]);
|
|
33
|
+
}
|
|
34
|
+
const upper = typeof d[options.upper] === 'number' ? d[options.upper] : 0;
|
|
35
|
+
const lower = typeof d[options.lower] === 'number' ? d[options.lower] : 0;
|
|
36
|
+
points.push({
|
|
37
|
+
px,
|
|
38
|
+
py: yScale(upper),
|
|
39
|
+
py0: yScale(lower),
|
|
40
|
+
dataIndex: i
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return points;
|
|
44
|
+
},
|
|
45
|
+
render(resolved) {
|
|
46
|
+
if (resolved.length === 0) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const areaGen = d3Area().x(d => d.px).y0(d => d.py0).y1(d => d.py).curve(curveMonotoneX);
|
|
50
|
+
const pathD = areaGen(resolved) ?? '';
|
|
51
|
+
return /*#__PURE__*/_jsx("path", {
|
|
52
|
+
d: pathD,
|
|
53
|
+
fill: color,
|
|
54
|
+
fillOpacity: opacity,
|
|
55
|
+
stroke: "none"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file marks/bar.tsx
|
|
3
|
+
* @output Bar series — self-contained resolve + render
|
|
4
|
+
* @position Standalone mark; chart root calls resolve() then render()
|
|
5
|
+
*/
|
|
6
|
+
import type { SeriesDef } from '../types';
|
|
7
|
+
export type ColorAccessor = string | ((datum: Record<string, unknown>, index: number) => string);
|
|
8
|
+
export interface BarOptions {
|
|
9
|
+
color?: ColorAccessor;
|
|
10
|
+
opacity?: number;
|
|
11
|
+
radius?: number;
|
|
12
|
+
stack?: string;
|
|
13
|
+
group?: string;
|
|
14
|
+
label?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function bar(dataKey: string, options?: BarOptions): SeriesDef;
|
|
17
|
+
//# sourceMappingURL=bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/bar.tsx"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAGvD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgDD,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,SAAS,CAwFxE"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file marks/bar.tsx
|
|
6
|
+
* @output Bar series — self-contained resolve + render
|
|
7
|
+
* @position Standalone mark; chart root calls resolve() then render()
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Build an SVG path for a rectangle with only the top corners rounded.
|
|
12
|
+
* When `r` is 0, produces a simple rect path with no curves.
|
|
13
|
+
*/
|
|
14
|
+
function roundedTopRect(x, y, w, h, r) {
|
|
15
|
+
// Clamp radius to half the smaller dimension
|
|
16
|
+
const cr = Math.min(r, w / 2, h / 2);
|
|
17
|
+
if (cr <= 0) {
|
|
18
|
+
return `M${x},${y + h}V${y}H${x + w}V${y + h}Z`;
|
|
19
|
+
}
|
|
20
|
+
return `M${x},${y + h}` + `V${y + cr}Q${x},${y} ${x + cr},${y}` + `H${x + w - cr}Q${x + w},${y} ${x + w},${y + cr}` + `V${y + h}Z`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Build an SVG path for a rectangle with only the bottom corners rounded.
|
|
25
|
+
*/
|
|
26
|
+
function roundedBottomRect(x, y, w, h, r) {
|
|
27
|
+
const cr = Math.min(r, w / 2, h / 2);
|
|
28
|
+
if (cr <= 0) {
|
|
29
|
+
return `M${x},${y}V${y + h}H${x + w}V${y}Z`;
|
|
30
|
+
}
|
|
31
|
+
return `M${x},${y}` + `V${y + h - cr}Q${x},${y + h} ${x + cr},${y + h}` + `H${x + w - cr}Q${x + w},${y + h} ${x + w},${y + h - cr}` + `V${y}Z`;
|
|
32
|
+
}
|
|
33
|
+
export function bar(dataKey, options = {}) {
|
|
34
|
+
const color = options.color ?? 'var(--color-chart-1)';
|
|
35
|
+
const opacity = options.opacity ?? 1;
|
|
36
|
+
const radius = options.radius ?? 4;
|
|
37
|
+
let barWidth = 0;
|
|
38
|
+
let barOffset = 0;
|
|
39
|
+
const seriesDef = {
|
|
40
|
+
type: 'bar',
|
|
41
|
+
key: dataKey,
|
|
42
|
+
dataKeys: [dataKey],
|
|
43
|
+
color: typeof color === 'string' ? color : undefined,
|
|
44
|
+
label: options.label ?? dataKey,
|
|
45
|
+
layout: {
|
|
46
|
+
stack: options.stack,
|
|
47
|
+
group: options.group,
|
|
48
|
+
includeZero: true
|
|
49
|
+
},
|
|
50
|
+
resolve(ctx, stackOffsets, groupInfo) {
|
|
51
|
+
const {
|
|
52
|
+
data,
|
|
53
|
+
xKey,
|
|
54
|
+
xScale,
|
|
55
|
+
yScale
|
|
56
|
+
} = ctx;
|
|
57
|
+
if (!('bandwidth' in xScale)) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
const bandScale = xScale;
|
|
61
|
+
const bw = bandScale.bandwidth();
|
|
62
|
+
if (groupInfo) {
|
|
63
|
+
const gutter = bw * 0.05;
|
|
64
|
+
const totalGutters = gutter * (groupInfo.count - 1);
|
|
65
|
+
barWidth = (bw - totalGutters) / groupInfo.count;
|
|
66
|
+
barOffset = groupInfo.index * (barWidth + gutter);
|
|
67
|
+
} else {
|
|
68
|
+
barWidth = bw;
|
|
69
|
+
barOffset = 0;
|
|
70
|
+
}
|
|
71
|
+
const points = [];
|
|
72
|
+
for (let i = 0; i < data.length; i++) {
|
|
73
|
+
const d = data[i];
|
|
74
|
+
const xBase = bandScale(String(d[xKey])) ?? 0;
|
|
75
|
+
const px = xBase + barOffset + barWidth / 2;
|
|
76
|
+
let py;
|
|
77
|
+
let py0;
|
|
78
|
+
if (stackOffsets) {
|
|
79
|
+
py = yScale(stackOffsets[i].y1);
|
|
80
|
+
py0 = yScale(stackOffsets[i].y0);
|
|
81
|
+
} else {
|
|
82
|
+
const v = typeof d[dataKey] === 'number' ? d[dataKey] : 0;
|
|
83
|
+
py = yScale(v);
|
|
84
|
+
py0 = yScale(0);
|
|
85
|
+
}
|
|
86
|
+
points.push({
|
|
87
|
+
px,
|
|
88
|
+
py,
|
|
89
|
+
py0,
|
|
90
|
+
dataIndex: i
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return points;
|
|
94
|
+
},
|
|
95
|
+
render(resolved, ctx) {
|
|
96
|
+
const {
|
|
97
|
+
data
|
|
98
|
+
} = ctx;
|
|
99
|
+
const isTop = seriesDef._isTopOfStack !== false;
|
|
100
|
+
const r = isTop ? radius : 0;
|
|
101
|
+
return /*#__PURE__*/_jsx("g", {
|
|
102
|
+
opacity: opacity,
|
|
103
|
+
children: resolved.map((p, i) => {
|
|
104
|
+
const d = data[p.dataIndex];
|
|
105
|
+
const fill = typeof color === 'function' ? color(d, p.dataIndex) : color;
|
|
106
|
+
const x = p.px - barWidth / 2;
|
|
107
|
+
const y = Math.min(p.py, p.py0);
|
|
108
|
+
const h = Math.max(0, Math.abs(p.py0 - p.py));
|
|
109
|
+
const growsUp = p.py <= p.py0;
|
|
110
|
+
const d_attr = growsUp ? roundedTopRect(x, y, barWidth, h, r) : roundedBottomRect(x, y, barWidth, h, r);
|
|
111
|
+
return /*#__PURE__*/_jsx("path", {
|
|
112
|
+
d: d_attr,
|
|
113
|
+
fill: fill
|
|
114
|
+
}, i);
|
|
115
|
+
})
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
return seriesDef;
|
|
120
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file marks/candlestick.tsx
|
|
3
|
+
* @output Candlestick (OHLC) series
|
|
4
|
+
*/
|
|
5
|
+
import type { SeriesDef } from '../types';
|
|
6
|
+
export interface CandlestickOptions {
|
|
7
|
+
open: string;
|
|
8
|
+
high: string;
|
|
9
|
+
low: string;
|
|
10
|
+
close: string;
|
|
11
|
+
upColor?: string;
|
|
12
|
+
downColor?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function candlestick(options: CandlestickOptions): SeriesDef;
|
|
15
|
+
//# sourceMappingURL=candlestick.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candlestick.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/candlestick.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAGvD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,CAsFlE"}
|