@astryxdesign/lab 0.1.6-canary.2829fc5 → 0.1.6-canary.2d8ba8b
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/Chart/ChartDotGLInteractive.d.ts.map +1 -1
- package/dist/Chart/ChartDotGLInteractive.js +1 -5
- package/dist/Chart/getChartColors.d.ts.map +1 -1
- package/dist/Chart/getChartColors.js +18 -6
- package/dist/Chart/webgl.d.ts +4 -12
- package/dist/Chart/webgl.d.ts.map +1 -1
- package/dist/Chart/webgl.js +9 -3
- package/dist/ThreeD/ThreeDScatterGL.d.ts.map +1 -1
- package/dist/ThreeD/ThreeDScatterGL.js +2 -6
- package/package.json +2 -2
- package/src/Chart/ChartDotGLInteractive.tsx +1 -5
- package/src/Chart/getChartColors.test.ts +28 -0
- package/src/Chart/getChartColors.ts +13 -8
- package/src/Chart/webgl.ts +9 -3
- package/src/ThreeD/ThreeDScatterGL.tsx +2 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartDotGLInteractive.d.ts","sourceRoot":"","sources":["../../src/Chart/ChartDotGLInteractive.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ChartDotGLInteractive.d.ts","sourceRoot":"","sources":["../../src/Chart/ChartDotGLInteractive.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,MAAM,WAAW,0BAA0B;IACzC,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;CAC9E;AA+GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,KAAK,EACL,IAAQ,EACR,OAAa,EACb,aAAa,GACd,EAAE,0BAA0B,sCAyV5B"}
|
|
@@ -13,12 +13,8 @@
|
|
|
13
13
|
import { useRef, useEffect, useCallback, useState, useMemo } from 'react';
|
|
14
14
|
import { useChart } from "./ChartContext.js";
|
|
15
15
|
import { xPixel } from "./utils.js";
|
|
16
|
+
import { hexToGL } from "./webgl.js";
|
|
16
17
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
17
|
-
function hexToGL(hex) {
|
|
18
|
-
const n = parseInt(hex.replace('#', ''), 16);
|
|
19
|
-
return [(n >> 16) / 255, (n >> 8 & 0xff) / 255, (n & 0xff) / 255];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
18
|
/** Encode a point index as an RGB color (supports up to 16.7M points) */
|
|
23
19
|
function indexToColor(i) {
|
|
24
20
|
// Add 1 so index 0 isn't black (which is our clear color)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getChartColors.d.ts","sourceRoot":"","sources":["../../src/Chart/getChartColors.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"getChartColors.d.ts","sourceRoot":"","sources":["../../src/Chart/getChartColors.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAO3D,kDAAkD;AAClD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,UAAU,GACV,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,KAAK,GACL,MAAM,GACN,QAAQ,GACR,MAAM,CAAC;AAEX,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC;IAC3D,SAAS,EAAE;QACT,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACtC,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC7B,MAAM,CACJ,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,aAAa,EAClB,CAAC,EAAE,MAAM,EACT,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,EAAE,CAAC;KACb,CAAC;IACF,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,qEAAqE;IACrE,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7C;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAoErD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,aAAa,GACrB,cAAc,CA+EhB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE,OAAO,GAAG,MAAgB,GAC/B,cAAc,CAsBhB"}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* the full chart colors API. The useChartColors hook wraps this.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { parseHex, parseColor, formatColor } from '@astryxdesign/core/utils';
|
|
13
|
+
|
|
12
14
|
// =============================================================================
|
|
13
15
|
// Types
|
|
14
16
|
// =============================================================================
|
|
@@ -39,15 +41,25 @@ function pickFromRamp(stops, n) {
|
|
|
39
41
|
length: n
|
|
40
42
|
}, (_, i) => stops[Math.round(i * 4 / (n - 1))]);
|
|
41
43
|
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Apply an opacity to a concrete CSS color (hex — with or without the leading
|
|
47
|
+
* `#` — `rgb()`/`rgba()`, named). The `opacity` argument always wins over any
|
|
48
|
+
* alpha already in the color. Unparseable input (e.g. `var()`) is returned
|
|
49
|
+
* unchanged.
|
|
50
|
+
*/
|
|
42
51
|
function hexAlpha(hex, opacity) {
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
// parseColor requires the `#` for hex; fall back to parseHex so bare hex
|
|
53
|
+
// strings (`0064E0`) keep working as they did before #3739.
|
|
54
|
+
const rgba = parseColor(hex) ?? parseHex(hex);
|
|
55
|
+
if (rgba === null) {
|
|
45
56
|
return hex;
|
|
46
57
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
const a = Number.isFinite(opacity) ? Math.max(0, Math.min(1, opacity)) : 1;
|
|
59
|
+
return formatColor({
|
|
60
|
+
...rgba,
|
|
61
|
+
a
|
|
62
|
+
});
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
// =============================================================================
|
package/dist/Chart/webgl.d.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file webgl.ts
|
|
3
|
-
* @output Shared WebGL utilities for chart components
|
|
4
|
-
* @position Internal helpers; consumed by all GL mark components
|
|
5
|
-
*
|
|
6
|
-
* Provides:
|
|
7
|
-
* - Canvas mounting outside SVG (avoids foreignObject DPR blur)
|
|
8
|
-
* - Premultiplied alpha setup (correct compositing over page)
|
|
9
|
-
* - Shader compilation helpers
|
|
10
|
-
* - Smoothstep circle fragment for crisp point sprites
|
|
11
|
-
*/
|
|
12
1
|
/** Compile a WebGL shader, returns null on failure */
|
|
13
2
|
export declare function compileShader(gl: WebGLRenderingContext, type: number, src: string): WebGLShader | null;
|
|
14
3
|
/** Link a vertex + fragment shader into a program */
|
|
15
4
|
export declare function createProgram(gl: WebGLRenderingContext, vertSrc: string, fragSrc: string): WebGLProgram | null;
|
|
16
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Parse a hex color (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) to [r, g, b]
|
|
7
|
+
* floats 0-1. Unparseable input returns a neutral fallback instead of NaN.
|
|
8
|
+
*/
|
|
17
9
|
export declare function hexToGL(hex: string): [number, number, number];
|
|
18
10
|
/** DPR with supersampling for crisp circles */
|
|
19
11
|
export declare function getCanvasDPR(): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../../src/Chart/webgl.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../../src/Chart/webgl.ts"],"names":[],"mappings":"AAkBA,sDAAsD;AACtD,wBAAgB,aAAa,CAC3B,EAAE,EAAE,qBAAqB,EACzB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,WAAW,GAAG,IAAI,CAYpB;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAC3B,EAAE,EAAE,qBAAqB,EACzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,YAAY,GAAG,IAAI,CAkBrB;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAE7D;AAED,+CAA+C;AAC/C,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,iBAAiB,GACxB,qBAAqB,GAAG,IAAI,CAM9B;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,qBAAqB,GAAG,IAAI,CAK5D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,MAAM,CAOR;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,kBAAkB,EAC7B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAwC1B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,iPAO5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QAAa,CAAC"}
|
package/dist/Chart/webgl.js
CHANGED
|
@@ -10,8 +10,12 @@
|
|
|
10
10
|
* - Premultiplied alpha setup (correct compositing over page)
|
|
11
11
|
* - Shader compilation helpers
|
|
12
12
|
* - Smoothstep circle fragment for crisp point sprites
|
|
13
|
+
* - Hex-to-GL color conversion via the shared @astryxdesign/core/utils/color
|
|
14
|
+
* parsers (fallback instead of NaN)
|
|
13
15
|
*/
|
|
14
16
|
|
|
17
|
+
import { parseHex, toGLFloats } from '@astryxdesign/core/utils';
|
|
18
|
+
|
|
15
19
|
/** Compile a WebGL shader, returns null on failure */
|
|
16
20
|
export function compileShader(gl, type, src) {
|
|
17
21
|
const s = gl.createShader(type);
|
|
@@ -48,10 +52,12 @@ export function createProgram(gl, vertSrc, fragSrc) {
|
|
|
48
52
|
return p;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Parse a hex color (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) to [r, g, b]
|
|
57
|
+
* floats 0-1. Unparseable input returns a neutral fallback instead of NaN.
|
|
58
|
+
*/
|
|
52
59
|
export function hexToGL(hex) {
|
|
53
|
-
|
|
54
|
-
return [(n >> 16) / 255, (n >> 8 & 0xff) / 255, (n & 0xff) / 255];
|
|
60
|
+
return toGLFloats(parseHex(hex));
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
/** DPR with supersampling for crisp circles */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreeDScatterGL.d.ts","sourceRoot":"","sources":["../../src/ThreeD/ThreeDScatterGL.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ThreeDScatterGL.d.ts","sourceRoot":"","sources":["../../src/ThreeD/ThreeDScatterGL.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuFD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,IAAQ,EACR,OAAc,GACf,EAAE,oBAAoB,sCAuJtB"}
|
|
@@ -14,13 +14,9 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { useRef, useEffect, useMemo } from 'react';
|
|
17
|
+
import { parseHex, toGLFloats } from '@astryxdesign/core/utils';
|
|
17
18
|
import { use3D } from "./ThreeDContext.js";
|
|
18
19
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
19
|
-
function hexToGL(hex) {
|
|
20
|
-
const n = parseInt(hex.replace('#', ''), 16);
|
|
21
|
-
return [(n >> 16) / 255, (n >> 8 & 0xff) / 255, (n & 0xff) / 255];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
20
|
// SYNC: Steps 1-5 match ThreeDChart.project() exactly.
|
|
25
21
|
const VERT = `
|
|
26
22
|
attribute vec3 a_position;
|
|
@@ -218,7 +214,7 @@ export function ThreeDScatterGL({
|
|
|
218
214
|
const azRad = camera.azimuth * Math.PI / 180;
|
|
219
215
|
const elRad = camera.elevation * Math.PI / 180;
|
|
220
216
|
const scale = Math.min(width, height) * 0.35;
|
|
221
|
-
const [r, g, b] =
|
|
217
|
+
const [r, g, b] = toGLFloats(parseHex(color));
|
|
222
218
|
gl.uniform2f(gl.getUniformLocation(program, 'u_resolution'), width, height);
|
|
223
219
|
gl.uniform2f(gl.getUniformLocation(program, 'u_center'), width / 2, height / 2);
|
|
224
220
|
gl.uniform1f(gl.getUniformLocation(program, 'u_scale'), scale);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.1.6-canary.
|
|
3
|
+
"version": "0.1.6-canary.2d8ba8b",
|
|
4
4
|
"description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@stylexjs/stylex": ">=0.10.0",
|
|
48
|
-
"@astryxdesign/core": "0.1.6-canary.
|
|
48
|
+
"@astryxdesign/core": "0.1.6-canary.2d8ba8b",
|
|
49
49
|
"react": ">=19.0.0",
|
|
50
50
|
"react-dom": ">=19.0.0"
|
|
51
51
|
},
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from 'react';
|
|
21
21
|
import {useChart} from './ChartContext';
|
|
22
22
|
import {xPixel} from './utils';
|
|
23
|
+
import {hexToGL} from './webgl';
|
|
23
24
|
|
|
24
25
|
export interface ChartDotGLInteractiveProps {
|
|
25
26
|
/** Which data key for the y values */
|
|
@@ -37,11 +38,6 @@ export interface ChartDotGLInteractiveProps {
|
|
|
37
38
|
renderTooltip?: (datum: Record<string, unknown>, index: number) => ReactNode;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
function hexToGL(hex: string): [number, number, number] {
|
|
41
|
-
const n = parseInt(hex.replace('#', ''), 16);
|
|
42
|
-
return [(n >> 16) / 255, ((n >> 8) & 0xff) / 255, (n & 0xff) / 255];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
41
|
/** Encode a point index as an RGB color (supports up to 16.7M points) */
|
|
46
42
|
function indexToColor(i: number): [number, number, number] {
|
|
47
43
|
// Add 1 so index 0 isn't black (which is our clear color)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
import {describe, expect, it} from 'vitest';
|
|
4
|
+
import {getChartColorsFromResolver} from './getChartColors';
|
|
5
|
+
|
|
6
|
+
describe('getChartColorsFromResolver alpha', () => {
|
|
7
|
+
const colors = getChartColorsFromResolver(name => `resolved(${name})`);
|
|
8
|
+
|
|
9
|
+
it('applies opacity to a hex color', () => {
|
|
10
|
+
expect(colors.alpha('#0064E0', 0.2)).toBe('rgba(0, 100, 224, 0.2)');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('applies opacity to bare hex without the leading # (pre-#3739 behavior)', () => {
|
|
14
|
+
expect(colors.alpha('0064E0', 0.2)).toBe('rgba(0, 100, 224, 0.2)');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('applies opacity to rgba() input, overriding its alpha', () => {
|
|
18
|
+
expect(colors.alpha('rgba(0, 100, 224, 0.9)', 0.2)).toBe(
|
|
19
|
+
'rgba(0, 100, 224, 0.2)',
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('preserves unparseable input unchanged', () => {
|
|
24
|
+
expect(colors.alpha('var(--color-accent)', 0.5)).toBe(
|
|
25
|
+
'var(--color-accent)',
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type {DefinedTheme} from '@astryxdesign/core/theme';
|
|
13
|
+
import {parseHex, parseColor, formatColor} from '@astryxdesign/core/utils';
|
|
13
14
|
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// Types
|
|
@@ -105,17 +106,21 @@ function pickFromRamp(stops: string[], n: number): string[] {
|
|
|
105
106
|
);
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Apply an opacity to a concrete CSS color (hex — with or without the leading
|
|
111
|
+
* `#` — `rgb()`/`rgba()`, named). The `opacity` argument always wins over any
|
|
112
|
+
* alpha already in the color. Unparseable input (e.g. `var()`) is returned
|
|
113
|
+
* unchanged.
|
|
114
|
+
*/
|
|
108
115
|
function hexAlpha(hex: string, opacity: number): string {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
);
|
|
112
|
-
if (
|
|
116
|
+
// parseColor requires the `#` for hex; fall back to parseHex so bare hex
|
|
117
|
+
// strings (`0064E0`) keep working as they did before #3739.
|
|
118
|
+
const rgba = parseColor(hex) ?? parseHex(hex);
|
|
119
|
+
if (rgba === null) {
|
|
113
120
|
return hex;
|
|
114
121
|
}
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
const b = parseInt(match[3], 16);
|
|
118
|
-
return `rgba(${r},${g},${b},${Math.max(0, Math.min(1, opacity))})`;
|
|
122
|
+
const a = Number.isFinite(opacity) ? Math.max(0, Math.min(1, opacity)) : 1;
|
|
123
|
+
return formatColor({...rgba, a});
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
// =============================================================================
|
package/src/Chart/webgl.ts
CHANGED
|
@@ -10,8 +10,12 @@
|
|
|
10
10
|
* - Premultiplied alpha setup (correct compositing over page)
|
|
11
11
|
* - Shader compilation helpers
|
|
12
12
|
* - Smoothstep circle fragment for crisp point sprites
|
|
13
|
+
* - Hex-to-GL color conversion via the shared @astryxdesign/core/utils/color
|
|
14
|
+
* parsers (fallback instead of NaN)
|
|
13
15
|
*/
|
|
14
16
|
|
|
17
|
+
import {parseHex, toGLFloats} from '@astryxdesign/core/utils';
|
|
18
|
+
|
|
15
19
|
/** Compile a WebGL shader, returns null on failure */
|
|
16
20
|
export function compileShader(
|
|
17
21
|
gl: WebGLRenderingContext,
|
|
@@ -56,10 +60,12 @@ export function createProgram(
|
|
|
56
60
|
return p;
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Parse a hex color (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) to [r, g, b]
|
|
65
|
+
* floats 0-1. Unparseable input returns a neutral fallback instead of NaN.
|
|
66
|
+
*/
|
|
60
67
|
export function hexToGL(hex: string): [number, number, number] {
|
|
61
|
-
|
|
62
|
-
return [(n >> 16) / 255, ((n >> 8) & 0xff) / 255, (n & 0xff) / 255];
|
|
68
|
+
return toGLFloats(parseHex(hex));
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
/** DPR with supersampling for crisp circles */
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import {useRef, useEffect, useMemo} from 'react';
|
|
17
|
+
import {parseHex, toGLFloats} from '@astryxdesign/core/utils';
|
|
17
18
|
import {use3D} from './ThreeDContext';
|
|
18
19
|
|
|
19
20
|
export interface ThreeDScatterGLProps {
|
|
@@ -22,11 +23,6 @@ export interface ThreeDScatterGLProps {
|
|
|
22
23
|
opacity?: number;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
function hexToGL(hex: string): [number, number, number] {
|
|
26
|
-
const n = parseInt(hex.replace('#', ''), 16);
|
|
27
|
-
return [(n >> 16) / 255, ((n >> 8) & 0xff) / 255, (n & 0xff) / 255];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
// SYNC: Steps 1-5 match ThreeDChart.project() exactly.
|
|
31
27
|
const VERT = `
|
|
32
28
|
attribute vec3 a_position;
|
|
@@ -240,7 +236,7 @@ export function ThreeDScatterGL({
|
|
|
240
236
|
const azRad = (camera.azimuth * Math.PI) / 180;
|
|
241
237
|
const elRad = (camera.elevation * Math.PI) / 180;
|
|
242
238
|
const scale = Math.min(width, height) * 0.35;
|
|
243
|
-
const [r, g, b] =
|
|
239
|
+
const [r, g, b] = toGLFloats(parseHex(color));
|
|
244
240
|
|
|
245
241
|
gl.uniform2f(gl.getUniformLocation(program, 'u_resolution'), width, height);
|
|
246
242
|
gl.uniform2f(
|