@pharos-ds/charts 0.0.0-stage → 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.
- package/CHANGELOG.md +73 -0
- package/LICENSE +24 -0
- package/README.md +117 -2
- package/dist/Chart.d.ts +62 -0
- package/dist/Chart.d.ts.map +1 -0
- package/dist/Chart.js +401 -0
- package/dist/ChartAxis.d.ts +37 -0
- package/dist/ChartAxis.d.ts.map +1 -0
- package/dist/ChartAxis.js +233 -0
- package/dist/ChartContext.d.ts +4 -0
- package/dist/ChartContext.d.ts.map +1 -0
- package/dist/ChartContext.js +15 -0
- package/dist/ChartGrid.d.ts +26 -0
- package/dist/ChartGrid.d.ts.map +1 -0
- package/dist/ChartGrid.js +118 -0
- package/dist/ChartLegend.d.ts +14 -0
- package/dist/ChartLegend.d.ts.map +1 -0
- package/dist/ChartLegend.js +62 -0
- package/dist/ChartSwatch.d.ts +36 -0
- package/dist/ChartSwatch.d.ts.map +1 -0
- package/dist/ChartSwatch.js +85 -0
- package/dist/ChartTooltip.d.ts +46 -0
- package/dist/ChartTooltip.d.ts.map +1 -0
- package/dist/ChartTooltip.js +330 -0
- package/dist/charts.css +33 -0
- package/dist/dataTable.d.ts +56 -0
- package/dist/dataTable.d.ts.map +1 -0
- package/dist/dataTable.js +88 -0
- package/dist/formatters.d.ts +37 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +156 -0
- package/dist/getChartColors.d.ts +67 -0
- package/dist/getChartColors.d.ts.map +1 -0
- package/dist/getChartColors.js +191 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/layout.d.ts +40 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +322 -0
- package/dist/legend.d.ts +17 -0
- package/dist/legend.d.ts.map +1 -0
- package/dist/legend.js +40 -0
- package/dist/markColor.d.ts +20 -0
- package/dist/markColor.d.ts.map +1 -0
- package/dist/markColor.js +56 -0
- package/dist/marks/area.d.ts +19 -0
- package/dist/marks/area.d.ts.map +1 -0
- package/dist/marks/area.js +121 -0
- package/dist/marks/band.d.ts +9 -0
- package/dist/marks/band.d.ts.map +1 -0
- package/dist/marks/band.js +64 -0
- package/dist/marks/bar.d.ts +21 -0
- package/dist/marks/bar.d.ts.map +1 -0
- package/dist/marks/bar.js +161 -0
- package/dist/marks/candlestick.d.ts +16 -0
- package/dist/marks/candlestick.d.ts.map +1 -0
- package/dist/marks/candlestick.js +110 -0
- package/dist/marks/dot.d.ts +19 -0
- package/dist/marks/dot.d.ts.map +1 -0
- package/dist/marks/dot.js +98 -0
- package/dist/marks/dotGL.d.ts +16 -0
- package/dist/marks/dotGL.d.ts.map +1 -0
- package/dist/marks/dotGL.js +231 -0
- package/dist/marks/dotGLInteractive.d.ts +35 -0
- package/dist/marks/dotGLInteractive.d.ts.map +1 -0
- package/dist/marks/dotGLInteractive.js +584 -0
- package/dist/marks/errorBar.d.ts +29 -0
- package/dist/marks/errorBar.d.ts.map +1 -0
- package/dist/marks/errorBar.js +95 -0
- package/dist/marks/heatmapGL.d.ts +27 -0
- package/dist/marks/heatmapGL.d.ts.map +1 -0
- package/dist/marks/heatmapGL.js +335 -0
- package/dist/marks/index.d.ts +13 -0
- package/dist/marks/index.d.ts.map +1 -0
- package/dist/marks/index.js +14 -0
- package/dist/marks/line.d.ts +18 -0
- package/dist/marks/line.d.ts.map +1 -0
- package/dist/marks/line.js +83 -0
- package/dist/marks/referenceLine.d.ts +37 -0
- package/dist/marks/referenceLine.d.ts.map +1 -0
- package/dist/marks/referenceLine.js +204 -0
- package/dist/marks/streamGL.d.ts +41 -0
- package/dist/marks/streamGL.d.ts.map +1 -0
- package/dist/marks/streamGL.js +317 -0
- package/dist/tooltip.d.ts +38 -0
- package/dist/tooltip.d.ts.map +1 -0
- package/dist/tooltip.js +57 -0
- package/dist/types.d.ts +193 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +70 -0
- package/dist/useChartColors.d.ts +16 -0
- package/dist/useChartColors.d.ts.map +1 -0
- package/dist/useChartColors.js +37 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +31 -0
- package/dist/webgl.d.ts +77 -0
- package/dist/webgl.d.ts.map +1 -0
- package/dist/webgl.js +235 -0
- package/package.json +71 -3
- package/src/Chart.doc.mjs +174 -0
- package/src/Chart.test.tsx +273 -0
- package/src/Chart.tsx +535 -0
- package/src/ChartAxis.tsx +289 -0
- package/src/ChartContext.ts +18 -0
- package/src/ChartGrid.tsx +136 -0
- package/src/ChartLegend.tsx +77 -0
- package/src/ChartSwatch.doc.mjs +17 -0
- package/src/ChartSwatch.tsx +89 -0
- package/src/ChartTooltip.tsx +452 -0
- package/src/charts.css.d.ts +3 -0
- package/src/dataTable.test.ts +86 -0
- package/src/dataTable.ts +124 -0
- package/src/formatters.ts +167 -0
- package/src/getChartColors.test.ts +114 -0
- package/src/getChartColors.ts +282 -0
- package/src/index.ts +88 -0
- package/src/layout.ts +372 -0
- package/src/legend.ts +44 -0
- package/src/markColor.ts +70 -0
- package/src/marks/area.tsx +142 -0
- package/src/marks/band.tsx +86 -0
- package/src/marks/bar.tsx +210 -0
- package/src/marks/candlestick.tsx +128 -0
- package/src/marks/dot.tsx +119 -0
- package/src/marks/dotGL.tsx +274 -0
- package/src/marks/dotGLInteractive.tsx +660 -0
- package/src/marks/errorBar.tsx +119 -0
- package/src/marks/heatmapGL.tsx +392 -0
- package/src/marks/index.ts +17 -0
- package/src/marks/line.tsx +118 -0
- package/src/marks/referenceLine.tsx +252 -0
- package/src/marks/streamGL.tsx +381 -0
- package/src/tooltip.ts +73 -0
- package/src/types.ts +212 -0
- package/src/useChartColors.ts +41 -0
- package/src/utils.ts +38 -0
- package/src/webgl.ts +262 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file marks/dotGL.tsx
|
|
5
|
+
* @output WebGL scatter — canvas overlay, single draw call
|
|
6
|
+
*
|
|
7
|
+
* GL context, program, and vertex buffer are created once and reused across
|
|
8
|
+
* redraws; all are released (and the context eagerly lost) on unmount. Handles
|
|
9
|
+
* context loss/restore and skips non-finite points.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { useRef, useEffect, useMemo, useState } from 'react';
|
|
13
|
+
import { hexToGL, getWebGLContext, setupGLState, sizeCanvas, mountCanvasOverSVG, createProgram, registerContextLossHandlers, loseContext, POINT_SIZE_COMPENSATION } from "../webgl.js";
|
|
14
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
15
|
+
const VERT = `
|
|
16
|
+
attribute vec2 a_position;
|
|
17
|
+
uniform vec2 u_resolution;
|
|
18
|
+
uniform float u_size;
|
|
19
|
+
void main() {
|
|
20
|
+
vec2 clip = (a_position / u_resolution) * 2.0 - 1.0;
|
|
21
|
+
gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
|
|
22
|
+
gl_PointSize = u_size * ${POINT_SIZE_COMPENSATION.toFixed(6)};
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
const FRAG = `
|
|
26
|
+
precision mediump float;
|
|
27
|
+
uniform vec3 u_color;
|
|
28
|
+
uniform float u_opacity;
|
|
29
|
+
void main() {
|
|
30
|
+
vec2 coord = gl_PointCoord - vec2(0.5);
|
|
31
|
+
float dist = length(coord);
|
|
32
|
+
if (dist > 0.5) discard;
|
|
33
|
+
float edge = 1.0 - smoothstep(0.48, 0.5, dist);
|
|
34
|
+
float a = u_opacity * edge;
|
|
35
|
+
gl_FragColor = vec4(u_color * a, a);
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
/**
|
|
39
|
+
* Inline component returned by render() — owns the WebGL canvas lifecycle. The
|
|
40
|
+
* canvas is mounted as a sibling of the SVG (via a marker <g>) for sharp Retina
|
|
41
|
+
* output without foreignObject blur.
|
|
42
|
+
*/
|
|
43
|
+
function DotGLCanvas({
|
|
44
|
+
resolved,
|
|
45
|
+
color,
|
|
46
|
+
size,
|
|
47
|
+
opacity,
|
|
48
|
+
width,
|
|
49
|
+
height
|
|
50
|
+
}) {
|
|
51
|
+
const canvasRef = useRef(null);
|
|
52
|
+
const glRef = useRef(null);
|
|
53
|
+
const programRef = useRef(null);
|
|
54
|
+
const bufferRef = useRef(null);
|
|
55
|
+
const locsRef = useRef(null);
|
|
56
|
+
const markerRef = useRef(null);
|
|
57
|
+
// Bumped on context restore to force the draw effect to rebuild + repaint.
|
|
58
|
+
const [contextEpoch, setContextEpoch] = useState(0);
|
|
59
|
+
const positions = useMemo(() => {
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const p of resolved) {
|
|
62
|
+
if (Number.isFinite(p.px) && Number.isFinite(p.py)) {
|
|
63
|
+
out.push(p.px, p.py);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return new Float32Array(out);
|
|
67
|
+
}, [resolved]);
|
|
68
|
+
|
|
69
|
+
// Mount the canvas outside the SVG and wire context-loss recovery. The canvas
|
|
70
|
+
// element persists across resizes; only its DOM attachment is re-established.
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const marker = markerRef.current;
|
|
73
|
+
if (!marker) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!canvasRef.current) {
|
|
77
|
+
canvasRef.current = document.createElement('canvas');
|
|
78
|
+
}
|
|
79
|
+
const canvas = canvasRef.current;
|
|
80
|
+
const detach = mountCanvasOverSVG(marker, canvas, width, height);
|
|
81
|
+
const unregister = registerContextLossHandlers(canvas, () => {
|
|
82
|
+
glRef.current = null;
|
|
83
|
+
programRef.current = null;
|
|
84
|
+
bufferRef.current = null;
|
|
85
|
+
locsRef.current = null;
|
|
86
|
+
}, () => setContextEpoch(e => e + 1));
|
|
87
|
+
return () => {
|
|
88
|
+
unregister();
|
|
89
|
+
detach?.();
|
|
90
|
+
};
|
|
91
|
+
}, [width, height]);
|
|
92
|
+
|
|
93
|
+
// Draw. The context, program, and buffer are created lazily once and reused;
|
|
94
|
+
// only vertex data + uniforms are re-uploaded per redraw.
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
const canvas = canvasRef.current;
|
|
97
|
+
if (!canvas || width <= 0 || height <= 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const dpr = sizeCanvas(canvas, width, height);
|
|
101
|
+
if (!glRef.current) {
|
|
102
|
+
glRef.current = getWebGLContext(canvas);
|
|
103
|
+
}
|
|
104
|
+
const gl = glRef.current;
|
|
105
|
+
if (!gl || gl.isContextLost()) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!programRef.current) {
|
|
109
|
+
programRef.current = createProgram(gl, VERT, FRAG);
|
|
110
|
+
locsRef.current = null;
|
|
111
|
+
}
|
|
112
|
+
const program = programRef.current;
|
|
113
|
+
if (!program) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!bufferRef.current) {
|
|
117
|
+
bufferRef.current = gl.createBuffer();
|
|
118
|
+
}
|
|
119
|
+
const buffer = bufferRef.current;
|
|
120
|
+
if (!buffer) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (!locsRef.current) {
|
|
124
|
+
locsRef.current = {
|
|
125
|
+
aPosition: gl.getAttribLocation(program, 'a_position'),
|
|
126
|
+
uResolution: gl.getUniformLocation(program, 'u_resolution'),
|
|
127
|
+
uColor: gl.getUniformLocation(program, 'u_color'),
|
|
128
|
+
uSize: gl.getUniformLocation(program, 'u_size'),
|
|
129
|
+
uOpacity: gl.getUniformLocation(program, 'u_opacity')
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const locs = locsRef.current;
|
|
133
|
+
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
134
|
+
setupGLState(gl);
|
|
135
|
+
gl.useProgram(program);
|
|
136
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
137
|
+
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
|
|
138
|
+
gl.enableVertexAttribArray(locs.aPosition);
|
|
139
|
+
gl.vertexAttribPointer(locs.aPosition, 2, gl.FLOAT, false, 0, 0);
|
|
140
|
+
const [r, g, b] = hexToGL(color);
|
|
141
|
+
gl.uniform2f(locs.uResolution, width, height);
|
|
142
|
+
gl.uniform3f(locs.uColor, r, g, b);
|
|
143
|
+
gl.uniform1f(locs.uSize, size * dpr);
|
|
144
|
+
gl.uniform1f(locs.uOpacity, opacity);
|
|
145
|
+
gl.drawArrays(gl.POINTS, 0, positions.length / 2);
|
|
146
|
+
}, [width, height, color, size, opacity, positions, contextEpoch]);
|
|
147
|
+
|
|
148
|
+
// Release all GL resources on unmount.
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
return () => {
|
|
151
|
+
const gl = glRef.current;
|
|
152
|
+
if (gl) {
|
|
153
|
+
if (bufferRef.current) {
|
|
154
|
+
gl.deleteBuffer(bufferRef.current);
|
|
155
|
+
}
|
|
156
|
+
if (programRef.current) {
|
|
157
|
+
gl.deleteProgram(programRef.current);
|
|
158
|
+
}
|
|
159
|
+
loseContext(gl);
|
|
160
|
+
}
|
|
161
|
+
glRef.current = null;
|
|
162
|
+
programRef.current = null;
|
|
163
|
+
bufferRef.current = null;
|
|
164
|
+
locsRef.current = null;
|
|
165
|
+
};
|
|
166
|
+
}, []);
|
|
167
|
+
if (width <= 0 || height <= 0) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return /*#__PURE__*/_jsx("g", {
|
|
171
|
+
ref: markerRef
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* WebGL scatter plot. Canvas mounted outside SVG for sharp Retina rendering.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```
|
|
180
|
+
* series={[dotGL('value', {color: '#4f46e5'})]}
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export function dotGL(dataKey, options) {
|
|
184
|
+
const {
|
|
185
|
+
color
|
|
186
|
+
} = options;
|
|
187
|
+
const size = options.size ?? 6;
|
|
188
|
+
const opacity = options.opacity ?? 0.8;
|
|
189
|
+
return {
|
|
190
|
+
type: 'dotGL',
|
|
191
|
+
key: dataKey,
|
|
192
|
+
dataKeys: [dataKey],
|
|
193
|
+
layout: {},
|
|
194
|
+
resolve(ctx) {
|
|
195
|
+
const {
|
|
196
|
+
data,
|
|
197
|
+
xKey,
|
|
198
|
+
xScale,
|
|
199
|
+
yScale
|
|
200
|
+
} = ctx;
|
|
201
|
+
const points = [];
|
|
202
|
+
for (let i = 0; i < data.length; i++) {
|
|
203
|
+
const d = data[i];
|
|
204
|
+
let px;
|
|
205
|
+
if ('bandwidth' in xScale) {
|
|
206
|
+
px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
|
|
207
|
+
} else {
|
|
208
|
+
px = xScale(d[xKey]);
|
|
209
|
+
}
|
|
210
|
+
const v = typeof d[dataKey] === 'number' ? d[dataKey] : 0;
|
|
211
|
+
points.push({
|
|
212
|
+
px,
|
|
213
|
+
py: yScale(v),
|
|
214
|
+
py0: yScale(0),
|
|
215
|
+
dataIndex: i
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
return points;
|
|
219
|
+
},
|
|
220
|
+
render(resolved, ctx) {
|
|
221
|
+
return /*#__PURE__*/_jsx(DotGLCanvas, {
|
|
222
|
+
resolved: resolved,
|
|
223
|
+
color: color,
|
|
224
|
+
size: size,
|
|
225
|
+
opacity: opacity,
|
|
226
|
+
width: ctx.width,
|
|
227
|
+
height: ctx.height
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file marks/dotGLInteractive.tsx
|
|
3
|
+
* @output WebGL scatter with GPU color-picking for O(1) nearest-point hover
|
|
4
|
+
*
|
|
5
|
+
* Each point gets a unique color encoding its index. On hover, readPixels
|
|
6
|
+
* from an offscreen framebuffer decodes the hovered index — no JS iteration.
|
|
7
|
+
*
|
|
8
|
+
* Two GL contexts (visible + offscreen pick) plus their programs, buffers,
|
|
9
|
+
* framebuffer, and pick texture are created once and reused. The pick texture
|
|
10
|
+
* is re-allocated only when the drawing-buffer size changes, and everything is
|
|
11
|
+
* released (both contexts eagerly lost) on unmount. Recovers from context loss.
|
|
12
|
+
*/
|
|
13
|
+
import { type ReactNode } from 'react';
|
|
14
|
+
import type { SeriesDef } from '../types';
|
|
15
|
+
export interface DotGLInteractiveOptions {
|
|
16
|
+
color: string;
|
|
17
|
+
size?: number;
|
|
18
|
+
opacity?: number;
|
|
19
|
+
/** Custom tooltip renderer. Receives datum and index. */
|
|
20
|
+
renderTooltip?: (datum: Record<string, unknown>, index: number) => ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* WebGL scatter with GPU color-picking hover. O(1) hit detection via offscreen
|
|
24
|
+
* framebuffer — no JS iteration regardless of point count.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```
|
|
28
|
+
* series={[dotGLInteractive('value', {
|
|
29
|
+
* color: '#4f46e5',
|
|
30
|
+
* renderTooltip: (d, i) => <span>{d.name}: {d.value}</span>,
|
|
31
|
+
* })]}
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function dotGLInteractive(dataKey: string, options: DotGLInteractiveOptions): SeriesDef;
|
|
35
|
+
//# sourceMappingURL=dotGLInteractive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dotGLInteractive.d.ts","sourceRoot":"","sources":["../../src/marks/dotGLInteractive.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AASvD,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;CAC9E;AAgjBD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,uBAAuB,GAC/B,SAAS,CA8CX"}
|