@pharos-ds/charts 0.0.0-bootstrap.0 → 1.0.10

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.
Files changed (139) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/LICENSE +24 -0
  3. package/README.md +118 -0
  4. package/dist/Chart.d.ts +62 -0
  5. package/dist/Chart.d.ts.map +1 -0
  6. package/dist/Chart.js +401 -0
  7. package/dist/ChartAxis.d.ts +37 -0
  8. package/dist/ChartAxis.d.ts.map +1 -0
  9. package/dist/ChartAxis.js +233 -0
  10. package/dist/ChartContext.d.ts +4 -0
  11. package/dist/ChartContext.d.ts.map +1 -0
  12. package/dist/ChartContext.js +15 -0
  13. package/dist/ChartGrid.d.ts +26 -0
  14. package/dist/ChartGrid.d.ts.map +1 -0
  15. package/dist/ChartGrid.js +118 -0
  16. package/dist/ChartLegend.d.ts +14 -0
  17. package/dist/ChartLegend.d.ts.map +1 -0
  18. package/dist/ChartLegend.js +62 -0
  19. package/dist/ChartSwatch.d.ts +36 -0
  20. package/dist/ChartSwatch.d.ts.map +1 -0
  21. package/dist/ChartSwatch.js +85 -0
  22. package/dist/ChartTooltip.d.ts +46 -0
  23. package/dist/ChartTooltip.d.ts.map +1 -0
  24. package/dist/ChartTooltip.js +330 -0
  25. package/dist/charts.css +33 -0
  26. package/dist/dataTable.d.ts +56 -0
  27. package/dist/dataTable.d.ts.map +1 -0
  28. package/dist/dataTable.js +88 -0
  29. package/dist/formatters.d.ts +37 -0
  30. package/dist/formatters.d.ts.map +1 -0
  31. package/dist/formatters.js +156 -0
  32. package/dist/getChartColors.d.ts +67 -0
  33. package/dist/getChartColors.d.ts.map +1 -0
  34. package/dist/getChartColors.js +191 -0
  35. package/dist/index.d.ts +17 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +19 -0
  38. package/dist/layout.d.ts +40 -0
  39. package/dist/layout.d.ts.map +1 -0
  40. package/dist/layout.js +322 -0
  41. package/dist/legend.d.ts +17 -0
  42. package/dist/legend.d.ts.map +1 -0
  43. package/dist/legend.js +40 -0
  44. package/dist/markColor.d.ts +20 -0
  45. package/dist/markColor.d.ts.map +1 -0
  46. package/dist/markColor.js +56 -0
  47. package/dist/marks/area.d.ts +19 -0
  48. package/dist/marks/area.d.ts.map +1 -0
  49. package/dist/marks/area.js +121 -0
  50. package/dist/marks/band.d.ts +9 -0
  51. package/dist/marks/band.d.ts.map +1 -0
  52. package/dist/marks/band.js +64 -0
  53. package/dist/marks/bar.d.ts +21 -0
  54. package/dist/marks/bar.d.ts.map +1 -0
  55. package/dist/marks/bar.js +161 -0
  56. package/dist/marks/candlestick.d.ts +16 -0
  57. package/dist/marks/candlestick.d.ts.map +1 -0
  58. package/dist/marks/candlestick.js +110 -0
  59. package/dist/marks/dot.d.ts +19 -0
  60. package/dist/marks/dot.d.ts.map +1 -0
  61. package/dist/marks/dot.js +98 -0
  62. package/dist/marks/dotGL.d.ts +16 -0
  63. package/dist/marks/dotGL.d.ts.map +1 -0
  64. package/dist/marks/dotGL.js +231 -0
  65. package/dist/marks/dotGLInteractive.d.ts +35 -0
  66. package/dist/marks/dotGLInteractive.d.ts.map +1 -0
  67. package/dist/marks/dotGLInteractive.js +584 -0
  68. package/dist/marks/errorBar.d.ts +29 -0
  69. package/dist/marks/errorBar.d.ts.map +1 -0
  70. package/dist/marks/errorBar.js +95 -0
  71. package/dist/marks/heatmapGL.d.ts +27 -0
  72. package/dist/marks/heatmapGL.d.ts.map +1 -0
  73. package/dist/marks/heatmapGL.js +335 -0
  74. package/dist/marks/index.d.ts +13 -0
  75. package/dist/marks/index.d.ts.map +1 -0
  76. package/dist/marks/index.js +14 -0
  77. package/dist/marks/line.d.ts +18 -0
  78. package/dist/marks/line.d.ts.map +1 -0
  79. package/dist/marks/line.js +83 -0
  80. package/dist/marks/referenceLine.d.ts +37 -0
  81. package/dist/marks/referenceLine.d.ts.map +1 -0
  82. package/dist/marks/referenceLine.js +204 -0
  83. package/dist/marks/streamGL.d.ts +41 -0
  84. package/dist/marks/streamGL.d.ts.map +1 -0
  85. package/dist/marks/streamGL.js +317 -0
  86. package/dist/tooltip.d.ts +38 -0
  87. package/dist/tooltip.d.ts.map +1 -0
  88. package/dist/tooltip.js +57 -0
  89. package/dist/types.d.ts +193 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +70 -0
  92. package/dist/useChartColors.d.ts +16 -0
  93. package/dist/useChartColors.d.ts.map +1 -0
  94. package/dist/useChartColors.js +37 -0
  95. package/dist/utils.d.ts +15 -0
  96. package/dist/utils.d.ts.map +1 -0
  97. package/dist/utils.js +31 -0
  98. package/dist/webgl.d.ts +77 -0
  99. package/dist/webgl.d.ts.map +1 -0
  100. package/dist/webgl.js +235 -0
  101. package/package.json +72 -4
  102. package/src/Chart.doc.mjs +174 -0
  103. package/src/Chart.test.tsx +273 -0
  104. package/src/Chart.tsx +535 -0
  105. package/src/ChartAxis.tsx +289 -0
  106. package/src/ChartContext.ts +18 -0
  107. package/src/ChartGrid.tsx +136 -0
  108. package/src/ChartLegend.tsx +77 -0
  109. package/src/ChartSwatch.doc.mjs +17 -0
  110. package/src/ChartSwatch.tsx +89 -0
  111. package/src/ChartTooltip.tsx +452 -0
  112. package/src/charts.css.d.ts +3 -0
  113. package/src/dataTable.test.ts +86 -0
  114. package/src/dataTable.ts +124 -0
  115. package/src/formatters.ts +167 -0
  116. package/src/getChartColors.test.ts +114 -0
  117. package/src/getChartColors.ts +282 -0
  118. package/src/index.ts +88 -0
  119. package/src/layout.ts +372 -0
  120. package/src/legend.ts +44 -0
  121. package/src/markColor.ts +70 -0
  122. package/src/marks/area.tsx +142 -0
  123. package/src/marks/band.tsx +86 -0
  124. package/src/marks/bar.tsx +210 -0
  125. package/src/marks/candlestick.tsx +128 -0
  126. package/src/marks/dot.tsx +119 -0
  127. package/src/marks/dotGL.tsx +274 -0
  128. package/src/marks/dotGLInteractive.tsx +660 -0
  129. package/src/marks/errorBar.tsx +119 -0
  130. package/src/marks/heatmapGL.tsx +392 -0
  131. package/src/marks/index.ts +17 -0
  132. package/src/marks/line.tsx +118 -0
  133. package/src/marks/referenceLine.tsx +252 -0
  134. package/src/marks/streamGL.tsx +381 -0
  135. package/src/tooltip.ts +73 -0
  136. package/src/types.ts +212 -0
  137. package/src/useChartColors.ts +41 -0
  138. package/src/utils.ts +38 -0
  139. package/src/webgl.ts +262 -0
@@ -0,0 +1,64 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file marks/band.tsx
5
+ * @output Band (confidence interval) series — area between upper/lower bounds.
6
+ * Non-numeric/NaN bounds break the area into gaps instead of collapsing to a
7
+ * false zero baseline.
8
+ */
9
+
10
+ import { area as d3Area, curveMonotoneX } from 'd3-shape';
11
+ import { DEFAULT_SERIES_COLOR } from "../types.js";
12
+ import { xPixel } from "../utils.js";
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ export function band(options) {
15
+ const color = options.color ?? DEFAULT_SERIES_COLOR;
16
+ const opacity = options.opacity ?? 0.15;
17
+ return {
18
+ type: 'band',
19
+ key: `band-${options.upper}-${options.lower}`,
20
+ dataKeys: [options.upper, options.lower],
21
+ layout: {},
22
+ resolve(ctx) {
23
+ const {
24
+ data,
25
+ xKey,
26
+ xScale,
27
+ yScale
28
+ } = ctx;
29
+ const points = [];
30
+ for (let i = 0; i < data.length; i++) {
31
+ const d = data[i];
32
+ // NaN for missing/non-numeric bounds so render() can gap the area
33
+ // rather than draw a spike down to the axis.
34
+ const upperVal = d[options.upper];
35
+ const lowerVal = d[options.lower];
36
+ const upper = typeof upperVal === 'number' && Number.isFinite(upperVal) ? upperVal : NaN;
37
+ const lower = typeof lowerVal === 'number' && Number.isFinite(lowerVal) ? lowerVal : NaN;
38
+ points.push({
39
+ px: xPixel(d, xKey, xScale),
40
+ py: yScale(upper),
41
+ py0: yScale(lower),
42
+ dataIndex: i
43
+ });
44
+ }
45
+ return points;
46
+ },
47
+ render(resolved) {
48
+ if (resolved.length === 0) {
49
+ return null;
50
+ }
51
+ const areaGen = d3Area().defined(d => Number.isFinite(d.px) && Number.isFinite(d.py) && Number.isFinite(d.py0)).x(d => d.px).y0(d => d.py0).y1(d => d.py).curve(curveMonotoneX);
52
+ const pathD = areaGen(resolved) ?? '';
53
+ if (!pathD) {
54
+ return null;
55
+ }
56
+ return /*#__PURE__*/_jsx("path", {
57
+ d: pathD,
58
+ fill: color,
59
+ fillOpacity: opacity,
60
+ stroke: "none"
61
+ });
62
+ }
63
+ };
64
+ }
@@ -0,0 +1,21 @@
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
+ * Robust to missing/NaN values (bars with no finite height are skipped rather
7
+ * than drawn at the baseline) and to degenerate bandwidths (grouped bar widths
8
+ * are clamped to a non-negative value). Negative values grow downward from zero.
9
+ */
10
+ import type { SeriesDef, ColorAccessor } from '../types';
11
+ export type { ColorAccessor };
12
+ export interface BarOptions {
13
+ color?: ColorAccessor;
14
+ opacity?: number;
15
+ radius?: number;
16
+ stack?: string;
17
+ group?: string;
18
+ label?: string;
19
+ }
20
+ export declare function bar(dataKey: string, options?: BarOptions): SeriesDef;
21
+ //# sourceMappingURL=bar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/marks/bar.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAiB,aAAa,EAAC,MAAM,UAAU,CAAC;AAItE,YAAY,EAAC,aAAa,EAAC,CAAC;AAE5B,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;AAgFD,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,SAAS,CAwGxE"}
@@ -0,0 +1,161 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file marks/bar.tsx
5
+ * @output Bar series — self-contained resolve + render
6
+ * @position Standalone mark; chart root calls resolve() then render()
7
+ *
8
+ * Robust to missing/NaN values (bars with no finite height are skipped rather
9
+ * than drawn at the baseline) and to degenerate bandwidths (grouped bar widths
10
+ * are clamped to a non-negative value). Negative values grow downward from zero.
11
+ */
12
+
13
+ import { pointFill } from "../markColor.js";
14
+ import { jsx as _jsx } from "react/jsx-runtime";
15
+ /** Clamp a user opacity into [0,1], falling back when it isn't a finite number. */
16
+ function clampOpacity(value, fallback) {
17
+ const n = typeof value === 'number' && Number.isFinite(value) ? value : fallback;
18
+ return Math.min(1, Math.max(0, n));
19
+ }
20
+
21
+ /** Coerce a user length (radius/width) to a finite, non-negative number. */
22
+ function nonNegative(value, fallback) {
23
+ return typeof value === 'number' && Number.isFinite(value) ? Math.max(0, value) : fallback;
24
+ }
25
+
26
+ /** True when every coordinate is finite — a NaN/Infinity would corrupt the path. */
27
+ function rectIsFinite(x, y, w, h) {
28
+ return Number.isFinite(x) && Number.isFinite(y) && Number.isFinite(w) && Number.isFinite(h);
29
+ }
30
+
31
+ /**
32
+ * Build an SVG path for a rectangle with only the top corners rounded.
33
+ * When `r` is 0, produces a simple rect path with no curves. Returns an empty
34
+ * path (draws nothing) if any coordinate is non-finite.
35
+ */
36
+ function roundedTopRect(x, y, w, h, r) {
37
+ if (!rectIsFinite(x, y, w, h)) {
38
+ return '';
39
+ }
40
+ // Clamp radius to half the smaller dimension
41
+ const cr = Math.min(r, w / 2, h / 2);
42
+ if (!(cr > 0)) {
43
+ return `M${x},${y + h}V${y}H${x + w}V${y + h}Z`;
44
+ }
45
+ 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`;
46
+ }
47
+
48
+ /**
49
+ * Build an SVG path for a rectangle with only the bottom corners rounded.
50
+ * Returns an empty path if any coordinate is non-finite.
51
+ */
52
+ function roundedBottomRect(x, y, w, h, r) {
53
+ if (!rectIsFinite(x, y, w, h)) {
54
+ return '';
55
+ }
56
+ const cr = Math.min(r, w / 2, h / 2);
57
+ if (!(cr > 0)) {
58
+ return `M${x},${y}V${y + h}H${x + w}V${y}Z`;
59
+ }
60
+ 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`;
61
+ }
62
+ export function bar(dataKey, options = {}) {
63
+ const color = options.color;
64
+ const opacity = clampOpacity(options.opacity, 1);
65
+ const radius = nonNegative(options.radius, 4);
66
+ let barWidth = 0;
67
+ let barOffset = 0;
68
+ const seriesDef = {
69
+ type: 'bar',
70
+ key: dataKey,
71
+ dataKeys: [dataKey],
72
+ color: typeof color === 'string' ? color : undefined,
73
+ label: options.label ?? dataKey,
74
+ layout: {
75
+ stack: options.stack,
76
+ group: options.group,
77
+ includeZero: true
78
+ },
79
+ resolve(ctx, stackOffsets, groupInfo) {
80
+ const {
81
+ data,
82
+ xKey,
83
+ xScale,
84
+ yScale
85
+ } = ctx;
86
+ if (!('bandwidth' in xScale)) {
87
+ return [];
88
+ }
89
+ const bandScale = xScale;
90
+ const bw = bandScale.bandwidth();
91
+ if (groupInfo && groupInfo.count > 0) {
92
+ const gutter = bw * 0.05;
93
+ const totalGutters = gutter * (groupInfo.count - 1);
94
+ // Clamp: with many groups in a narrow band, gutters can exceed the band
95
+ // and drive the raw width negative — a negative width mirrors the path.
96
+ barWidth = Math.max(0, (bw - totalGutters) / groupInfo.count);
97
+ barOffset = groupInfo.index * (barWidth + gutter);
98
+ } else {
99
+ barWidth = bw;
100
+ barOffset = 0;
101
+ }
102
+ const points = [];
103
+ for (let i = 0; i < data.length; i++) {
104
+ const d = data[i];
105
+ // Unknown categories aren't in the band domain → NaN px so render skips
106
+ // them rather than stacking phantom bars at the origin.
107
+ const xBase = bandScale(String(d[xKey]));
108
+ const px = xBase == null ? NaN : xBase + barOffset + barWidth / 2;
109
+ let py;
110
+ let py0;
111
+ if (stackOffsets) {
112
+ const offset = stackOffsets[i];
113
+ py = offset ? yScale(offset.y1) : NaN;
114
+ py0 = offset ? yScale(offset.y0) : NaN;
115
+ } else {
116
+ const raw = d[dataKey];
117
+ const v = typeof raw === 'number' && Number.isFinite(raw) ? raw : NaN;
118
+ py = yScale(v);
119
+ py0 = yScale(0);
120
+ }
121
+ points.push({
122
+ px,
123
+ py,
124
+ py0,
125
+ dataIndex: i
126
+ });
127
+ }
128
+ return points;
129
+ },
130
+ render(resolved, ctx) {
131
+ const {
132
+ data
133
+ } = ctx;
134
+ const isTop = seriesDef._isTopOfStack !== false;
135
+ const r = isTop ? radius : 0;
136
+ if (!(barWidth > 0)) {
137
+ return null;
138
+ }
139
+ return /*#__PURE__*/_jsx("g", {
140
+ opacity: opacity,
141
+ children: resolved.map(p => {
142
+ const d = data[p.dataIndex];
143
+ if (!d || !Number.isFinite(p.px) || !Number.isFinite(p.py) || !Number.isFinite(p.py0)) {
144
+ return null;
145
+ }
146
+ const fill = pointFill(seriesDef, color, d, p.dataIndex);
147
+ const x = p.px - barWidth / 2;
148
+ const y = Math.min(p.py, p.py0);
149
+ const h = Math.max(0, Math.abs(p.py0 - p.py));
150
+ const growsUp = p.py <= p.py0;
151
+ const d_attr = growsUp ? roundedTopRect(x, y, barWidth, h, r) : roundedBottomRect(x, y, barWidth, h, r);
152
+ return /*#__PURE__*/_jsx("path", {
153
+ d: d_attr,
154
+ fill: fill
155
+ }, p.dataIndex);
156
+ })
157
+ });
158
+ }
159
+ };
160
+ return seriesDef;
161
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file marks/candlestick.tsx
3
+ * @output Candlestick (OHLC) series. Renders on both band and linear/time x
4
+ * scales; candles missing any OHLC field are skipped rather than drawn to 0.
5
+ */
6
+ import type { SeriesDef } from '../types';
7
+ export interface CandlestickOptions {
8
+ open: string;
9
+ high: string;
10
+ low: string;
11
+ close: string;
12
+ upColor?: string;
13
+ downColor?: string;
14
+ }
15
+ export declare function candlestick(options: CandlestickOptions): SeriesDef;
16
+ //# sourceMappingURL=candlestick.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candlestick.d.ts","sourceRoot":"","sources":["../../src/marks/candlestick.tsx"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,SAAS,EAA+B,MAAM,UAAU,CAAC;AAGtE,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;AAgCD,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,CA6ElE"}
@@ -0,0 +1,110 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file marks/candlestick.tsx
5
+ * @output Candlestick (OHLC) series. Renders on both band and linear/time x
6
+ * scales; candles missing any OHLC field are skipped rather than drawn to 0.
7
+ */
8
+
9
+ import { xPixel, isBandScale } from "../utils.js";
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ /** Read a datum field as a finite number, or NaN when missing/non-numeric. */
12
+ function readNumber(d, key) {
13
+ const v = d[key];
14
+ return typeof v === 'number' && Number.isFinite(v) ? v : NaN;
15
+ }
16
+
17
+ /**
18
+ * Pixel width of one candle body. On a band scale this is the bandwidth; on a
19
+ * linear/time scale it's derived from the smallest gap between adjacent points
20
+ * (falling back to a modest width when there's only one point).
21
+ */
22
+ function candleSlot(resolved, ctx) {
23
+ const {
24
+ xScale,
25
+ width
26
+ } = ctx;
27
+ if (isBandScale(xScale)) {
28
+ return xScale.bandwidth();
29
+ }
30
+ const xs = resolved.map(p => p.px).filter(x => Number.isFinite(x)).sort((a, b) => a - b);
31
+ let minGap = Infinity;
32
+ for (let i = 1; i < xs.length; i++) {
33
+ const gap = xs[i] - xs[i - 1];
34
+ if (gap > 0 && gap < minGap) {
35
+ minGap = gap;
36
+ }
37
+ }
38
+ return Number.isFinite(minGap) ? minGap : Math.min(width, 40);
39
+ }
40
+ export function candlestick(options) {
41
+ // Emitted core semantic tokens (data-viz --color-data-* tokens aren't CSS vars).
42
+ const upColor = options.upColor ?? 'var(--color-success)';
43
+ const downColor = options.downColor ?? 'var(--color-error)';
44
+ return {
45
+ type: 'candlestick',
46
+ key: `ohlc-${options.close}`,
47
+ dataKeys: [options.open, options.high, options.low, options.close],
48
+ layout: {},
49
+ resolve(ctx) {
50
+ const {
51
+ data,
52
+ xKey,
53
+ xScale,
54
+ yScale
55
+ } = ctx;
56
+ const points = [];
57
+ for (let i = 0; i < data.length; i++) {
58
+ const d = data[i];
59
+ const close = readNumber(d, options.close);
60
+ points.push({
61
+ px: xPixel(d, xKey, xScale),
62
+ py: yScale(close),
63
+ py0: yScale(0),
64
+ dataIndex: i
65
+ });
66
+ }
67
+ return points;
68
+ },
69
+ render(resolved, ctx) {
70
+ const {
71
+ data,
72
+ yScale
73
+ } = ctx;
74
+ const bodyWidth = Math.max(1, candleSlot(resolved, ctx) * 0.6);
75
+ return /*#__PURE__*/_jsx("g", {
76
+ children: resolved.map(p => {
77
+ const d = data[p.dataIndex];
78
+ const o = readNumber(d, options.open);
79
+ const c = readNumber(d, options.close);
80
+ const h = readNumber(d, options.high);
81
+ const l = readNumber(d, options.low);
82
+ // Drop candles missing any OHLC field (or an unplaceable x) — a gap
83
+ // reads more honestly than a full-height candle anchored at 0.
84
+ if (!Number.isFinite(p.px) || !Number.isFinite(o) || !Number.isFinite(c) || !Number.isFinite(h) || !Number.isFinite(l)) {
85
+ return null;
86
+ }
87
+ const col = c >= o ? upColor : downColor;
88
+ const bodyTop = yScale(Math.max(o, c));
89
+ const bodyHeight = Math.max(1, Math.abs(yScale(o) - yScale(c)));
90
+ return /*#__PURE__*/_jsxs("g", {
91
+ children: [/*#__PURE__*/_jsx("line", {
92
+ x1: p.px,
93
+ x2: p.px,
94
+ y1: yScale(h),
95
+ y2: yScale(l),
96
+ stroke: col,
97
+ strokeWidth: 1
98
+ }), /*#__PURE__*/_jsx("rect", {
99
+ x: p.px - bodyWidth / 2,
100
+ y: bodyTop,
101
+ width: bodyWidth,
102
+ height: bodyHeight,
103
+ fill: col
104
+ })]
105
+ }, p.dataIndex);
106
+ })
107
+ });
108
+ }
109
+ };
110
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @file marks/dot.tsx
3
+ * @output Dot/scatter series — self-contained resolve + render
4
+ *
5
+ * Points with missing / non-finite values are skipped rather than plotted at the
6
+ * baseline. Optional `dodge` spreads coincident points horizontally, ignoring
7
+ * non-finite ones so a single missing value can't collapse a whole dodge group.
8
+ */
9
+ import type { SeriesDef, ColorAccessor } from '../types';
10
+ export type { ColorAccessor };
11
+ export interface DotOptions {
12
+ color?: ColorAccessor;
13
+ radius?: number;
14
+ opacity?: number;
15
+ dodge?: boolean;
16
+ label?: string;
17
+ }
18
+ export declare function dot(dataKey: string, options?: DotOptions): SeriesDef;
19
+ //# sourceMappingURL=dot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../src/marks/dot.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAiB,aAAa,EAAC,MAAM,UAAU,CAAC;AAItE,YAAY,EAAC,aAAa,EAAC,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,SAAS,CA6FxE"}
@@ -0,0 +1,98 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file marks/dot.tsx
5
+ * @output Dot/scatter series — self-contained resolve + render
6
+ *
7
+ * Points with missing / non-finite values are skipped rather than plotted at the
8
+ * baseline. Optional `dodge` spreads coincident points horizontally, ignoring
9
+ * non-finite ones so a single missing value can't collapse a whole dodge group.
10
+ */
11
+
12
+ import { pointFill } from "../markColor.js";
13
+ import { xPixel } from "../utils.js";
14
+ import { jsx as _jsx } from "react/jsx-runtime";
15
+ export function dot(dataKey, options = {}) {
16
+ const color = options.color;
17
+ const radius = typeof options.radius === 'number' && Number.isFinite(options.radius) ? Math.max(0, options.radius) : 4;
18
+ const opacity = typeof options.opacity === 'number' && Number.isFinite(options.opacity) ? Math.min(1, Math.max(0, options.opacity)) : 0.8;
19
+ const dodge = options.dodge ?? false;
20
+ const seriesDef = {
21
+ type: 'dot',
22
+ key: dataKey,
23
+ dataKeys: [dataKey],
24
+ color: typeof color === 'string' ? color : undefined,
25
+ label: options.label ?? dataKey,
26
+ layout: {},
27
+ resolve(ctx) {
28
+ const {
29
+ data,
30
+ xKey,
31
+ xScale,
32
+ yScale
33
+ } = ctx;
34
+ const points = [];
35
+ for (let i = 0; i < data.length; i++) {
36
+ const d = data[i];
37
+ const raw = d[dataKey];
38
+ const v = typeof raw === 'number' && Number.isFinite(raw) ? raw : NaN;
39
+ points.push({
40
+ px: xPixel(d, xKey, xScale),
41
+ py: yScale(v),
42
+ py0: yScale(0),
43
+ dataIndex: i
44
+ });
45
+ }
46
+ if (dodge) {
47
+ // Spread points that land on the same x (e.g. dots over band categories)
48
+ // horizontally so they don't overlap, centered on the original x.
49
+ const groups = new Map();
50
+ for (const p of points) {
51
+ // Only points render() will actually draw (finite px AND py) join a
52
+ // dodge group; a missing y-value must not reserve a slot and knock the
53
+ // visible points off-center.
54
+ if (!Number.isFinite(p.px) || !Number.isFinite(p.py)) {
55
+ continue;
56
+ }
57
+ const key = Math.round(p.px);
58
+ const group = groups.get(key) ?? [];
59
+ group.push(p);
60
+ groups.set(key, group);
61
+ }
62
+ const spacing = radius * 2 + 1;
63
+ for (const group of groups.values()) {
64
+ if (group.length < 2) {
65
+ continue;
66
+ }
67
+ const mid = (group.length - 1) / 2;
68
+ group.forEach((p, idx) => {
69
+ p.px += (idx - mid) * spacing;
70
+ });
71
+ }
72
+ }
73
+ return points;
74
+ },
75
+ render(resolved, ctx) {
76
+ const {
77
+ data
78
+ } = ctx;
79
+ return /*#__PURE__*/_jsx("g", {
80
+ children: resolved.map(p => {
81
+ const d = data[p.dataIndex];
82
+ if (!d || !Number.isFinite(p.px) || !Number.isFinite(p.py)) {
83
+ return null;
84
+ }
85
+ const fill = pointFill(seriesDef, color, d, p.dataIndex);
86
+ return /*#__PURE__*/_jsx("circle", {
87
+ cx: p.px,
88
+ cy: p.py,
89
+ r: radius,
90
+ fill: fill,
91
+ opacity: opacity
92
+ }, p.dataIndex);
93
+ })
94
+ });
95
+ }
96
+ };
97
+ return seriesDef;
98
+ }
@@ -0,0 +1,16 @@
1
+ import type { SeriesDef } from '../types';
2
+ export interface DotGLOptions {
3
+ color: string;
4
+ size?: number;
5
+ opacity?: number;
6
+ }
7
+ /**
8
+ * WebGL scatter plot. Canvas mounted outside SVG for sharp Retina rendering.
9
+ *
10
+ * @example
11
+ * ```
12
+ * series={[dotGL('value', {color: '#4f46e5'})]}
13
+ * ```
14
+ */
15
+ export declare function dotGL(dataKey: string, options: DotGLOptions): SeriesDef;
16
+ //# sourceMappingURL=dotGL.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotGL.d.ts","sourceRoot":"","sources":["../../src/marks/dotGL.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAcvD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAgMD;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,SAAS,CA2CvE"}