@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.
Files changed (142) hide show
  1. package/dist/ChartV2/Chart.d.ts +32 -0
  2. package/dist/ChartV2/Chart.d.ts.map +1 -0
  3. package/dist/ChartV2/Chart.js +281 -0
  4. package/dist/ChartV2/ChartAxis.d.ts +36 -0
  5. package/dist/ChartV2/ChartAxis.d.ts.map +1 -0
  6. package/dist/ChartV2/ChartAxis.js +161 -0
  7. package/dist/ChartV2/ChartGrid.d.ts +20 -0
  8. package/dist/ChartV2/ChartGrid.d.ts.map +1 -0
  9. package/dist/ChartV2/ChartGrid.js +76 -0
  10. package/dist/ChartV2/ChartLegend.d.ts +14 -0
  11. package/dist/ChartV2/ChartLegend.d.ts.map +1 -0
  12. package/dist/ChartV2/ChartLegend.js +54 -0
  13. package/dist/ChartV2/ChartSwatch.d.ts +36 -0
  14. package/dist/ChartV2/ChartSwatch.d.ts.map +1 -0
  15. package/dist/ChartV2/ChartSwatch.js +82 -0
  16. package/dist/ChartV2/ChartTooltip.d.ts +46 -0
  17. package/dist/ChartV2/ChartTooltip.d.ts.map +1 -0
  18. package/dist/ChartV2/ChartTooltip.js +267 -0
  19. package/dist/ChartV2/ChartV2Context.d.ts +4 -0
  20. package/dist/ChartV2/ChartV2Context.d.ts.map +1 -0
  21. package/dist/ChartV2/ChartV2Context.js +12 -0
  22. package/dist/ChartV2/index.d.ts +13 -0
  23. package/dist/ChartV2/index.d.ts.map +1 -0
  24. package/dist/ChartV2/index.js +10 -0
  25. package/dist/ChartV2/layout.d.ts +25 -0
  26. package/dist/ChartV2/layout.d.ts.map +1 -0
  27. package/dist/ChartV2/layout.js +195 -0
  28. package/dist/ChartV2/legend.d.ts +18 -0
  29. package/dist/ChartV2/legend.d.ts.map +1 -0
  30. package/dist/ChartV2/legend.js +24 -0
  31. package/dist/ChartV2/marks/area.d.ts +19 -0
  32. package/dist/ChartV2/marks/area.d.ts.map +1 -0
  33. package/dist/ChartV2/marks/area.js +109 -0
  34. package/dist/ChartV2/marks/band.d.ts +9 -0
  35. package/dist/ChartV2/marks/band.d.ts.map +1 -0
  36. package/dist/ChartV2/marks/band.js +59 -0
  37. package/dist/ChartV2/marks/bar.d.ts +17 -0
  38. package/dist/ChartV2/marks/bar.d.ts.map +1 -0
  39. package/dist/ChartV2/marks/bar.js +120 -0
  40. package/dist/ChartV2/marks/candlestick.d.ts +15 -0
  41. package/dist/ChartV2/marks/candlestick.d.ts.map +1 -0
  42. package/dist/ChartV2/marks/candlestick.js +83 -0
  43. package/dist/ChartV2/marks/dot.d.ts +15 -0
  44. package/dist/ChartV2/marks/dot.d.ts.map +1 -0
  45. package/dist/ChartV2/marks/dot.js +65 -0
  46. package/dist/ChartV2/marks/dotGL.d.ts +16 -0
  47. package/dist/ChartV2/marks/dotGL.d.ts.map +1 -0
  48. package/dist/ChartV2/marks/dotGL.js +178 -0
  49. package/dist/ChartV2/marks/dotGLInteractive.d.ts +30 -0
  50. package/dist/ChartV2/marks/dotGLInteractive.d.ts.map +1 -0
  51. package/dist/ChartV2/marks/dotGLInteractive.js +464 -0
  52. package/dist/ChartV2/marks/errorBar.d.ts +27 -0
  53. package/dist/ChartV2/marks/errorBar.d.ts.map +1 -0
  54. package/dist/ChartV2/marks/errorBar.js +87 -0
  55. package/dist/ChartV2/marks/heatmapGL.d.ts +23 -0
  56. package/dist/ChartV2/marks/heatmapGL.d.ts.map +1 -0
  57. package/dist/ChartV2/marks/heatmapGL.js +242 -0
  58. package/dist/ChartV2/marks/index.d.ts +13 -0
  59. package/dist/ChartV2/marks/index.d.ts.map +1 -0
  60. package/dist/ChartV2/marks/index.js +14 -0
  61. package/dist/ChartV2/marks/line.d.ts +18 -0
  62. package/dist/ChartV2/marks/line.d.ts.map +1 -0
  63. package/dist/ChartV2/marks/line.js +76 -0
  64. package/dist/ChartV2/marks/referenceLine.d.ts +35 -0
  65. package/dist/ChartV2/marks/referenceLine.d.ts.map +1 -0
  66. package/dist/ChartV2/marks/referenceLine.js +186 -0
  67. package/dist/ChartV2/marks/streamGL.d.ts +36 -0
  68. package/dist/ChartV2/marks/streamGL.d.ts.map +1 -0
  69. package/dist/ChartV2/marks/streamGL.js +204 -0
  70. package/dist/ChartV2/tooltip.d.ts +38 -0
  71. package/dist/ChartV2/tooltip.d.ts.map +1 -0
  72. package/dist/ChartV2/tooltip.js +54 -0
  73. package/dist/ChartV2/types.d.ts +115 -0
  74. package/dist/ChartV2/types.d.ts.map +1 -0
  75. package/dist/ChartV2/types.js +35 -0
  76. package/dist/CodeEditor/CodeEditor.d.ts +1 -4
  77. package/dist/CodeEditor/CodeEditor.d.ts.map +1 -1
  78. package/dist/CodeEditor/CodeEditor.js +0 -3
  79. package/dist/Sankey/SankeyChart.d.ts.map +1 -1
  80. package/dist/Sankey/SankeyChart.js +0 -3
  81. package/dist/Schedule/ListView.d.ts.map +1 -1
  82. package/dist/Schedule/ListView.js +4 -7
  83. package/dist/Schedule/MonthlyView.js +2 -3
  84. package/dist/Schedule/Schedule.d.ts +1 -3
  85. package/dist/Schedule/Schedule.d.ts.map +1 -1
  86. package/dist/Schedule/Schedule.js +4 -9
  87. package/dist/Schedule/TimeGridView.js +2 -3
  88. package/dist/Schedule/context.d.ts +0 -2
  89. package/dist/Schedule/context.d.ts.map +1 -1
  90. package/dist/index.d.ts +1 -1
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js +2 -5
  93. package/dist/lab.css +15 -6
  94. package/package.json +2 -2
  95. package/src/ChartV2/Chart.tsx +348 -0
  96. package/src/ChartV2/ChartAxis.tsx +209 -0
  97. package/src/ChartV2/ChartGrid.tsx +99 -0
  98. package/src/ChartV2/ChartLegend.tsx +69 -0
  99. package/src/ChartV2/ChartSwatch.doc.mjs +17 -0
  100. package/src/ChartV2/ChartSwatch.tsx +86 -0
  101. package/src/ChartV2/ChartTooltip.tsx +382 -0
  102. package/src/ChartV2/ChartV2.doc.mjs +16 -0
  103. package/src/ChartV2/ChartV2Context.ts +15 -0
  104. package/src/ChartV2/index.ts +62 -0
  105. package/src/ChartV2/layout.ts +223 -0
  106. package/src/ChartV2/legend.ts +32 -0
  107. package/src/ChartV2/marks/area.tsx +122 -0
  108. package/src/ChartV2/marks/band.tsx +70 -0
  109. package/src/ChartV2/marks/bar.tsx +159 -0
  110. package/src/ChartV2/marks/candlestick.tsx +106 -0
  111. package/src/ChartV2/marks/dot.tsx +64 -0
  112. package/src/ChartV2/marks/dotGL.tsx +202 -0
  113. package/src/ChartV2/marks/dotGLInteractive.tsx +546 -0
  114. package/src/ChartV2/marks/errorBar.tsx +89 -0
  115. package/src/ChartV2/marks/heatmapGL.tsx +299 -0
  116. package/src/ChartV2/marks/index.ts +14 -0
  117. package/src/ChartV2/marks/line.tsx +94 -0
  118. package/src/ChartV2/marks/referenceLine.tsx +224 -0
  119. package/src/ChartV2/marks/streamGL.tsx +251 -0
  120. package/src/ChartV2/tooltip.ts +70 -0
  121. package/src/ChartV2/types.ts +129 -0
  122. package/src/CodeEditor/CodeEditor.tsx +0 -5
  123. package/src/Sankey/SankeyChart.tsx +0 -3
  124. package/src/Schedule/ListView.tsx +2 -5
  125. package/src/Schedule/MonthlyView.tsx +2 -2
  126. package/src/Schedule/Schedule.test.tsx +0 -39
  127. package/src/Schedule/Schedule.tsx +0 -8
  128. package/src/Schedule/TimeGridView.tsx +2 -2
  129. package/src/Schedule/context.tsx +0 -2
  130. package/src/index.ts +46 -5
  131. package/dist/InfoTip/InfoTip.d.ts +0 -58
  132. package/dist/InfoTip/InfoTip.d.ts.map +0 -1
  133. package/dist/InfoTip/InfoTip.js +0 -91
  134. package/dist/InfoTip/index.d.ts +0 -6
  135. package/dist/InfoTip/index.d.ts.map +0 -1
  136. package/dist/InfoTip/index.js +0 -8
  137. package/src/CodeEditor/CodeEditor.test.tsx +0 -21
  138. package/src/InfoTip/InfoTip.doc.mjs +0 -97
  139. package/src/InfoTip/InfoTip.test.tsx +0 -169
  140. package/src/InfoTip/InfoTip.tsx +0 -155
  141. package/src/InfoTip/index.ts +0 -10
  142. package/src/Sankey/SankeyChart.test.tsx +0 -77
@@ -0,0 +1,464 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file marks/dotGLInteractive.tsx
5
+ * @output WebGL scatter with GPU color-picking for O(1) nearest-point hover
6
+ *
7
+ * Each point gets a unique color encoding its index. On hover, readPixels
8
+ * from an offscreen framebuffer decodes the hovered index — no JS iteration.
9
+ */
10
+
11
+ import { useRef, useEffect, useCallback, useState, useMemo } from 'react';
12
+ import { hexToGL } from "../../Chart/webgl.js";
13
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
14
+ /** Encode a point index as an RGB color (supports up to 16.7M points) */
15
+ function indexToColor(i) {
16
+ const id = i + 1;
17
+ return [(id >> 16 & 0xff) / 255, (id >> 8 & 0xff) / 255, (id & 0xff) / 255];
18
+ }
19
+
20
+ /** Decode an RGB pixel back to a point index. Returns -1 for background. */
21
+ function colorToIndex(r, g, b) {
22
+ if (r === 0 && g === 0 && b === 0) {
23
+ return -1;
24
+ }
25
+ return (r << 16 | g << 8 | b) - 1;
26
+ }
27
+ function compileShader(gl, type, src) {
28
+ const s = gl.createShader(type);
29
+ if (!s) {
30
+ return null;
31
+ }
32
+ gl.shaderSource(s, src);
33
+ gl.compileShader(s);
34
+ if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
35
+ gl.deleteShader(s);
36
+ return null;
37
+ }
38
+ return s;
39
+ }
40
+ function linkProgram(gl, vert, frag) {
41
+ const vs = compileShader(gl, gl.VERTEX_SHADER, vert);
42
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, frag);
43
+ if (!vs || !fs) {
44
+ return null;
45
+ }
46
+ const p = gl.createProgram();
47
+ if (!p) {
48
+ return null;
49
+ }
50
+ gl.attachShader(p, vs);
51
+ gl.attachShader(p, fs);
52
+ gl.linkProgram(p);
53
+ if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
54
+ gl.deleteProgram(p);
55
+ return null;
56
+ }
57
+ return p;
58
+ }
59
+
60
+ // Visible pass
61
+ const VERT_VIS = `
62
+ attribute vec2 a_position;
63
+ uniform vec2 u_resolution;
64
+ uniform float u_size;
65
+ void main() {
66
+ vec2 clip = (a_position / u_resolution) * 2.0 - 1.0;
67
+ gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
68
+ gl_PointSize = u_size;
69
+ }
70
+ `;
71
+ const FRAG_VIS = `
72
+ precision mediump float;
73
+ uniform vec3 u_color;
74
+ uniform float u_opacity;
75
+ void main() {
76
+ vec2 coord = gl_PointCoord - vec2(0.5);
77
+ if (dot(coord, coord) > 0.25) discard;
78
+ gl_FragColor = vec4(u_color, u_opacity);
79
+ }
80
+ `;
81
+
82
+ // Pick pass — encode index as color
83
+ const VERT_PICK = `
84
+ attribute vec2 a_position;
85
+ attribute vec3 a_pickColor;
86
+ uniform vec2 u_resolution;
87
+ uniform float u_size;
88
+ varying vec3 v_pickColor;
89
+ void main() {
90
+ vec2 clip = (a_position / u_resolution) * 2.0 - 1.0;
91
+ gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
92
+ gl_PointSize = u_size + 4.0;
93
+ v_pickColor = a_pickColor;
94
+ }
95
+ `;
96
+ const FRAG_PICK = `
97
+ precision mediump float;
98
+ varying vec3 v_pickColor;
99
+ void main() {
100
+ vec2 coord = gl_PointCoord - vec2(0.5);
101
+ if (dot(coord, coord) > 0.25) discard;
102
+ gl_FragColor = vec4(v_pickColor, 1.0);
103
+ }
104
+ `;
105
+
106
+ /**
107
+ * Inline component — manages visible + pick canvases and hover state.
108
+ */
109
+ function DotGLInteractiveCanvas({
110
+ resolved,
111
+ color,
112
+ size,
113
+ opacity,
114
+ width,
115
+ height,
116
+ data,
117
+ renderTooltip
118
+ }) {
119
+ const visCanvasRef = useRef(null);
120
+ const pickCanvasRef = useRef(null);
121
+ const [hoverIndex, setHoverIndex] = useState(-1);
122
+ const [mousePos, setMousePos] = useState(null);
123
+ const visGLRef = useRef(null);
124
+ const pickGLRef = useRef(null);
125
+ const positions = useMemo(() => {
126
+ const pos = [];
127
+ for (const p of resolved) {
128
+ pos.push(p.px, p.py);
129
+ }
130
+ return new Float32Array(pos);
131
+ }, [resolved]);
132
+ const pickColors = useMemo(() => {
133
+ const colors = [];
134
+ for (let i = 0; i < resolved.length; i++) {
135
+ const [r, g, b] = indexToColor(i);
136
+ colors.push(r, g, b);
137
+ }
138
+ return new Float32Array(colors);
139
+ }, [resolved.length]);
140
+
141
+ // Render both passes
142
+ useEffect(() => {
143
+ if (width <= 0 || height <= 0) {
144
+ return;
145
+ }
146
+ const dpr = window.devicePixelRatio || 1;
147
+
148
+ // Visible canvas
149
+ const visCanvas = visCanvasRef.current;
150
+ if (visCanvas) {
151
+ visCanvas.width = width * dpr;
152
+ visCanvas.height = height * dpr;
153
+ if (!visGLRef.current) {
154
+ const gl = visCanvas.getContext('webgl', {
155
+ alpha: true,
156
+ premultipliedAlpha: false,
157
+ antialias: true
158
+ });
159
+ const prog = gl ? linkProgram(gl, VERT_VIS, FRAG_VIS) : null;
160
+ if (gl && prog) {
161
+ visGLRef.current = {
162
+ gl,
163
+ prog
164
+ };
165
+ }
166
+ }
167
+ const vis = visGLRef.current;
168
+ if (vis) {
169
+ const {
170
+ gl,
171
+ prog
172
+ } = vis;
173
+ gl.viewport(0, 0, visCanvas.width, visCanvas.height);
174
+ gl.clearColor(0, 0, 0, 0);
175
+ gl.clear(gl.COLOR_BUFFER_BIT);
176
+ gl.enable(gl.BLEND);
177
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
178
+ gl.useProgram(prog);
179
+ const buf = gl.createBuffer();
180
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
181
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
182
+ const aPos = gl.getAttribLocation(prog, 'a_position');
183
+ gl.enableVertexAttribArray(aPos);
184
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
185
+ const [r, g, b] = hexToGL(color);
186
+ gl.uniform2f(gl.getUniformLocation(prog, 'u_resolution'), width, height);
187
+ gl.uniform3f(gl.getUniformLocation(prog, 'u_color'), r, g, b);
188
+ gl.uniform1f(gl.getUniformLocation(prog, 'u_size'), size * dpr);
189
+ gl.uniform1f(gl.getUniformLocation(prog, 'u_opacity'), opacity);
190
+ gl.drawArrays(gl.POINTS, 0, positions.length / 2);
191
+ gl.deleteBuffer(buf);
192
+ }
193
+ }
194
+
195
+ // Pick canvas (offscreen)
196
+ const pickCanvas = pickCanvasRef.current;
197
+ if (pickCanvas) {
198
+ pickCanvas.width = width * dpr;
199
+ pickCanvas.height = height * dpr;
200
+ if (!pickGLRef.current) {
201
+ const gl = pickCanvas.getContext('webgl', {
202
+ alpha: false,
203
+ premultipliedAlpha: false,
204
+ antialias: false,
205
+ preserveDrawingBuffer: true
206
+ });
207
+ if (gl) {
208
+ const prog = linkProgram(gl, VERT_PICK, FRAG_PICK);
209
+ const fb = gl.createFramebuffer();
210
+ const tex = gl.createTexture();
211
+ if (prog && fb && tex) {
212
+ gl.bindTexture(gl.TEXTURE_2D, tex);
213
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, pickCanvas.width, pickCanvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
214
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
215
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
216
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
217
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
218
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
219
+ pickGLRef.current = {
220
+ gl,
221
+ prog,
222
+ fb,
223
+ tex
224
+ };
225
+ }
226
+ }
227
+ }
228
+ const pick = pickGLRef.current;
229
+ if (pick) {
230
+ const {
231
+ gl,
232
+ prog,
233
+ fb,
234
+ tex
235
+ } = pick;
236
+ gl.bindTexture(gl.TEXTURE_2D, tex);
237
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, pickCanvas.width, pickCanvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
238
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
239
+ gl.viewport(0, 0, pickCanvas.width, pickCanvas.height);
240
+ gl.clearColor(0, 0, 0, 1);
241
+ gl.clear(gl.COLOR_BUFFER_BIT);
242
+ gl.disable(gl.BLEND);
243
+ gl.useProgram(prog);
244
+ const posBuf = gl.createBuffer();
245
+ gl.bindBuffer(gl.ARRAY_BUFFER, posBuf);
246
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
247
+ const aPos = gl.getAttribLocation(prog, 'a_position');
248
+ gl.enableVertexAttribArray(aPos);
249
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
250
+ const colBuf = gl.createBuffer();
251
+ gl.bindBuffer(gl.ARRAY_BUFFER, colBuf);
252
+ gl.bufferData(gl.ARRAY_BUFFER, pickColors, gl.STATIC_DRAW);
253
+ const aCol = gl.getAttribLocation(prog, 'a_pickColor');
254
+ gl.enableVertexAttribArray(aCol);
255
+ gl.vertexAttribPointer(aCol, 3, gl.FLOAT, false, 0, 0);
256
+ gl.uniform2f(gl.getUniformLocation(prog, 'u_resolution'), width, height);
257
+ gl.uniform1f(gl.getUniformLocation(prog, 'u_size'), (size + 4) * dpr);
258
+ gl.drawArrays(gl.POINTS, 0, positions.length / 2);
259
+ gl.deleteBuffer(posBuf);
260
+ gl.deleteBuffer(colBuf);
261
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
262
+ }
263
+ }
264
+ }, [width, height, positions, pickColors, color, size, opacity]);
265
+ const handleMouseMove = useCallback(e => {
266
+ const pick = pickGLRef.current;
267
+ if (!pick) {
268
+ return;
269
+ }
270
+ const svg = e.currentTarget.ownerSVGElement;
271
+ if (!svg) {
272
+ return;
273
+ }
274
+ const pt = svg.createSVGPoint();
275
+ pt.x = e.clientX;
276
+ pt.y = e.clientY;
277
+ const local = pt.matrixTransform(e.currentTarget.getScreenCTM()?.inverse());
278
+ const dpr = window.devicePixelRatio || 1;
279
+ const px = Math.floor(local.x * dpr);
280
+ const py = Math.floor(local.y * dpr);
281
+ const {
282
+ gl,
283
+ fb
284
+ } = pick;
285
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
286
+ const pixel = new Uint8Array(4);
287
+ gl.readPixels(px, gl.canvas.height - py, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
288
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
289
+ const idx = colorToIndex(pixel[0], pixel[1], pixel[2]);
290
+ setHoverIndex(idx);
291
+ setMousePos(idx >= 0 ? {
292
+ x: local.x,
293
+ y: local.y
294
+ } : null);
295
+ }, []);
296
+ const handleMouseLeave = useCallback(() => {
297
+ setHoverIndex(-1);
298
+ setMousePos(null);
299
+ }, []);
300
+ const datum = hoverIndex >= 0 && hoverIndex < data.length ? data[hoverIndex] : null;
301
+ const defaultTooltip = (d, i) => /*#__PURE__*/_jsxs("div", {
302
+ style: {
303
+ display: 'flex',
304
+ flexDirection: 'column',
305
+ gap: 2,
306
+ fontSize: 12
307
+ },
308
+ children: [/*#__PURE__*/_jsxs("div", {
309
+ style: {
310
+ fontWeight: 600,
311
+ color: 'var(--color-text-primary)'
312
+ },
313
+ children: ["Point ", i]
314
+ }), Object.entries(d).map(([k, v]) => /*#__PURE__*/_jsxs("div", {
315
+ children: [/*#__PURE__*/_jsxs("span", {
316
+ style: {
317
+ color: 'var(--color-text-secondary)'
318
+ },
319
+ children: [k, ":"]
320
+ }), ' ', /*#__PURE__*/_jsx("span", {
321
+ style: {
322
+ fontWeight: 500
323
+ },
324
+ children: String(v)
325
+ })]
326
+ }, k))]
327
+ });
328
+ return /*#__PURE__*/_jsxs("g", {
329
+ children: [/*#__PURE__*/_jsx("foreignObject", {
330
+ x: 0,
331
+ y: 0,
332
+ width: width,
333
+ height: height,
334
+ style: {
335
+ overflow: 'hidden'
336
+ },
337
+ children: /*#__PURE__*/_jsx("canvas", {
338
+ ref: visCanvasRef,
339
+ style: {
340
+ width,
341
+ height,
342
+ pointerEvents: 'none'
343
+ }
344
+ })
345
+ }), /*#__PURE__*/_jsx("foreignObject", {
346
+ x: 0,
347
+ y: 0,
348
+ width: 0,
349
+ height: 0,
350
+ style: {
351
+ overflow: 'hidden'
352
+ },
353
+ children: /*#__PURE__*/_jsx("canvas", {
354
+ ref: pickCanvasRef,
355
+ style: {
356
+ display: 'none'
357
+ }
358
+ })
359
+ }), /*#__PURE__*/_jsx("rect", {
360
+ x: 0,
361
+ y: 0,
362
+ width: width,
363
+ height: height,
364
+ fill: "transparent",
365
+ onMouseMove: handleMouseMove,
366
+ onMouseLeave: handleMouseLeave
367
+ }), datum && hoverIndex >= 0 && /*#__PURE__*/_jsx("circle", {
368
+ cx: positions[hoverIndex * 2],
369
+ cy: positions[hoverIndex * 2 + 1],
370
+ r: size / 2 + 3,
371
+ fill: "none",
372
+ stroke: color,
373
+ strokeWidth: 2,
374
+ strokeOpacity: 0.8,
375
+ pointerEvents: "none"
376
+ }), datum && mousePos && /*#__PURE__*/_jsx("foreignObject", {
377
+ x: mousePos.x + 12,
378
+ y: Math.max(0, mousePos.y - 40),
379
+ width: 200,
380
+ height: 120,
381
+ pointerEvents: "none",
382
+ style: {
383
+ overflow: 'visible'
384
+ },
385
+ children: /*#__PURE__*/_jsx("div", {
386
+ style: {
387
+ background: 'var(--color-background-popover)',
388
+ border: '1px solid var(--color-border)',
389
+ borderRadius: 8,
390
+ padding: '8px 12px',
391
+ boxShadow: 'var(--shadow-med)',
392
+ whiteSpace: 'nowrap',
393
+ width: 'fit-content'
394
+ },
395
+ children: renderTooltip ? renderTooltip(datum, hoverIndex) : defaultTooltip(datum, hoverIndex)
396
+ })
397
+ })]
398
+ });
399
+ }
400
+
401
+ /**
402
+ * WebGL scatter with GPU color-picking hover. O(1) hit detection via offscreen
403
+ * framebuffer — no JS iteration regardless of point count.
404
+ *
405
+ * @example
406
+ * ```
407
+ * series={[dotGLInteractive('value', {
408
+ * color: '#4f46e5',
409
+ * renderTooltip: (d, i) => <span>{d.name}: {d.value}</span>,
410
+ * })]}
411
+ * ```
412
+ */
413
+ export function dotGLInteractive(dataKey, options) {
414
+ const {
415
+ color
416
+ } = options;
417
+ const size = options.size ?? 6;
418
+ const opacity = options.opacity ?? 0.8;
419
+ const renderTooltip = options.renderTooltip;
420
+ return {
421
+ type: 'dotGLInteractive',
422
+ key: dataKey,
423
+ dataKeys: [dataKey],
424
+ layout: {},
425
+ resolve(ctx) {
426
+ const {
427
+ data,
428
+ xKey,
429
+ xScale,
430
+ yScale
431
+ } = ctx;
432
+ const points = [];
433
+ for (let i = 0; i < data.length; i++) {
434
+ const d = data[i];
435
+ let px;
436
+ if ('bandwidth' in xScale) {
437
+ px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
438
+ } else {
439
+ px = xScale(d[xKey]);
440
+ }
441
+ const v = typeof d[dataKey] === 'number' ? d[dataKey] : 0;
442
+ points.push({
443
+ px,
444
+ py: yScale(v),
445
+ py0: yScale(0),
446
+ dataIndex: i
447
+ });
448
+ }
449
+ return points;
450
+ },
451
+ render(resolved, ctx) {
452
+ return /*#__PURE__*/_jsx(DotGLInteractiveCanvas, {
453
+ resolved: resolved,
454
+ color: color,
455
+ size: size,
456
+ opacity: opacity,
457
+ width: ctx.width,
458
+ height: ctx.height,
459
+ data: ctx.data,
460
+ renderTooltip: renderTooltip
461
+ });
462
+ }
463
+ };
464
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @file marks/errorBar.tsx
3
+ * @output Error bar (whisker) series — vertical high/low bounds
4
+ */
5
+ import type { SeriesDef } from '../types';
6
+ export interface ErrorBarOptions {
7
+ /** Data key for the upper bound */
8
+ high: string;
9
+ /** Data key for the lower bound */
10
+ low: string;
11
+ /** Stroke color */
12
+ color?: string;
13
+ /** Stroke width */
14
+ strokeWidth?: number;
15
+ /** Width of the whisker caps in pixels */
16
+ capWidth?: number;
17
+ }
18
+ /**
19
+ * Error bars with whisker caps. Pair with bar() or dot().
20
+ *
21
+ * @example
22
+ * ```
23
+ * series={[bar('mean'), errorBar({high: 'upper95', low: 'lower95'})]}
24
+ * ```
25
+ */
26
+ export declare function errorBar(options: ErrorBarOptions): SeriesDef;
27
+ //# sourceMappingURL=errorBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorBar.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/errorBar.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAGvD,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,SAAS,CAyD5D"}
@@ -0,0 +1,87 @@
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/errorBar.tsx
6
+ * @output Error bar (whisker) series — vertical high/low bounds
7
+ */
8
+
9
+ /**
10
+ * Error bars with whisker caps. Pair with bar() or dot().
11
+ *
12
+ * @example
13
+ * ```
14
+ * series={[bar('mean'), errorBar({high: 'upper95', low: 'lower95'})]}
15
+ * ```
16
+ */
17
+ export function errorBar(options) {
18
+ const {
19
+ high,
20
+ low
21
+ } = options;
22
+ const color = options.color ?? 'var(--color-text-primary)';
23
+ const strokeWidth = options.strokeWidth ?? 1.5;
24
+ const capWidth = options.capWidth ?? 8;
25
+ return {
26
+ type: 'errorBar',
27
+ key: `errorBar-${high}-${low}`,
28
+ dataKeys: [high, low],
29
+ layout: {},
30
+ resolve(ctx) {
31
+ const {
32
+ data,
33
+ xKey,
34
+ xScale,
35
+ yScale
36
+ } = ctx;
37
+ const points = [];
38
+ for (let i = 0; i < data.length; i++) {
39
+ const d = data[i];
40
+ let px;
41
+ if ('bandwidth' in xScale) {
42
+ px = (xScale(String(d[xKey])) ?? 0) + xScale.bandwidth() / 2;
43
+ } else {
44
+ px = xScale(d[xKey]);
45
+ }
46
+ const upper = typeof d[high] === 'number' ? d[high] : 0;
47
+ const lower = typeof d[low] === 'number' ? d[low] : 0;
48
+ points.push({
49
+ px,
50
+ py: yScale(upper),
51
+ py0: yScale(lower),
52
+ dataIndex: i
53
+ });
54
+ }
55
+ return points;
56
+ },
57
+ render(resolved) {
58
+ const half = capWidth / 2;
59
+ return /*#__PURE__*/_jsx("g", {
60
+ children: resolved.map((p, i) => /*#__PURE__*/_jsxs("g", {
61
+ children: [/*#__PURE__*/_jsx("line", {
62
+ x1: p.px,
63
+ x2: p.px,
64
+ y1: p.py,
65
+ y2: p.py0,
66
+ stroke: color,
67
+ strokeWidth: strokeWidth
68
+ }), /*#__PURE__*/_jsx("line", {
69
+ x1: p.px - half,
70
+ x2: p.px + half,
71
+ y1: p.py,
72
+ y2: p.py,
73
+ stroke: color,
74
+ strokeWidth: strokeWidth
75
+ }), /*#__PURE__*/_jsx("line", {
76
+ x1: p.px - half,
77
+ x2: p.px + half,
78
+ y1: p.py0,
79
+ y2: p.py0,
80
+ stroke: color,
81
+ strokeWidth: strokeWidth
82
+ })]
83
+ }, i))
84
+ });
85
+ }
86
+ };
87
+ }
@@ -0,0 +1,23 @@
1
+ import type { SeriesDef } from '../types';
2
+ export interface HeatmapGLOptions {
3
+ xKey: string;
4
+ yKey: string;
5
+ valueKey: string;
6
+ colorRange: string[];
7
+ domain?: [number, number];
8
+ cellGap?: number;
9
+ }
10
+ /**
11
+ * WebGL heatmap. Renders a 2D grid of colored cells using triangles.
12
+ * Manages its own y band scale for rows; uses the chart's x band scale for columns.
13
+ *
14
+ * @example
15
+ * ```
16
+ * series={[heatmapGL({
17
+ * xKey: 'hour', yKey: 'day', valueKey: 'count',
18
+ * colorRange: ['#f0f9ff', '#1e40af'],
19
+ * })]}
20
+ * ```
21
+ */
22
+ export declare function heatmapGL(options: HeatmapGLOptions): SeriesDef;
23
+ //# sourceMappingURL=heatmapGL.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heatmapGL.d.ts","sourceRoot":"","sources":["../../../src/ChartV2/marks/heatmapGL.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,SAAS,EAAgB,MAAM,UAAU,CAAC;AAWvD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAkND;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAiD9D"}