diff --git a/src/renderer/visualizers/SpectrumAnalyzer.ts b/src/renderer/visualizers/SpectrumAnalyzer.ts index 24c4133..c8dc23b 100644 --- a/src/renderer/visualizers/SpectrumAnalyzer.ts +++ b/src/renderer/visualizers/SpectrumAnalyzer.ts @@ -1005,10 +1005,7 @@ export class SpectrumAnalyzer { private renderHeatmap(xPoints: Float32Array, yPoints: Float32Array, heatmapIntensity: Float32Array, pointCount: number, width: number, height: number): void { const baseColor = this.options.heatBaseColor const parsedBaseColor = baseColor ? parseColorToRgba(baseColor) : null - if (baseColor && baseColor !== 'transparent' && (!parsedBaseColor || parsedBaseColor.a > 0)) { - this.ctx.fillStyle = baseColor - this.ctx.fillRect(0, 0, width, height) - } + const shouldRenderBaseColor = !!baseColor && baseColor !== 'transparent' && (!parsedBaseColor || parsedBaseColor.a > 0) for (let index = 0; index < pointCount; index += 1) { const x = Math.floor(xPoints[index]) @@ -1020,6 +1017,11 @@ export class SpectrumAnalyzer { continue } + if (shouldRenderBaseColor) { + this.ctx.fillStyle = baseColor + this.ctx.fillRect(x, Math.floor(y), columnWidth, Math.ceil(fillHeight)) + } + const lutIndex = Math.round(heatmapIntensity[index] * 255) const r = this.heatLut[lutIndex * 4] const g = this.heatLut[lutIndex * 4 + 1] diff --git a/test/renderer-helpers.test.ts b/test/renderer-helpers.test.ts index 82f95a3..ac7fae0 100644 --- a/test/renderer-helpers.test.ts +++ b/test/renderer-helpers.test.ts @@ -776,7 +776,11 @@ function renderSpectrumSnapshot(options: Partial): { } } -function renderSpectrumHeatmap(options: Partial, heatmapIntensity: number[]): FakeCanvasRecorder { +function renderSpectrumHeatmap( + options: Partial, + heatmapIntensity: number[], + yPoints: number[] = heatmapIntensity.map(() => 0), +): FakeCanvasRecorder { const recorder = createFakeCanvasRecorder() const dom = installFakeCanvasDom() const canvas = createFakeCanvas(recorder) @@ -812,7 +816,7 @@ function renderSpectrumHeatmap(options: Partial, heatma } state.renderHeatmap( Float32Array.from(heatmapIntensity.map((_value, index) => index)), - Float32Array.from(heatmapIntensity.map(() => 0)), + Float32Array.from(yPoints), Float32Array.from(heatmapIntensity), heatmapIntensity.length, canvas.width, @@ -1307,6 +1311,32 @@ test('SpectrumAnalyzer heatmap honors authored token alpha for low-end heat colo assert.equal(renderedAlpha.some((value) => Math.abs(value - 1) < 1e-3), true) }) +test('SpectrumAnalyzer heat base only fills the visible heatmap area under the curve', () => { + const recorder = renderSpectrumHeatmap( + { + heatBaseColor: 'rgb(12, 34, 56)', + heatColors: [ + 'rgba(15, 7, 33, 0)', + 'rgba(163, 26, 121, 0)', + 'rgba(255, 241, 209, 0)', + ], + }, + [0, 0, 0], + [8, 12, 16], + ) + + const baseRects = recorder.fillRects.filter((rect) => rect.fillStyle === 'rgb(12, 34, 56)') + assert.equal(baseRects.length, 3) + assert.deepEqual( + baseRects.map((rect) => ({ x: rect.x, y: rect.y, width: rect.width, height: rect.height })), + [ + { x: 0, y: 8, width: 1, height: 16 }, + { x: 1, y: 12, width: 1, height: 12 }, + { x: 2, y: 16, width: 1, height: 8 }, + ], + ) +}) + test('Spectrogram heatmap preserves authored alpha in generated image data', () => { const imageData = renderSpectrogramColumnImage({ heatColors: [