@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.
Files changed (171) hide show
  1. package/BarChartPremium/BarChartPremium.js +2 -1183
  2. package/BarChartPremium/BarChartPremium.mjs +2 -1183
  3. package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.js +2 -0
  4. package/BarChartPremium/RangeBar/seriesConfig/seriesProcessor.mjs +2 -0
  5. package/CHANGELOG.md +133 -0
  6. package/CandlestickChart/CandlestickChart.d.mts +2 -2
  7. package/CandlestickChart/CandlestickChart.d.ts +2 -2
  8. package/CandlestickChart/CandlestickChart.js +2 -1183
  9. package/CandlestickChart/CandlestickChart.mjs +2 -1183
  10. package/CandlestickChart/CandlestickWebGLProgram.d.mts +6 -11
  11. package/CandlestickChart/CandlestickWebGLProgram.d.ts +6 -11
  12. package/CandlestickChart/CandlestickWebGLProgram.js +136 -121
  13. package/CandlestickChart/CandlestickWebGLProgram.mjs +137 -122
  14. package/CandlestickChart/useCandlestickPlotData.d.mts +2 -2
  15. package/CandlestickChart/useCandlestickPlotData.d.ts +2 -2
  16. package/CandlestickChart/useCandlestickPlotData.js +121 -61
  17. package/CandlestickChart/useCandlestickPlotData.mjs +122 -61
  18. package/ChartsAxisHighlightValue/index.d.mts +1 -0
  19. package/ChartsAxisHighlightValue/index.d.ts +1 -0
  20. package/ChartsAxisHighlightValue/index.js +16 -0
  21. package/ChartsAxisHighlightValue/index.mjs +2 -0
  22. package/ChartsDataProviderPremium/ChartsDataProviderPremium.js +2 -2
  23. package/ChartsDataProviderPremium/ChartsDataProviderPremium.mjs +2 -2
  24. package/ChartsRadialAxisHighlight/index.d.mts +1 -0
  25. package/ChartsRadialAxisHighlight/index.d.ts +1 -0
  26. package/ChartsRadialAxisHighlight/index.js +16 -0
  27. package/ChartsRadialAxisHighlight/index.mjs +2 -0
  28. package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.js +2 -2
  29. package/ChartsRadialDataProviderPremium/ChartsRadialDataProviderPremium.mjs +2 -2
  30. package/HeatmapPremium/HeatmapPremium.js +2 -155
  31. package/HeatmapPremium/HeatmapPremium.mjs +2 -155
  32. package/HeatmapPremium/webgl/HeatmapWebGLPlot.js +19 -112
  33. package/HeatmapPremium/webgl/HeatmapWebGLPlot.mjs +19 -111
  34. package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.mts +24 -0
  35. package/HeatmapPremium/webgl/HeatmapWebGLProgram.d.ts +24 -0
  36. package/HeatmapPremium/webgl/HeatmapWebGLProgram.js +132 -0
  37. package/HeatmapPremium/webgl/HeatmapWebGLProgram.mjs +125 -0
  38. package/HeatmapPremium/webgl/useHeatmapPlotData.d.mts +3 -3
  39. package/HeatmapPremium/webgl/useHeatmapPlotData.d.ts +3 -3
  40. package/HeatmapPremium/webgl/useHeatmapPlotData.js +78 -26
  41. package/HeatmapPremium/webgl/useHeatmapPlotData.mjs +80 -26
  42. package/LICENSE +3 -1
  43. package/RadialBarChart/RadialBarChart.d.mts +60 -0
  44. package/RadialBarChart/RadialBarChart.d.ts +60 -0
  45. package/RadialBarChart/RadialBarChart.js +298 -0
  46. package/RadialBarChart/RadialBarChart.mjs +292 -0
  47. package/RadialBarChart/RadialBarChart.plugins.d.mts +4 -0
  48. package/RadialBarChart/RadialBarChart.plugins.d.ts +4 -0
  49. package/RadialBarChart/RadialBarChart.plugins.js +9 -0
  50. package/RadialBarChart/RadialBarChart.plugins.mjs +3 -0
  51. package/RadialBarChart/RadialBarElement.d.mts +16 -0
  52. package/RadialBarChart/RadialBarElement.d.ts +16 -0
  53. package/RadialBarChart/RadialBarElement.js +54 -0
  54. package/RadialBarChart/RadialBarElement.mjs +48 -0
  55. package/RadialBarChart/RadialBarPlot.d.mts +21 -0
  56. package/RadialBarChart/RadialBarPlot.d.ts +21 -0
  57. package/RadialBarChart/RadialBarPlot.js +85 -0
  58. package/RadialBarChart/RadialBarPlot.mjs +79 -0
  59. package/RadialBarChart/index.d.mts +3 -0
  60. package/RadialBarChart/index.d.ts +3 -0
  61. package/RadialBarChart/index.js +39 -0
  62. package/RadialBarChart/index.mjs +3 -0
  63. package/RadialBarChart/radialBarClasses.d.mts +15 -0
  64. package/RadialBarChart/radialBarClasses.d.ts +15 -0
  65. package/RadialBarChart/radialBarClasses.js +26 -0
  66. package/RadialBarChart/radialBarClasses.mjs +18 -0
  67. package/RadialBarChart/seriesConfig/seriesProcessor.js +4 -0
  68. package/RadialBarChart/seriesConfig/seriesProcessor.mjs +4 -0
  69. package/RadialBarChart/useRadialBarChartProps.d.mts +28 -0
  70. package/RadialBarChart/useRadialBarChartProps.d.ts +28 -0
  71. package/RadialBarChart/useRadialBarChartProps.js +100 -0
  72. package/RadialBarChart/useRadialBarChartProps.mjs +93 -0
  73. package/RadialBarChart/useRadialBarPlotData.d.mts +23 -0
  74. package/RadialBarChart/useRadialBarPlotData.d.ts +23 -0
  75. package/RadialBarChart/useRadialBarPlotData.js +94 -0
  76. package/RadialBarChart/useRadialBarPlotData.mjs +87 -0
  77. package/RadialLineChart/RadialArea.js +13 -1
  78. package/RadialLineChart/RadialArea.mjs +13 -1
  79. package/RadialLineChart/RadialLine.js +13 -1
  80. package/RadialLineChart/RadialLine.mjs +13 -1
  81. package/RadialLineChart/RadialLineChart.d.mts +11 -3
  82. package/RadialLineChart/RadialLineChart.d.ts +11 -3
  83. package/RadialLineChart/RadialLineChart.js +24 -673
  84. package/RadialLineChart/RadialLineChart.mjs +24 -673
  85. package/RadialLineChart/RadialLineHighlightElement.d.mts +15 -0
  86. package/RadialLineChart/RadialLineHighlightElement.d.ts +15 -0
  87. package/RadialLineChart/RadialLineHighlightElement.js +46 -0
  88. package/RadialLineChart/RadialLineHighlightElement.mjs +39 -0
  89. package/RadialLineChart/RadialLineHighlightPlot.d.mts +23 -0
  90. package/RadialLineChart/RadialLineHighlightPlot.d.ts +23 -0
  91. package/RadialLineChart/RadialLineHighlightPlot.js +92 -0
  92. package/RadialLineChart/RadialLineHighlightPlot.mjs +86 -0
  93. package/RadialLineChart/RadialMarkPlot.js +17 -2
  94. package/RadialLineChart/RadialMarkPlot.mjs +17 -2
  95. package/RadialLineChart/index.d.mts +3 -1
  96. package/RadialLineChart/index.d.ts +3 -1
  97. package/RadialLineChart/index.js +22 -0
  98. package/RadialLineChart/index.mjs +3 -1
  99. package/RadialLineChart/radialLineClasses.d.mts +3 -1
  100. package/RadialLineChart/radialLineClasses.d.ts +3 -1
  101. package/RadialLineChart/radialLineClasses.js +2 -1
  102. package/RadialLineChart/radialLineClasses.mjs +2 -1
  103. package/RadialLineChart/seriesConfig/getItemAtPosition.d.mts +6 -0
  104. package/RadialLineChart/seriesConfig/getItemAtPosition.d.ts +6 -0
  105. package/RadialLineChart/seriesConfig/getItemAtPosition.js +353 -0
  106. package/RadialLineChart/seriesConfig/getItemAtPosition.mjs +348 -0
  107. package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.js +2 -1
  108. package/RadialLineChart/seriesConfig/getSeriesWithDefaultValues.mjs +2 -1
  109. package/RadialLineChart/seriesConfig/index.js +2 -1
  110. package/RadialLineChart/seriesConfig/index.mjs +2 -1
  111. package/RadialLineChart/seriesConfig/seriesProcessor.js +4 -0
  112. package/RadialLineChart/seriesConfig/seriesProcessor.mjs +4 -0
  113. package/RadialLineChart/useRadialLineChartProps.d.mts +2 -0
  114. package/RadialLineChart/useRadialLineChartProps.d.ts +2 -0
  115. package/RadialLineChart/useRadialLineChartProps.js +16 -8
  116. package/RadialLineChart/useRadialLineChartProps.mjs +16 -8
  117. package/RadialLineChart/useRadialLinePlotData.js +2 -1
  118. package/RadialLineChart/useRadialLinePlotData.mjs +3 -2
  119. package/ScatterChartPremium/ScatterChartPremium.d.mts +25 -0
  120. package/ScatterChartPremium/ScatterChartPremium.d.ts +25 -0
  121. package/ScatterChartPremium/ScatterChartPremium.js +507 -0
  122. package/ScatterChartPremium/ScatterChartPremium.mjs +501 -0
  123. package/ScatterChartPremium/ScatterChartPremium.plugins.d.mts +3 -0
  124. package/ScatterChartPremium/ScatterChartPremium.plugins.d.ts +3 -0
  125. package/ScatterChartPremium/ScatterChartPremium.plugins.js +8 -0
  126. package/ScatterChartPremium/ScatterChartPremium.plugins.mjs +2 -0
  127. package/ScatterChartPremium/ScatterPlotPremium.d.mts +14 -0
  128. package/ScatterChartPremium/ScatterPlotPremium.d.ts +14 -0
  129. package/ScatterChartPremium/ScatterPlotPremium.js +28 -0
  130. package/ScatterChartPremium/ScatterPlotPremium.mjs +21 -0
  131. package/ScatterChartPremium/index.d.mts +3 -0
  132. package/ScatterChartPremium/index.d.ts +3 -0
  133. package/ScatterChartPremium/index.js +26 -0
  134. package/ScatterChartPremium/index.mjs +3 -0
  135. package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.mts +4 -0
  136. package/ScatterChartPremium/webgl/ScatterWebGLPlot.d.ts +4 -0
  137. package/ScatterChartPremium/webgl/ScatterWebGLPlot.js +70 -0
  138. package/ScatterChartPremium/webgl/ScatterWebGLPlot.mjs +65 -0
  139. package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.mts +18 -0
  140. package/ScatterChartPremium/webgl/ScatterWebGLProgram.d.ts +18 -0
  141. package/ScatterChartPremium/webgl/ScatterWebGLProgram.js +129 -0
  142. package/ScatterChartPremium/webgl/ScatterWebGLProgram.mjs +122 -0
  143. package/ScatterChartPremium/webgl/shaders.d.mts +2 -0
  144. package/ScatterChartPremium/webgl/shaders.d.ts +2 -0
  145. package/ScatterChartPremium/webgl/shaders.js +57 -0
  146. package/ScatterChartPremium/webgl/shaders.mjs +51 -0
  147. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.mts +7 -0
  148. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.d.ts +7 -0
  149. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.js +140 -0
  150. package/ScatterChartPremium/webgl/useScatterWebGLPlotData.mjs +134 -0
  151. package/index.d.mts +3 -1
  152. package/index.d.ts +3 -1
  153. package/index.js +25 -1
  154. package/index.mjs +4 -2
  155. package/internals/index.d.mts +1 -0
  156. package/internals/index.d.ts +1 -0
  157. package/internals/index.js +13 -0
  158. package/internals/index.mjs +1 -0
  159. package/models/seriesType/radialLine.d.mts +7 -1
  160. package/models/seriesType/radialLine.d.ts +7 -1
  161. package/package.json +184 -114
  162. package/plugins/selectors/useChartCandlestickPosition.selectors.d.mts +1 -1
  163. package/plugins/selectors/useChartCandlestickPosition.selectors.d.ts +1 -1
  164. package/utils/webgl/parseColor.d.mts +2 -1
  165. package/utils/webgl/parseColor.d.ts +2 -1
  166. package/utils/webgl/parseColor.js +8 -7
  167. package/utils/webgl/parseColor.mjs +8 -7
  168. package/utils/webgl/utils.d.mts +13 -0
  169. package/utils/webgl/utils.d.ts +13 -0
  170. package/utils/webgl/utils.js +29 -0
  171. 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 { heatmapFragmentShaderSourceNoBorderRadius, heatmapFragmentShaderSourceWithBorderRadius, heatmapVertexShaderSource } from "./shaders.mjs";
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 [vertexShader] = React.useState(() => compileShader(gl, heatmapVertexShaderSource, gl.VERTEX_SHADER));
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
- gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, dataLength);
43
+ program?.render(dataLength);
52
44
  };
53
- }, [gl, dataLength]);
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
- /* Enable blending for transparency
60
- * These are global to the WebGL context and need to be set only once */
61
- gl.enable(gl.BLEND);
62
- gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
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
- const shouldAttachNewShader = lastSeriesBorderRadiusRef.current > 0 !== seriesBorderRadius > 0;
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
- }, [gl, program, requestRender, seriesBorderRadius, setupBorderRadiusUniform,
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
- setupResolutionUniform();
66
+ program?.setRectDimensions(width, height);
160
67
  requestRender();
161
- }, [setupResolutionUniform, requestRender]);
68
+ }, [width, height, program, requestRender]);
162
69
  React.useEffect(() => {
163
- setupRectDimensionsUniform();
70
+ program?.setBorderRadius(seriesBorderRadius);
164
71
  requestRender();
165
- }, [setupRectDimensionsUniform, requestRender]);
72
+ }, [seriesBorderRadius, program, requestRender]);
73
+ const plotData = useHeatmapPlotData(drawingArea, series, xScale, yScale);
166
74
  React.useEffect(() => {
167
- setupAttributes();
75
+ program?.plot(plotData);
168
76
  requestRender();
169
- }, [requestRender, setupAttributes]);
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<ArrayBuffer>;
10
- colors: Float32Array<ArrayBuffer>;
11
- saturations: Float32Array<ArrayBuffer>;
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<ArrayBuffer>;
10
- colors: Float32Array<ArrayBuffer>;
11
- saturations: Float32Array<ArrayBuffer>;
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
- return React.useMemo(() => {
19
- const centers = new Float32Array(series.data.length * 2);
20
- const colors = new Float32Array(series.data.length * 4);
21
- const saturations = new Float32Array(series.data.length);
22
- const xDomain = xScale.domain();
23
- const yDomain = yScale.domain();
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 [xIndex, yIndex, value] = series.data[dataIndex];
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 (x === undefined || y === undefined || !color) {
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
- colors[dataIndex * 4] = rgbColor[0];
36
- colors[dataIndex * 4 + 1] = rgbColor[1];
37
- colors[dataIndex * 4 + 2] = rgbColor[2];
38
- colors[dataIndex * 4 + 3] = 1.0;
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
- saturations[dataIndex] = 0.2;
67
+ saturation = 0.2;
47
68
  } else if (highlightState === 'faded') {
48
- saturations[dataIndex] = -0.2;
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
- centers,
53
- colors,
54
- saturations
55
- };
56
- }, [colorScale, drawingArea.left, drawingArea.top, height, getHighlightState, series.data, series.id, width, xScale, yScale]);
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
  }