@mui/x-charts-premium 9.0.4 → 9.1.0
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/BarChartPremium/BarChartPremium.js +2 -1183
- package/BarChartPremium/BarChartPremium.mjs +2 -1183
- package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.js +2 -0
- package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.mjs +2 -0
- package/CHANGELOG.md +133 -0
- package/CandlestickChart/CandlestickChart.d.mts +2 -2
- package/CandlestickChart/CandlestickChart.d.ts +2 -2
- package/CandlestickChart/CandlestickChart.js +2 -1183
- package/CandlestickChart/CandlestickChart.mjs +2 -1183
- package/CandlestickChart/CandlestickWebGLProgram.d.mts +6 -11
- package/CandlestickChart/CandlestickWebGLProgram.d.ts +6 -11
- package/CandlestickChart/CandlestickWebGLProgram.js +136 -121
- package/CandlestickChart/CandlestickWebGLProgram.mjs +137 -122
- package/CandlestickChart/useCandlestickPlotData.d.mts +2 -2
- package/CandlestickChart/useCandlestickPlotData.d.ts +2 -2
- package/CandlestickChart/useCandlestickPlotData.js +121 -61
- package/CandlestickChart/useCandlestickPlotData.mjs +122 -61
- package/ChartsAxisHighlightValue/index.d.mts +1 -0
- package/ChartsAxisHighlightValue/index.d.ts +1 -0
- package/ChartsAxisHighlightValue/index.js +16 -0
- package/ChartsAxisHighlightValue/index.mjs +2 -0
- package/ChartsDataProviderPremium/ChartsDataProviderPremium.js +2 -2
- package/ChartsDataProviderPremium/ChartsDataProviderPremium.mjs +2 -2
- package/ChartsRadialAxisHighlight/index.d.mts +1 -0
- package/ChartsRadialAxisHighlight/index.d.ts +1 -0
- package/ChartsRadialAxisHighlight/index.js +16 -0
- package/ChartsRadialAxisHighlight/index.mjs +2 -0
- package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.js +2 -2
- package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.mjs +2 -2
- package/HeatmapPremium/HeatmapPremium.js +2 -155
- package/HeatmapPremium/HeatmapPremium.mjs +2 -155
- package/HeatmapPremium/webgl/HeatmapWebGLPlot.js +19 -112
- package/HeatmapPremium/webgl/HeatmapWebGLPlot.mjs +19 -111
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.mts +24 -0
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.ts +24 -0
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.js +132 -0
- package/HeatmapPremium/webgl/HeatmapWebGLProgram.mjs +125 -0
- package/HeatmapPremium/webgl/useHeatmapPlotData.d.mts +3 -3
- package/HeatmapPremium/webgl/useHeatmapPlotData.d.ts +3 -3
- package/HeatmapPremium/webgl/useHeatmapPlotData.js +78 -26
- package/HeatmapPremium/webgl/useHeatmapPlotData.mjs +80 -26
- package/LICENSE +3 -1
- package/RadialBarChart/RadialBarChart.d.mts +60 -0
- package/RadialBarChart/RadialBarChart.d.ts +60 -0
- package/RadialBarChart/RadialBarChart.js +298 -0
- package/RadialBarChart/RadialBarChart.mjs +292 -0
- package/RadialBarChart/RadialBarChart.plugins.d.mts +4 -0
- package/RadialBarChart/RadialBarChart.plugins.d.ts +4 -0
- package/RadialBarChart/RadialBarChart.plugins.js +9 -0
- package/RadialBarChart/RadialBarChart.plugins.mjs +3 -0
- package/RadialBarChart/RadialBarElement.d.mts +16 -0
- package/RadialBarChart/RadialBarElement.d.ts +16 -0
- package/RadialBarChart/RadialBarElement.js +54 -0
- package/RadialBarChart/RadialBarElement.mjs +48 -0
- package/RadialBarChart/RadialBarPlot.d.mts +21 -0
- package/RadialBarChart/RadialBarPlot.d.ts +21 -0
- package/RadialBarChart/RadialBarPlot.js +85 -0
- package/RadialBarChart/RadialBarPlot.mjs +79 -0
- package/RadialBarChart/index.d.mts +3 -0
- package/RadialBarChart/index.d.ts +3 -0
- package/RadialBarChart/index.js +39 -0
- package/RadialBarChart/index.mjs +3 -0
- package/RadialBarChart/radialBarClasses.d.mts +15 -0
- package/RadialBarChart/radialBarClasses.d.ts +15 -0
- package/RadialBarChart/radialBarClasses.js +26 -0
- package/RadialBarChart/radialBarClasses.mjs +18 -0
- package/RadialBarChart/seriesConfig/seriesProcessor.js +4 -0
- package/RadialBarChart/seriesConfig/seriesProcessor.mjs +4 -0
- package/RadialBarChart/useRadialBarChartProps.d.mts +28 -0
- package/RadialBarChart/useRadialBarChartProps.d.ts +28 -0
- package/RadialBarChart/useRadialBarChartProps.js +100 -0
- package/RadialBarChart/useRadialBarChartProps.mjs +93 -0
- package/RadialBarChart/useRadialBarPlotData.d.mts +23 -0
- package/RadialBarChart/useRadialBarPlotData.d.ts +23 -0
- package/RadialBarChart/useRadialBarPlotData.js +94 -0
- package/RadialBarChart/useRadialBarPlotData.mjs +87 -0
- package/RadialLineChart/RadialArea.js +13 -1
- package/RadialLineChart/RadialArea.mjs +13 -1
- package/RadialLineChart/RadialLine.js +13 -1
- package/RadialLineChart/RadialLine.mjs +13 -1
- package/RadialLineChart/RadialLineChart.d.mts +11 -3
- package/RadialLineChart/RadialLineChart.d.ts +11 -3
- package/RadialLineChart/RadialLineChart.js +24 -673
- package/RadialLineChart/RadialLineChart.mjs +24 -673
- package/RadialLineChart/RadialLineHighlightElement.d.mts +15 -0
- package/RadialLineChart/RadialLineHighlightElement.d.ts +15 -0
- package/RadialLineChart/RadialLineHighlightElement.js +46 -0
- package/RadialLineChart/RadialLineHighlightElement.mjs +39 -0
- package/RadialLineChart/RadialLineHighlightPlot.d.mts +23 -0
- package/RadialLineChart/RadialLineHighlightPlot.d.ts +23 -0
- package/RadialLineChart/RadialLineHighlightPlot.js +92 -0
- package/RadialLineChart/RadialLineHighlightPlot.mjs +86 -0
- package/RadialLineChart/RadialMarkPlot.js +17 -2
- package/RadialLineChart/RadialMarkPlot.mjs +17 -2
- package/RadialLineChart/index.d.mts +3 -1
- package/RadialLineChart/index.d.ts +3 -1
- package/RadialLineChart/index.js +22 -0
- package/RadialLineChart/index.mjs +3 -1
- package/RadialLineChart/radialLineClasses.d.mts +3 -1
- package/RadialLineChart/radialLineClasses.d.ts +3 -1
- package/RadialLineChart/radialLineClasses.js +2 -1
- package/RadialLineChart/radialLineClasses.mjs +2 -1
- package/RadialLineChart/seriesConfig/getItemAtPosition.d.mts +6 -0
- package/RadialLineChart/seriesConfig/getItemAtPosition.d.ts +6 -0
- package/RadialLineChart/seriesConfig/getItemAtPosition.js +353 -0
- package/RadialLineChart/seriesConfig/getItemAtPosition.mjs +348 -0
- package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.js +2 -1
- package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.mjs +2 -1
- package/RadialLineChart/seriesConfig/index.js +2 -1
- package/RadialLineChart/seriesConfig/index.mjs +2 -1
- package/RadialLineChart/seriesConfig/seriesProcessor.js +4 -0
- package/RadialLineChart/seriesConfig/seriesProcessor.mjs +4 -0
- package/RadialLineChart/useRadialLineChartProps.d.mts +2 -0
- package/RadialLineChart/useRadialLineChartProps.d.ts +2 -0
- package/RadialLineChart/useRadialLineChartProps.js +16 -8
- package/RadialLineChart/useRadialLineChartProps.mjs +16 -8
- package/RadialLineChart/useRadialLinePlotData.js +2 -1
- package/RadialLineChart/useRadialLinePlotData.mjs +3 -2
- package/ScatterChartPremium/ScatterChartPremium.d.mts +25 -0
- package/ScatterChartPremium/ScatterChartPremium.d.ts +25 -0
- package/ScatterChartPremium/ScatterChartPremium.js +507 -0
- package/ScatterChartPremium/ScatterChartPremium.mjs +501 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.d.mts +3 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.d.ts +3 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.js +8 -0
- package/ScatterChartPremium/ScatterChartPremium.plugins.mjs +2 -0
- package/ScatterChartPremium/ScatterPlotPremium.d.mts +14 -0
- package/ScatterChartPremium/ScatterPlotPremium.d.ts +14 -0
- package/ScatterChartPremium/ScatterPlotPremium.js +28 -0
- package/ScatterChartPremium/ScatterPlotPremium.mjs +21 -0
- package/ScatterChartPremium/index.d.mts +3 -0
- package/ScatterChartPremium/index.d.ts +3 -0
- package/ScatterChartPremium/index.js +26 -0
- package/ScatterChartPremium/index.mjs +3 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.mts +4 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.ts +4 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.js +70 -0
- package/ScatterChartPremium/webgl/ScatterWebGLPlot.mjs +65 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.mts +18 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.ts +18 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.js +129 -0
- package/ScatterChartPremium/webgl/ScatterWebGLProgram.mjs +122 -0
- package/ScatterChartPremium/webgl/shaders.d.mts +2 -0
- package/ScatterChartPremium/webgl/shaders.d.ts +2 -0
- package/ScatterChartPremium/webgl/shaders.js +57 -0
- package/ScatterChartPremium/webgl/shaders.mjs +51 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.mts +7 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.ts +7 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.js +140 -0
- package/ScatterChartPremium/webgl/useScatterWebGLPlotData.mjs +134 -0
- package/index.d.mts +3 -1
- package/index.d.ts +3 -1
- package/index.js +25 -1
- package/index.mjs +4 -2
- package/internals/index.d.mts +1 -0
- package/internals/index.d.ts +1 -0
- package/internals/index.js +13 -0
- package/internals/index.mjs +1 -0
- package/models/seriesType/radialLine.d.mts +7 -1
- package/models/seriesType/radialLine.d.ts +7 -1
- package/package.json +184 -114
- package/plugins/selectors/useChartCandlestickPosition.selectors.d.mts +1 -1
- package/plugins/selectors/useChartCandlestickPosition.selectors.d.ts +1 -1
- package/utils/webgl/parseColor.d.mts +2 -1
- package/utils/webgl/parseColor.d.ts +2 -1
- package/utils/webgl/parseColor.js +8 -7
- package/utils/webgl/parseColor.mjs +8 -7
- package/utils/webgl/utils.d.mts +13 -0
- package/utils/webgl/utils.d.ts +13 -0
- package/utils/webgl/utils.js +29 -0
- package/utils/webgl/utils.mjs +27 -0
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { useDrawingArea, useXScale, useYScale } from '@mui/x-charts/hooks';
|
|
5
|
-
import useEventCallback from '@mui/utils/useEventCallback';
|
|
6
5
|
import { useWebGLLayer } from "../../ChartsWebGLLayer/ChartsWebGLContext.mjs";
|
|
7
6
|
import { useHeatmapSeriesContext } from "../../hooks/index.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import { attachShader, bindQuadBuffer, compileShader, logWebGLErrors, uploadQuadBuffer } from "../../utils/webgl/utils.mjs";
|
|
7
|
+
import { HeatmapWebGLProgram } from "./HeatmapWebGLProgram.mjs";
|
|
10
8
|
import { useHeatmapPlotData } from "./useHeatmapPlotData.mjs";
|
|
11
9
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
10
|
export function HeatmapWebGLPlot({
|
|
@@ -37,135 +35,45 @@ function HeatmapWebGLPlotImpl(props) {
|
|
|
37
35
|
const drawingArea = useDrawingArea();
|
|
38
36
|
const xScale = useXScale();
|
|
39
37
|
const yScale = useYScale();
|
|
40
|
-
const [
|
|
41
|
-
const [program] = React.useState(() => {
|
|
42
|
-
const p = gl.createProgram();
|
|
43
|
-
gl.attachShader(p, vertexShader);
|
|
44
|
-
return p;
|
|
45
|
-
});
|
|
46
|
-
const [quadBuffer] = React.useState(() => uploadQuadBuffer(gl));
|
|
38
|
+
const [program, setProgram] = React.useState(null);
|
|
47
39
|
const dataLength = series.data.length;
|
|
48
40
|
const drawRef = React.useRef(null);
|
|
49
41
|
React.useEffect(() => {
|
|
50
42
|
drawRef.current = () => {
|
|
51
|
-
|
|
43
|
+
program?.render(dataLength);
|
|
52
44
|
};
|
|
53
|
-
}, [
|
|
45
|
+
}, [program, dataLength]);
|
|
54
46
|
React.useEffect(() => {
|
|
55
47
|
const unregister = registerDraw(drawRef);
|
|
56
48
|
return unregister;
|
|
57
49
|
}, [registerDraw]);
|
|
58
50
|
React.useEffect(() => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
51
|
+
const prog = new HeatmapWebGLProgram(gl);
|
|
52
|
+
setProgram(prog);
|
|
53
|
+
return () => {
|
|
54
|
+
prog.dispose();
|
|
55
|
+
};
|
|
63
56
|
}, [gl]);
|
|
64
57
|
const width = xScale.bandwidth();
|
|
65
58
|
const height = yScale.bandwidth();
|
|
66
|
-
|
|
67
|
-
// A border radius cannot be larger than half the width or height of the rectangle
|
|
59
|
+
/* A border radius cannot be larger than half the width or height of the rectangle. */
|
|
68
60
|
const seriesBorderRadius = Math.min(borderRadius ?? 0, width / 2, height / 2);
|
|
69
|
-
const lastSeriesBorderRadiusRef = React.useRef(seriesBorderRadius > 0 ? 0 : 1);
|
|
70
|
-
const setupResolutionUniform = React.useCallback(() => {
|
|
71
|
-
gl.uniform2f(gl.getUniformLocation(program, 'u_resolution'), drawingArea.width, drawingArea.height);
|
|
72
|
-
}, [drawingArea.height, drawingArea.width, gl, program]);
|
|
73
|
-
const setupBorderRadiusUniform = React.useCallback(() => {
|
|
74
|
-
gl.uniform1f(gl.getUniformLocation(program, 'u_borderRadius'), seriesBorderRadius);
|
|
75
|
-
}, [gl, program, seriesBorderRadius]);
|
|
76
|
-
const setupRectDimensionsUniform = React.useCallback(() => {
|
|
77
|
-
gl.uniform2f(gl.getUniformLocation(program, 'u_dimensions'), width, height);
|
|
78
|
-
}, [gl, height, program, width]);
|
|
79
|
-
const setupUniformsEvent = useEventCallback(() => {
|
|
80
|
-
bindQuadBuffer(gl, program, quadBuffer);
|
|
81
|
-
setupBorderRadiusUniform();
|
|
82
|
-
setupResolutionUniform();
|
|
83
|
-
setupRectDimensionsUniform();
|
|
84
|
-
});
|
|
85
|
-
const plotData = useHeatmapPlotData(drawingArea, series, xScale, yScale);
|
|
86
|
-
const setupAttributes = React.useCallback(() => {
|
|
87
|
-
const {
|
|
88
|
-
centers,
|
|
89
|
-
colors,
|
|
90
|
-
saturations
|
|
91
|
-
} = plotData;
|
|
92
|
-
|
|
93
|
-
// Upload rectangle centers
|
|
94
|
-
const centerBuffer = gl.createBuffer();
|
|
95
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
|
|
96
|
-
gl.bufferData(gl.ARRAY_BUFFER, centers, gl.STATIC_DRAW);
|
|
97
|
-
const aCenter = gl.getAttribLocation(program, 'a_center');
|
|
98
|
-
gl.enableVertexAttribArray(aCenter);
|
|
99
|
-
gl.vertexAttribPointer(aCenter, 2, gl.FLOAT, false, 0, 0);
|
|
100
|
-
|
|
101
|
-
// This makes the attribute instanced (one value per rectangle, not per vertex)
|
|
102
|
-
gl.vertexAttribDivisor(aCenter, 1);
|
|
103
|
-
|
|
104
|
-
// Upload colors
|
|
105
|
-
const colorBuffer = gl.createBuffer();
|
|
106
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
|
|
107
|
-
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
|
|
108
|
-
const aColor = gl.getAttribLocation(program, 'a_color');
|
|
109
|
-
gl.enableVertexAttribArray(aColor);
|
|
110
|
-
gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, 0, 0);
|
|
111
|
-
gl.vertexAttribDivisor(aColor, 1);
|
|
112
|
-
|
|
113
|
-
// Upload saturations
|
|
114
|
-
const saturationBuffer = gl.createBuffer();
|
|
115
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, saturationBuffer);
|
|
116
|
-
gl.bufferData(gl.ARRAY_BUFFER, saturations, gl.STATIC_DRAW);
|
|
117
|
-
const aSaturation = gl.getAttribLocation(program, 'a_saturation');
|
|
118
|
-
gl.enableVertexAttribArray(aSaturation);
|
|
119
|
-
gl.vertexAttribPointer(aSaturation, 1, gl.FLOAT, false, 0, 0);
|
|
120
|
-
gl.vertexAttribDivisor(aSaturation, 1);
|
|
121
|
-
}, [gl, plotData, program]);
|
|
122
|
-
const setupAttributesEvent = useEventCallback(() => setupAttributes());
|
|
123
61
|
React.useEffect(() => {
|
|
124
|
-
|
|
125
|
-
lastSeriesBorderRadiusRef.current = seriesBorderRadius;
|
|
126
|
-
if (shouldAttachNewShader) {
|
|
127
|
-
const shaderSource = seriesBorderRadius > 0 ? heatmapFragmentShaderSourceWithBorderRadius : heatmapFragmentShaderSourceNoBorderRadius;
|
|
128
|
-
gl.getAttachedShaders(program)?.forEach(shader => {
|
|
129
|
-
const shaderType = gl.getShaderParameter(shader, gl.SHADER_TYPE);
|
|
130
|
-
if (shaderType === gl.FRAGMENT_SHADER) {
|
|
131
|
-
gl.detachShader(program, shader);
|
|
132
|
-
gl.deleteShader(shader);
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
const fragmentShader = attachShader(gl, program, shaderSource, gl.FRAGMENT_SHADER);
|
|
136
|
-
gl.linkProgram(program);
|
|
137
|
-
|
|
138
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#dont_check_shader_compile_status_unless_linking_fails
|
|
139
|
-
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
140
|
-
console.error(`Program linking failed: ${gl.getProgramInfoLog(program)}`);
|
|
141
|
-
console.error(`Vertex shader info-log: ${gl.getShaderInfoLog(vertexShader)}`);
|
|
142
|
-
console.error(`Fragment shader info-log: ${gl.getShaderInfoLog(fragmentShader)}`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Not a hook
|
|
146
|
-
// eslint-disable-next-line react-compiler/react-compiler
|
|
147
|
-
gl.useProgram(program);
|
|
148
|
-
logWebGLErrors(gl);
|
|
149
|
-
setupUniformsEvent();
|
|
150
|
-
setupAttributesEvent();
|
|
151
|
-
} else {
|
|
152
|
-
setupBorderRadiusUniform();
|
|
153
|
-
}
|
|
62
|
+
program?.setResolution(drawingArea.width, drawingArea.height);
|
|
154
63
|
requestRender();
|
|
155
|
-
}, [
|
|
156
|
-
// We use the event callback versions here because we only want this effect to trigger when the border radius changes
|
|
157
|
-
setupAttributesEvent, setupUniformsEvent, vertexShader]);
|
|
64
|
+
}, [drawingArea.height, drawingArea.width, program, requestRender]);
|
|
158
65
|
React.useEffect(() => {
|
|
159
|
-
|
|
66
|
+
program?.setRectDimensions(width, height);
|
|
160
67
|
requestRender();
|
|
161
|
-
}, [
|
|
68
|
+
}, [width, height, program, requestRender]);
|
|
162
69
|
React.useEffect(() => {
|
|
163
|
-
|
|
70
|
+
program?.setBorderRadius(seriesBorderRadius);
|
|
164
71
|
requestRender();
|
|
165
|
-
}, [
|
|
72
|
+
}, [seriesBorderRadius, program, requestRender]);
|
|
73
|
+
const plotData = useHeatmapPlotData(drawingArea, series, xScale, yScale);
|
|
166
74
|
React.useEffect(() => {
|
|
167
|
-
|
|
75
|
+
program?.plot(plotData);
|
|
168
76
|
requestRender();
|
|
169
|
-
}, [
|
|
77
|
+
}, [plotData, program, requestRender]);
|
|
170
78
|
return null;
|
|
171
79
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface HeatmapPlotData {
|
|
2
|
+
centers: Float32Array;
|
|
3
|
+
colors: Uint8Array;
|
|
4
|
+
saturations: Float32Array;
|
|
5
|
+
}
|
|
6
|
+
export declare class HeatmapWebGLProgram {
|
|
7
|
+
private gl;
|
|
8
|
+
private readonly shaders;
|
|
9
|
+
private readonly quadBuffer;
|
|
10
|
+
private readonly centers;
|
|
11
|
+
private readonly colors;
|
|
12
|
+
private readonly saturations;
|
|
13
|
+
private readonly flatVariant;
|
|
14
|
+
private readonly roundedVariant;
|
|
15
|
+
private active;
|
|
16
|
+
constructor(gl: WebGL2RenderingContext);
|
|
17
|
+
private buildVariant;
|
|
18
|
+
setBorderRadius(borderRadius: number): void;
|
|
19
|
+
setResolution(width: number, height: number): void;
|
|
20
|
+
setRectDimensions(width: number, height: number): void;
|
|
21
|
+
plot(plotData: HeatmapPlotData): void;
|
|
22
|
+
render(dataLength: number): void;
|
|
23
|
+
dispose(): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface HeatmapPlotData {
|
|
2
|
+
centers: Float32Array;
|
|
3
|
+
colors: Uint8Array;
|
|
4
|
+
saturations: Float32Array;
|
|
5
|
+
}
|
|
6
|
+
export declare class HeatmapWebGLProgram {
|
|
7
|
+
private gl;
|
|
8
|
+
private readonly shaders;
|
|
9
|
+
private readonly quadBuffer;
|
|
10
|
+
private readonly centers;
|
|
11
|
+
private readonly colors;
|
|
12
|
+
private readonly saturations;
|
|
13
|
+
private readonly flatVariant;
|
|
14
|
+
private readonly roundedVariant;
|
|
15
|
+
private active;
|
|
16
|
+
constructor(gl: WebGL2RenderingContext);
|
|
17
|
+
private buildVariant;
|
|
18
|
+
setBorderRadius(borderRadius: number): void;
|
|
19
|
+
setResolution(width: number, height: number): void;
|
|
20
|
+
setRectDimensions(width: number, height: number): void;
|
|
21
|
+
plot(plotData: HeatmapPlotData): void;
|
|
22
|
+
render(dataLength: number): void;
|
|
23
|
+
dispose(): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.HeatmapWebGLProgram = void 0;
|
|
7
|
+
var _utils = require("../../utils/webgl/utils");
|
|
8
|
+
var _shaders = require("./shaders");
|
|
9
|
+
const QUAD_VERTICES = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
|
|
10
|
+
class HeatmapWebGLProgram {
|
|
11
|
+
shaders = [];
|
|
12
|
+
constructor(gl) {
|
|
13
|
+
this.gl = gl;
|
|
14
|
+
/* Enable blending for transparency
|
|
15
|
+
* These are global to the WebGL context and need to be set only once */
|
|
16
|
+
gl.enable(gl.BLEND);
|
|
17
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
18
|
+
this.quadBuffer = gl.createBuffer();
|
|
19
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadBuffer);
|
|
20
|
+
gl.bufferData(gl.ARRAY_BUFFER, QUAD_VERTICES, gl.STATIC_DRAW);
|
|
21
|
+
this.centers = (0, _utils.createGrowableBuffer)(gl);
|
|
22
|
+
this.colors = (0, _utils.createGrowableBuffer)(gl);
|
|
23
|
+
this.saturations = (0, _utils.createGrowableBuffer)(gl);
|
|
24
|
+
|
|
25
|
+
/* Two pre-built programs let us swap border-radius on/off without re-linking. */
|
|
26
|
+
this.flatVariant = this.buildVariant(_shaders.heatmapFragmentShaderSourceNoBorderRadius);
|
|
27
|
+
this.roundedVariant = this.buildVariant(_shaders.heatmapFragmentShaderSourceWithBorderRadius);
|
|
28
|
+
this.active = this.flatVariant;
|
|
29
|
+
}
|
|
30
|
+
buildVariant(fragmentShaderSource) {
|
|
31
|
+
const gl = this.gl;
|
|
32
|
+
const program = gl.createProgram();
|
|
33
|
+
const vertexShader = (0, _utils.compileShader)(gl, _shaders.heatmapVertexShaderSource, gl.VERTEX_SHADER);
|
|
34
|
+
gl.attachShader(program, vertexShader);
|
|
35
|
+
const fragmentShader = (0, _utils.attachShader)(gl, program, fragmentShaderSource, gl.FRAGMENT_SHADER);
|
|
36
|
+
gl.linkProgram(program);
|
|
37
|
+
|
|
38
|
+
/* https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#dont_check_shader_compile_status_unless_linking_fails */
|
|
39
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
40
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
41
|
+
console.error(`Program linking failed: ${gl.getProgramInfoLog(program)}`);
|
|
42
|
+
console.error(`Vertex shader info-log: ${gl.getShaderInfoLog(vertexShader)}`);
|
|
43
|
+
console.error(`Fragment shader info-log: ${gl.getShaderInfoLog(fragmentShader)}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
this.shaders.push(vertexShader, fragmentShader);
|
|
47
|
+
const vao = gl.createVertexArray();
|
|
48
|
+
gl.bindVertexArray(vao);
|
|
49
|
+
bindAttribute(gl, program, 'a_position', this.quadBuffer, 2, 0);
|
|
50
|
+
bindAttribute(gl, program, 'a_center', this.centers.buffer, 2, 1);
|
|
51
|
+
/* Colors are uploaded as Uint8(Clamped)Array; shader sees normalized [0, 1] floats. */
|
|
52
|
+
bindAttribute(gl, program, 'a_color', this.colors.buffer, 4, 1, gl.UNSIGNED_BYTE, true);
|
|
53
|
+
bindAttribute(gl, program, 'a_saturation', this.saturations.buffer, 1, 1);
|
|
54
|
+
gl.bindVertexArray(null);
|
|
55
|
+
return {
|
|
56
|
+
program,
|
|
57
|
+
vao,
|
|
58
|
+
uResolution: gl.getUniformLocation(program, 'u_resolution'),
|
|
59
|
+
uDimensions: gl.getUniformLocation(program, 'u_dimensions'),
|
|
60
|
+
uBorderRadius: gl.getUniformLocation(program, 'u_borderRadius')
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
setBorderRadius(borderRadius) {
|
|
64
|
+
this.active = borderRadius > 0 ? this.roundedVariant : this.flatVariant;
|
|
65
|
+
if (this.active.uBorderRadius) {
|
|
66
|
+
this.gl.useProgram(this.active.program);
|
|
67
|
+
this.gl.uniform1f(this.active.uBorderRadius, borderRadius);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
setResolution(width, height) {
|
|
71
|
+
const {
|
|
72
|
+
gl
|
|
73
|
+
} = this;
|
|
74
|
+
gl.useProgram(this.flatVariant.program);
|
|
75
|
+
gl.uniform2f(this.flatVariant.uResolution, width, height);
|
|
76
|
+
gl.useProgram(this.roundedVariant.program);
|
|
77
|
+
gl.uniform2f(this.roundedVariant.uResolution, width, height);
|
|
78
|
+
}
|
|
79
|
+
setRectDimensions(width, height) {
|
|
80
|
+
const {
|
|
81
|
+
gl
|
|
82
|
+
} = this;
|
|
83
|
+
gl.useProgram(this.flatVariant.program);
|
|
84
|
+
gl.uniform2f(this.flatVariant.uDimensions, width, height);
|
|
85
|
+
gl.useProgram(this.roundedVariant.program);
|
|
86
|
+
gl.uniform2f(this.roundedVariant.uDimensions, width, height);
|
|
87
|
+
}
|
|
88
|
+
plot(plotData) {
|
|
89
|
+
const {
|
|
90
|
+
gl
|
|
91
|
+
} = this;
|
|
92
|
+
(0, _utils.uploadGrowableBuffer)(gl, this.centers, plotData.centers);
|
|
93
|
+
(0, _utils.uploadGrowableBuffer)(gl, this.colors, plotData.colors);
|
|
94
|
+
(0, _utils.uploadGrowableBuffer)(gl, this.saturations, plotData.saturations);
|
|
95
|
+
}
|
|
96
|
+
render(dataLength) {
|
|
97
|
+
if (dataLength === 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const {
|
|
101
|
+
gl
|
|
102
|
+
} = this;
|
|
103
|
+
gl.useProgram(this.active.program);
|
|
104
|
+
gl.bindVertexArray(this.active.vao);
|
|
105
|
+
gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, dataLength);
|
|
106
|
+
(0, _utils.logWebGLErrors)(gl);
|
|
107
|
+
}
|
|
108
|
+
dispose() {
|
|
109
|
+
const {
|
|
110
|
+
gl
|
|
111
|
+
} = this;
|
|
112
|
+
gl.deleteBuffer(this.quadBuffer);
|
|
113
|
+
gl.deleteBuffer(this.centers.buffer);
|
|
114
|
+
gl.deleteBuffer(this.colors.buffer);
|
|
115
|
+
gl.deleteBuffer(this.saturations.buffer);
|
|
116
|
+
gl.deleteProgram(this.flatVariant.program);
|
|
117
|
+
gl.deleteVertexArray(this.flatVariant.vao);
|
|
118
|
+
gl.deleteProgram(this.roundedVariant.program);
|
|
119
|
+
gl.deleteVertexArray(this.roundedVariant.vao);
|
|
120
|
+
this.shaders.forEach(shader => gl.deleteShader(shader));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.HeatmapWebGLProgram = HeatmapWebGLProgram;
|
|
124
|
+
function bindAttribute(gl, program, name, buffer, size, divisor, type = gl.FLOAT, normalized = false) {
|
|
125
|
+
const location = gl.getAttribLocation(program, name);
|
|
126
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
127
|
+
gl.enableVertexAttribArray(location);
|
|
128
|
+
gl.vertexAttribPointer(location, size, type, normalized, 0, 0);
|
|
129
|
+
if (divisor !== 0) {
|
|
130
|
+
gl.vertexAttribDivisor(location, divisor);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { attachShader, compileShader, createGrowableBuffer, logWebGLErrors, uploadGrowableBuffer } from "../../utils/webgl/utils.mjs";
|
|
2
|
+
import { heatmapFragmentShaderSourceNoBorderRadius, heatmapFragmentShaderSourceWithBorderRadius, heatmapVertexShaderSource } from "./shaders.mjs";
|
|
3
|
+
const QUAD_VERTICES = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
|
|
4
|
+
export class HeatmapWebGLProgram {
|
|
5
|
+
shaders = [];
|
|
6
|
+
constructor(gl) {
|
|
7
|
+
this.gl = gl;
|
|
8
|
+
/* Enable blending for transparency
|
|
9
|
+
* These are global to the WebGL context and need to be set only once */
|
|
10
|
+
gl.enable(gl.BLEND);
|
|
11
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
12
|
+
this.quadBuffer = gl.createBuffer();
|
|
13
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadBuffer);
|
|
14
|
+
gl.bufferData(gl.ARRAY_BUFFER, QUAD_VERTICES, gl.STATIC_DRAW);
|
|
15
|
+
this.centers = createGrowableBuffer(gl);
|
|
16
|
+
this.colors = createGrowableBuffer(gl);
|
|
17
|
+
this.saturations = createGrowableBuffer(gl);
|
|
18
|
+
|
|
19
|
+
/* Two pre-built programs let us swap border-radius on/off without re-linking. */
|
|
20
|
+
this.flatVariant = this.buildVariant(heatmapFragmentShaderSourceNoBorderRadius);
|
|
21
|
+
this.roundedVariant = this.buildVariant(heatmapFragmentShaderSourceWithBorderRadius);
|
|
22
|
+
this.active = this.flatVariant;
|
|
23
|
+
}
|
|
24
|
+
buildVariant(fragmentShaderSource) {
|
|
25
|
+
const gl = this.gl;
|
|
26
|
+
const program = gl.createProgram();
|
|
27
|
+
const vertexShader = compileShader(gl, heatmapVertexShaderSource, gl.VERTEX_SHADER);
|
|
28
|
+
gl.attachShader(program, vertexShader);
|
|
29
|
+
const fragmentShader = attachShader(gl, program, fragmentShaderSource, gl.FRAGMENT_SHADER);
|
|
30
|
+
gl.linkProgram(program);
|
|
31
|
+
|
|
32
|
+
/* https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#dont_check_shader_compile_status_unless_linking_fails */
|
|
33
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
34
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
35
|
+
console.error(`Program linking failed: ${gl.getProgramInfoLog(program)}`);
|
|
36
|
+
console.error(`Vertex shader info-log: ${gl.getShaderInfoLog(vertexShader)}`);
|
|
37
|
+
console.error(`Fragment shader info-log: ${gl.getShaderInfoLog(fragmentShader)}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
this.shaders.push(vertexShader, fragmentShader);
|
|
41
|
+
const vao = gl.createVertexArray();
|
|
42
|
+
gl.bindVertexArray(vao);
|
|
43
|
+
bindAttribute(gl, program, 'a_position', this.quadBuffer, 2, 0);
|
|
44
|
+
bindAttribute(gl, program, 'a_center', this.centers.buffer, 2, 1);
|
|
45
|
+
/* Colors are uploaded as Uint8(Clamped)Array; shader sees normalized [0, 1] floats. */
|
|
46
|
+
bindAttribute(gl, program, 'a_color', this.colors.buffer, 4, 1, gl.UNSIGNED_BYTE, true);
|
|
47
|
+
bindAttribute(gl, program, 'a_saturation', this.saturations.buffer, 1, 1);
|
|
48
|
+
gl.bindVertexArray(null);
|
|
49
|
+
return {
|
|
50
|
+
program,
|
|
51
|
+
vao,
|
|
52
|
+
uResolution: gl.getUniformLocation(program, 'u_resolution'),
|
|
53
|
+
uDimensions: gl.getUniformLocation(program, 'u_dimensions'),
|
|
54
|
+
uBorderRadius: gl.getUniformLocation(program, 'u_borderRadius')
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
setBorderRadius(borderRadius) {
|
|
58
|
+
this.active = borderRadius > 0 ? this.roundedVariant : this.flatVariant;
|
|
59
|
+
if (this.active.uBorderRadius) {
|
|
60
|
+
this.gl.useProgram(this.active.program);
|
|
61
|
+
this.gl.uniform1f(this.active.uBorderRadius, borderRadius);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
setResolution(width, height) {
|
|
65
|
+
const {
|
|
66
|
+
gl
|
|
67
|
+
} = this;
|
|
68
|
+
gl.useProgram(this.flatVariant.program);
|
|
69
|
+
gl.uniform2f(this.flatVariant.uResolution, width, height);
|
|
70
|
+
gl.useProgram(this.roundedVariant.program);
|
|
71
|
+
gl.uniform2f(this.roundedVariant.uResolution, width, height);
|
|
72
|
+
}
|
|
73
|
+
setRectDimensions(width, height) {
|
|
74
|
+
const {
|
|
75
|
+
gl
|
|
76
|
+
} = this;
|
|
77
|
+
gl.useProgram(this.flatVariant.program);
|
|
78
|
+
gl.uniform2f(this.flatVariant.uDimensions, width, height);
|
|
79
|
+
gl.useProgram(this.roundedVariant.program);
|
|
80
|
+
gl.uniform2f(this.roundedVariant.uDimensions, width, height);
|
|
81
|
+
}
|
|
82
|
+
plot(plotData) {
|
|
83
|
+
const {
|
|
84
|
+
gl
|
|
85
|
+
} = this;
|
|
86
|
+
uploadGrowableBuffer(gl, this.centers, plotData.centers);
|
|
87
|
+
uploadGrowableBuffer(gl, this.colors, plotData.colors);
|
|
88
|
+
uploadGrowableBuffer(gl, this.saturations, plotData.saturations);
|
|
89
|
+
}
|
|
90
|
+
render(dataLength) {
|
|
91
|
+
if (dataLength === 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const {
|
|
95
|
+
gl
|
|
96
|
+
} = this;
|
|
97
|
+
gl.useProgram(this.active.program);
|
|
98
|
+
gl.bindVertexArray(this.active.vao);
|
|
99
|
+
gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, dataLength);
|
|
100
|
+
logWebGLErrors(gl);
|
|
101
|
+
}
|
|
102
|
+
dispose() {
|
|
103
|
+
const {
|
|
104
|
+
gl
|
|
105
|
+
} = this;
|
|
106
|
+
gl.deleteBuffer(this.quadBuffer);
|
|
107
|
+
gl.deleteBuffer(this.centers.buffer);
|
|
108
|
+
gl.deleteBuffer(this.colors.buffer);
|
|
109
|
+
gl.deleteBuffer(this.saturations.buffer);
|
|
110
|
+
gl.deleteProgram(this.flatVariant.program);
|
|
111
|
+
gl.deleteVertexArray(this.flatVariant.vao);
|
|
112
|
+
gl.deleteProgram(this.roundedVariant.program);
|
|
113
|
+
gl.deleteVertexArray(this.roundedVariant.vao);
|
|
114
|
+
this.shaders.forEach(shader => gl.deleteShader(shader));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function bindAttribute(gl, program, name, buffer, size, divisor, type = gl.FLOAT, normalized = false) {
|
|
118
|
+
const location = gl.getAttribLocation(program, name);
|
|
119
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
120
|
+
gl.enableVertexAttribArray(location);
|
|
121
|
+
gl.vertexAttribPointer(location, size, type, normalized, 0, 0);
|
|
122
|
+
if (divisor !== 0) {
|
|
123
|
+
gl.vertexAttribDivisor(location, divisor);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -6,7 +6,7 @@ export declare function useHeatmapPlotData(drawingArea: ChartDrawingArea, series
|
|
|
6
6
|
}>, yScale: ScaleBand<{
|
|
7
7
|
toString(): string;
|
|
8
8
|
}>): {
|
|
9
|
-
centers: Float32Array<
|
|
10
|
-
colors:
|
|
11
|
-
saturations: Float32Array<
|
|
9
|
+
centers: Float32Array<ArrayBufferLike>;
|
|
10
|
+
colors: Uint8Array<ArrayBuffer>;
|
|
11
|
+
saturations: Float32Array<ArrayBufferLike>;
|
|
12
12
|
};
|
|
@@ -6,7 +6,7 @@ export declare function useHeatmapPlotData(drawingArea: ChartDrawingArea, series
|
|
|
6
6
|
}>, yScale: ScaleBand<{
|
|
7
7
|
toString(): string;
|
|
8
8
|
}>): {
|
|
9
|
-
centers: Float32Array<
|
|
10
|
-
colors:
|
|
11
|
-
saturations: Float32Array<
|
|
9
|
+
centers: Float32Array<ArrayBufferLike>;
|
|
10
|
+
colors: Uint8Array<ArrayBuffer>;
|
|
11
|
+
saturations: Float32Array<ArrayBufferLike>;
|
|
12
12
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
'use client';
|
|
2
3
|
|
|
3
4
|
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
4
5
|
Object.defineProperty(exports, "__esModule", {
|
|
@@ -9,49 +10,100 @@ var React = _interopRequireWildcard(require("react"));
|
|
|
9
10
|
var _hooks = require("@mui/x-charts/hooks");
|
|
10
11
|
var _internals = require("@mui/x-charts/internals");
|
|
11
12
|
var _parseColor = require("../../utils/webgl/parseColor");
|
|
13
|
+
/* Far enough off-canvas that the rect is never visible; used for invalid x/y entries.
|
|
14
|
+
* Avoids coupling the position pass to the color/saturation passes. */
|
|
15
|
+
const OFFSCREEN = -1e9;
|
|
16
|
+
function ensurePoolFloat32(pool, n) {
|
|
17
|
+
if (pool && pool.length >= n) {
|
|
18
|
+
return pool;
|
|
19
|
+
}
|
|
20
|
+
return new Float32Array(n);
|
|
21
|
+
}
|
|
12
22
|
function useHeatmapPlotData(drawingArea, series, xScale, yScale) {
|
|
13
23
|
const width = xScale.bandwidth();
|
|
14
24
|
const height = yScale.bandwidth();
|
|
15
25
|
const colorScale = (0, _hooks.useZColorScale)();
|
|
16
26
|
const store = (0, _internals.useStore)();
|
|
17
27
|
const getHighlightState = store.use(_internals.selectorChartsHighlightStateCallback);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
28
|
+
|
|
29
|
+
/* Colors only change when series data or color scale changes. Cached so resize/highlight
|
|
30
|
+
* renders don't re-upload the colors buffer.
|
|
31
|
+
* Stored as Uint8 (1 byte per channel) — 4x less GPU traffic than Float32 RGBA. */
|
|
32
|
+
const colors = React.useMemo(() => {
|
|
33
|
+
const out = new Uint8Array(series.data.length * 4);
|
|
24
34
|
for (let dataIndex = 0; dataIndex < series.data.length; dataIndex += 1) {
|
|
25
|
-
const
|
|
26
|
-
const x = xScale(xDomain[xIndex]);
|
|
27
|
-
const y = yScale(yDomain[yIndex]);
|
|
35
|
+
const value = series.data[dataIndex][2];
|
|
28
36
|
const color = colorScale?.(value);
|
|
29
|
-
if (
|
|
37
|
+
if (!color) {
|
|
38
|
+
/* Alpha 0 hides the rect; src-alpha blending makes RGB irrelevant. */
|
|
30
39
|
continue;
|
|
31
40
|
}
|
|
32
|
-
centers[dataIndex * 2] = x + width / 2 - drawingArea.left;
|
|
33
|
-
centers[dataIndex * 2 + 1] = y + height / 2 - drawingArea.top;
|
|
34
41
|
const rgbColor = (0, _parseColor.parseColor)(color);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
out[dataIndex * 4] = rgbColor[0];
|
|
43
|
+
out[dataIndex * 4 + 1] = rgbColor[1];
|
|
44
|
+
out[dataIndex * 4 + 2] = rgbColor[2];
|
|
45
|
+
out[dataIndex * 4 + 3] = 255;
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}, [colorScale, series.data]);
|
|
49
|
+
|
|
50
|
+
/* Saturations only change with highlight state. Pooled so highlight churn doesn't
|
|
51
|
+
* allocate per change. */
|
|
52
|
+
const saturationsPoolRef = React.useRef(null);
|
|
53
|
+
const saturations = React.useMemo(() => {
|
|
54
|
+
const n = series.data.length;
|
|
55
|
+
const pool = ensurePoolFloat32(saturationsPoolRef.current ?? undefined, n);
|
|
56
|
+
saturationsPoolRef.current = pool;
|
|
57
|
+
for (let dataIndex = 0; dataIndex < n; dataIndex += 1) {
|
|
58
|
+
const item = series.data[dataIndex];
|
|
39
59
|
const highlightState = getHighlightState({
|
|
40
60
|
type: 'heatmap',
|
|
41
61
|
seriesId: series.id,
|
|
42
|
-
xIndex,
|
|
43
|
-
yIndex
|
|
62
|
+
xIndex: item[0],
|
|
63
|
+
yIndex: item[1]
|
|
44
64
|
});
|
|
65
|
+
let saturation = 0;
|
|
45
66
|
if (highlightState === 'highlighted') {
|
|
46
|
-
|
|
67
|
+
saturation = 0.2;
|
|
47
68
|
} else if (highlightState === 'faded') {
|
|
48
|
-
|
|
69
|
+
saturation = -0.2;
|
|
70
|
+
}
|
|
71
|
+
pool[dataIndex] = saturation;
|
|
72
|
+
}
|
|
73
|
+
/* Subarray gives a fresh identity over the same bytes — upload short-circuit fires. */
|
|
74
|
+
return pool.subarray(0, n);
|
|
75
|
+
}, [getHighlightState, series.data, series.id]);
|
|
76
|
+
|
|
77
|
+
/* Positions change on resize (drawing area / band width). Pooled to avoid per-frame
|
|
78
|
+
* allocation. Subarray view gives a fresh identity each call so the upload still runs. */
|
|
79
|
+
const centersPoolRef = React.useRef(null);
|
|
80
|
+
const centers = React.useMemo(() => {
|
|
81
|
+
const n = series.data.length;
|
|
82
|
+
const pool = ensurePoolFloat32(centersPoolRef.current ?? undefined, n * 2);
|
|
83
|
+
centersPoolRef.current = pool;
|
|
84
|
+
const left = drawingArea.left;
|
|
85
|
+
const top = drawingArea.top;
|
|
86
|
+
const halfWidth = width / 2;
|
|
87
|
+
const halfHeight = height / 2;
|
|
88
|
+
const xDomain = xScale.domain();
|
|
89
|
+
const yDomain = yScale.domain();
|
|
90
|
+
for (let dataIndex = 0; dataIndex < n; dataIndex += 1) {
|
|
91
|
+
const item = series.data[dataIndex];
|
|
92
|
+
const x = xScale(xDomain[item[0]]);
|
|
93
|
+
const y = yScale(yDomain[item[1]]);
|
|
94
|
+
if (x === undefined || y === undefined) {
|
|
95
|
+
pool[dataIndex * 2] = OFFSCREEN;
|
|
96
|
+
pool[dataIndex * 2 + 1] = OFFSCREEN;
|
|
97
|
+
continue;
|
|
49
98
|
}
|
|
99
|
+
pool[dataIndex * 2] = x + halfWidth - left;
|
|
100
|
+
pool[dataIndex * 2 + 1] = y + halfHeight - top;
|
|
50
101
|
}
|
|
51
|
-
return
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
102
|
+
return pool.subarray(0, n * 2);
|
|
103
|
+
}, [drawingArea.left, drawingArea.top, height, series.data, width, xScale, yScale]);
|
|
104
|
+
return React.useMemo(() => ({
|
|
105
|
+
centers,
|
|
106
|
+
colors,
|
|
107
|
+
saturations
|
|
108
|
+
}), [centers, colors, saturations]);
|
|
57
109
|
}
|