@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,83 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file marks/candlestick.tsx
|
|
6
|
+
* @output Candlestick (OHLC) series
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export function candlestick(options) {
|
|
10
|
+
const upColor = options.upColor ?? 'var(--color-positive)';
|
|
11
|
+
const downColor = options.downColor ?? 'var(--color-negative)';
|
|
12
|
+
return {
|
|
13
|
+
type: 'candlestick',
|
|
14
|
+
key: `ohlc-${options.close}`,
|
|
15
|
+
dataKeys: [options.open, options.high, options.low, options.close],
|
|
16
|
+
layout: {},
|
|
17
|
+
resolve(ctx) {
|
|
18
|
+
const {
|
|
19
|
+
data,
|
|
20
|
+
xKey,
|
|
21
|
+
xScale,
|
|
22
|
+
yScale
|
|
23
|
+
} = ctx;
|
|
24
|
+
const points = [];
|
|
25
|
+
for (let i = 0; i < data.length; i++) {
|
|
26
|
+
const d = data[i];
|
|
27
|
+
let px;
|
|
28
|
+
if ('bandwidth' in xScale) {
|
|
29
|
+
px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
|
|
30
|
+
} else {
|
|
31
|
+
px = xScale(d[xKey]);
|
|
32
|
+
}
|
|
33
|
+
const close = typeof d[options.close] === 'number' ? d[options.close] : 0;
|
|
34
|
+
points.push({
|
|
35
|
+
px,
|
|
36
|
+
py: yScale(close),
|
|
37
|
+
py0: yScale(0),
|
|
38
|
+
dataIndex: i
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return points;
|
|
42
|
+
},
|
|
43
|
+
render(resolved, ctx) {
|
|
44
|
+
const {
|
|
45
|
+
data,
|
|
46
|
+
xScale,
|
|
47
|
+
yScale
|
|
48
|
+
} = ctx;
|
|
49
|
+
if (!('bandwidth' in xScale)) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const bw = xScale.bandwidth();
|
|
53
|
+
const bodyWidth = bw * 0.6;
|
|
54
|
+
return /*#__PURE__*/_jsx("g", {
|
|
55
|
+
children: resolved.map((p, i) => {
|
|
56
|
+
const d = data[p.dataIndex];
|
|
57
|
+
const o = typeof d[options.open] === 'number' ? d[options.open] : 0;
|
|
58
|
+
const c = typeof d[options.close] === 'number' ? d[options.close] : 0;
|
|
59
|
+
const h = typeof d[options.high] === 'number' ? d[options.high] : 0;
|
|
60
|
+
const l = typeof d[options.low] === 'number' ? d[options.low] : 0;
|
|
61
|
+
const isUp = c >= o;
|
|
62
|
+
const col = isUp ? upColor : downColor;
|
|
63
|
+
return /*#__PURE__*/_jsxs("g", {
|
|
64
|
+
children: [/*#__PURE__*/_jsx("line", {
|
|
65
|
+
x1: p.px,
|
|
66
|
+
x2: p.px,
|
|
67
|
+
y1: yScale(h),
|
|
68
|
+
y2: yScale(l),
|
|
69
|
+
stroke: col,
|
|
70
|
+
strokeWidth: 1
|
|
71
|
+
}), /*#__PURE__*/_jsx("rect", {
|
|
72
|
+
x: p.px - bodyWidth / 2,
|
|
73
|
+
y: yScale(Math.max(o, c)),
|
|
74
|
+
width: bodyWidth,
|
|
75
|
+
height: Math.max(1, Math.abs(yScale(o) - yScale(c))),
|
|
76
|
+
fill: col
|
|
77
|
+
})]
|
|
78
|
+
}, i);
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file marks/dot.tsx
|
|
3
|
+
* @output Dot/scatter series — self-contained resolve + render
|
|
4
|
+
*/
|
|
5
|
+
import type { SeriesDef } from '../types';
|
|
6
|
+
export type ColorAccessor = string | ((datum: Record<string, unknown>, index: number) => string);
|
|
7
|
+
export interface DotOptions {
|
|
8
|
+
color?: ColorAccessor;
|
|
9
|
+
radius?: number;
|
|
10
|
+
opacity?: number;
|
|
11
|
+
dodge?: boolean;
|
|
12
|
+
label?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function dot(dataKey: string, options?: DotOptions): SeriesDef;
|
|
15
|
+
//# sourceMappingURL=dot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/dot.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAGvD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;AAEjG,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,CA2CxE"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file marks/dot.tsx
|
|
6
|
+
* @output Dot/scatter series — self-contained resolve + render
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export function dot(dataKey, options = {}) {
|
|
10
|
+
const color = options.color ?? 'var(--color-chart-1)';
|
|
11
|
+
const radius = options.radius ?? 4;
|
|
12
|
+
const opacity = options.opacity ?? 0.8;
|
|
13
|
+
return {
|
|
14
|
+
type: 'dot',
|
|
15
|
+
key: dataKey,
|
|
16
|
+
dataKeys: [dataKey],
|
|
17
|
+
color: typeof color === 'string' ? color : undefined,
|
|
18
|
+
label: options.label ?? dataKey,
|
|
19
|
+
layout: {},
|
|
20
|
+
resolve(ctx) {
|
|
21
|
+
const {
|
|
22
|
+
data,
|
|
23
|
+
xKey,
|
|
24
|
+
xScale,
|
|
25
|
+
yScale
|
|
26
|
+
} = ctx;
|
|
27
|
+
const points = [];
|
|
28
|
+
for (let i = 0; i < data.length; i++) {
|
|
29
|
+
const d = data[i];
|
|
30
|
+
let px;
|
|
31
|
+
if ('bandwidth' in xScale) {
|
|
32
|
+
px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
|
|
33
|
+
} else {
|
|
34
|
+
px = xScale(d[xKey]);
|
|
35
|
+
}
|
|
36
|
+
const v = typeof d[dataKey] === 'number' ? d[dataKey] : 0;
|
|
37
|
+
points.push({
|
|
38
|
+
px,
|
|
39
|
+
py: yScale(v),
|
|
40
|
+
py0: yScale(0),
|
|
41
|
+
dataIndex: i
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// TODO: dodge layout runs here — has access to radius + all points
|
|
45
|
+
return points;
|
|
46
|
+
},
|
|
47
|
+
render(resolved, ctx) {
|
|
48
|
+
const {
|
|
49
|
+
data
|
|
50
|
+
} = ctx;
|
|
51
|
+
return /*#__PURE__*/_jsx("g", {
|
|
52
|
+
children: resolved.map((p, i) => {
|
|
53
|
+
const fill = typeof color === 'function' ? color(data[p.dataIndex], p.dataIndex) : color;
|
|
54
|
+
return /*#__PURE__*/_jsx("circle", {
|
|
55
|
+
cx: p.px,
|
|
56
|
+
cy: p.py,
|
|
57
|
+
r: radius,
|
|
58
|
+
fill: fill,
|
|
59
|
+
opacity: opacity
|
|
60
|
+
}, i);
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -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/ChartV2/marks/dotGL.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAavD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA6HD;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,SAAS,CA2CvE"}
|
|
@@ -0,0 +1,178 @@
|
|
|
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
|
+
|
|
8
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
9
|
+
import { useChartV2 } from "../ChartV2Context.js";
|
|
10
|
+
import { hexToGL, getWebGLContext, setupGLState, sizeCanvas, mountCanvasOverSVG, createProgram, POINT_SIZE_COMPENSATION } from "../../Chart/webgl.js";
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
const VERT = `
|
|
13
|
+
attribute vec2 a_position;
|
|
14
|
+
uniform vec2 u_resolution;
|
|
15
|
+
uniform float u_size;
|
|
16
|
+
void main() {
|
|
17
|
+
vec2 clip = (a_position / u_resolution) * 2.0 - 1.0;
|
|
18
|
+
gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
|
|
19
|
+
gl_PointSize = u_size * ${POINT_SIZE_COMPENSATION.toFixed(6)};
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
const FRAG = `
|
|
23
|
+
precision mediump float;
|
|
24
|
+
uniform vec3 u_color;
|
|
25
|
+
uniform float u_opacity;
|
|
26
|
+
void main() {
|
|
27
|
+
vec2 coord = gl_PointCoord - vec2(0.5);
|
|
28
|
+
float dist = length(coord);
|
|
29
|
+
if (dist > 0.5) discard;
|
|
30
|
+
float edge = 1.0 - smoothstep(0.48, 0.5, dist);
|
|
31
|
+
float a = u_opacity * edge;
|
|
32
|
+
gl_FragColor = vec4(u_color * a, a);
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Inline component returned by render() — manages the WebGL canvas lifecycle.
|
|
38
|
+
* Needs access to svgRef from ChartV2Context to mount the canvas outside SVG.
|
|
39
|
+
*/
|
|
40
|
+
function DotGLCanvas({
|
|
41
|
+
resolved,
|
|
42
|
+
color,
|
|
43
|
+
size,
|
|
44
|
+
opacity,
|
|
45
|
+
width,
|
|
46
|
+
height
|
|
47
|
+
}) {
|
|
48
|
+
const {
|
|
49
|
+
svgRef: _svgRef
|
|
50
|
+
} = useChartV2();
|
|
51
|
+
const canvasRef = useRef(null);
|
|
52
|
+
const glRef = useRef(null);
|
|
53
|
+
const programRef = useRef(null);
|
|
54
|
+
const markerRef = useRef(null);
|
|
55
|
+
const getPositions = useCallback(() => {
|
|
56
|
+
const positions = [];
|
|
57
|
+
for (const p of resolved) {
|
|
58
|
+
positions.push(p.px, p.py);
|
|
59
|
+
}
|
|
60
|
+
return new Float32Array(positions);
|
|
61
|
+
}, [resolved]);
|
|
62
|
+
|
|
63
|
+
// Mount canvas outside SVG
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const marker = markerRef.current;
|
|
66
|
+
if (!marker) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!canvasRef.current) {
|
|
70
|
+
canvasRef.current = document.createElement('canvas');
|
|
71
|
+
}
|
|
72
|
+
return mountCanvasOverSVG(marker, canvasRef.current, width, height);
|
|
73
|
+
}, [width, height]);
|
|
74
|
+
|
|
75
|
+
// Draw
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const canvas = canvasRef.current;
|
|
78
|
+
if (!canvas || width <= 0 || height <= 0) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const dpr = sizeCanvas(canvas, width, height);
|
|
82
|
+
if (!glRef.current) {
|
|
83
|
+
glRef.current = getWebGLContext(canvas);
|
|
84
|
+
}
|
|
85
|
+
const gl = glRef.current;
|
|
86
|
+
if (!gl) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!programRef.current) {
|
|
90
|
+
programRef.current = createProgram(gl, VERT, FRAG);
|
|
91
|
+
}
|
|
92
|
+
const program = programRef.current;
|
|
93
|
+
if (!program) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
97
|
+
setupGLState(gl);
|
|
98
|
+
gl.useProgram(program);
|
|
99
|
+
const positions = getPositions();
|
|
100
|
+
const posBuffer = gl.createBuffer();
|
|
101
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
|
|
102
|
+
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
|
|
103
|
+
const aPos = gl.getAttribLocation(program, 'a_position');
|
|
104
|
+
gl.enableVertexAttribArray(aPos);
|
|
105
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
|
|
106
|
+
const [r, g, b] = hexToGL(color);
|
|
107
|
+
gl.uniform2f(gl.getUniformLocation(program, 'u_resolution'), width, height);
|
|
108
|
+
gl.uniform3f(gl.getUniformLocation(program, 'u_color'), r, g, b);
|
|
109
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_size'), size * dpr);
|
|
110
|
+
gl.uniform1f(gl.getUniformLocation(program, 'u_opacity'), opacity);
|
|
111
|
+
gl.drawArrays(gl.POINTS, 0, positions.length / 2);
|
|
112
|
+
gl.deleteBuffer(posBuffer);
|
|
113
|
+
}, [width, height, color, size, opacity, getPositions]);
|
|
114
|
+
if (width <= 0 || height <= 0) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
return /*#__PURE__*/_jsx("g", {
|
|
118
|
+
ref: markerRef
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* WebGL scatter plot. Canvas mounted outside SVG for sharp Retina rendering.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```
|
|
127
|
+
* series={[dotGL('value', {color: '#4f46e5'})]}
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function dotGL(dataKey, options) {
|
|
131
|
+
const {
|
|
132
|
+
color
|
|
133
|
+
} = options;
|
|
134
|
+
const size = options.size ?? 6;
|
|
135
|
+
const opacity = options.opacity ?? 0.8;
|
|
136
|
+
return {
|
|
137
|
+
type: 'dotGL',
|
|
138
|
+
key: dataKey,
|
|
139
|
+
dataKeys: [dataKey],
|
|
140
|
+
layout: {},
|
|
141
|
+
resolve(ctx) {
|
|
142
|
+
const {
|
|
143
|
+
data,
|
|
144
|
+
xKey,
|
|
145
|
+
xScale,
|
|
146
|
+
yScale
|
|
147
|
+
} = ctx;
|
|
148
|
+
const points = [];
|
|
149
|
+
for (let i = 0; i < data.length; i++) {
|
|
150
|
+
const d = data[i];
|
|
151
|
+
let px;
|
|
152
|
+
if ('bandwidth' in xScale) {
|
|
153
|
+
px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
|
|
154
|
+
} else {
|
|
155
|
+
px = xScale(d[xKey]);
|
|
156
|
+
}
|
|
157
|
+
const v = typeof d[dataKey] === 'number' ? d[dataKey] : 0;
|
|
158
|
+
points.push({
|
|
159
|
+
px,
|
|
160
|
+
py: yScale(v),
|
|
161
|
+
py0: yScale(0),
|
|
162
|
+
dataIndex: i
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return points;
|
|
166
|
+
},
|
|
167
|
+
render(resolved, ctx) {
|
|
168
|
+
return /*#__PURE__*/_jsx(DotGLCanvas, {
|
|
169
|
+
resolved: resolved,
|
|
170
|
+
color: color,
|
|
171
|
+
size: size,
|
|
172
|
+
opacity: opacity,
|
|
173
|
+
width: ctx.width,
|
|
174
|
+
height: ctx.height
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
import { type ReactNode } from 'react';
|
|
9
|
+
import type { SeriesDef } from '../types';
|
|
10
|
+
export interface DotGLInteractiveOptions {
|
|
11
|
+
color: string;
|
|
12
|
+
size?: number;
|
|
13
|
+
opacity?: number;
|
|
14
|
+
/** Custom tooltip renderer. Receives datum and index. */
|
|
15
|
+
renderTooltip?: (datum: Record<string, unknown>, index: number) => ReactNode;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* WebGL scatter with GPU color-picking hover. O(1) hit detection via offscreen
|
|
19
|
+
* framebuffer — no JS iteration regardless of point count.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```
|
|
23
|
+
* series={[dotGLInteractive('value', {
|
|
24
|
+
* color: '#4f46e5',
|
|
25
|
+
* renderTooltip: (d, i) => <span>{d.name}: {d.value}</span>,
|
|
26
|
+
* })]}
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function dotGLInteractive(dataKey: string, options: DotGLInteractiveOptions): SeriesDef;
|
|
30
|
+
//# sourceMappingURL=dotGLInteractive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dotGLInteractive.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/dotGLInteractive.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAIvD,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;AAwcD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,uBAAuB,GAC/B,SAAS,CA8CX"}
|