From fe90c1bacd73826bf9f437f1be63b71dc0b126df Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 7 Apr 2020 22:02:58 -0700 Subject: [PATCH] Type preRenderBar --- js/components/Visualizer.tsx | 51 +++++++++++++++++++++++++++++++- js/components/VisualizerInner.js | 47 +---------------------------- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/js/components/Visualizer.tsx b/js/components/Visualizer.tsx index 55b8ce6c..b1e6f7c7 100644 --- a/js/components/Visualizer.tsx +++ b/js/components/Visualizer.tsx @@ -6,6 +6,8 @@ import { useTypedSelector, useActionCreator } from "../hooks"; import VisualizerInner from "./VisualizerInner"; const PIXEL_DENSITY = 2; +const BAR_WIDTH = 3 * PIXEL_DENSITY; +const GRADIENT_COLOR_COUNT = 16; type Props = { analyser: AnalyserNode; @@ -18,7 +20,7 @@ function preRenderBg( bgColor: string, fgColor: string, windowShade: boolean -) { +): HTMLCanvasElement { // Off-screen canvas for pre-rendering the background const bgCanvas = document.createElement("canvas"); bgCanvas.width = width; @@ -42,6 +44,48 @@ function preRenderBg( return bgCanvas; } +function preRenderBar( + height: number, + colors: string[], + renderHeight: number +): HTMLCanvasElement { + /** + * The order of the colours is commented in the file: the fist two colours + * define the background and dots (check it to see what are the dots), the + * next 16 colours are the analyzer's colours from top to bottom, the next + * 5 colours are the oscilloscope's ones, from center to top/bottom, the + * last colour is for the analyzer's peak markers. + */ + + // Off-screen canvas for pre-rendering a single bar gradient + const barCanvas = document.createElement("canvas"); + barCanvas.width = BAR_WIDTH; + barCanvas.height = height; + + const offset = 2; // The first two colors are for the background; + const gradientColors = colors.slice(offset, offset + GRADIENT_COLOR_COUNT); + + const barCanvasCtx = barCanvas.getContext("2d"); + if (barCanvasCtx == null) { + throw new Error("Could not construct canvas context"); + } + const multiplier = GRADIENT_COLOR_COUNT / renderHeight; + // In shade mode, the five colors are, from top to bottom: + // 214, 102, 0 -- 3 + // 222, 165, 24 -- 6 + // 148, 222, 33 -- 9 + // 57, 181, 16 -- 12 + // 24, 132, 8 -- 15 + // TODO: This could probably be improved by iterating backwards + for (let i = 0; i < renderHeight; i++) { + const colorIndex = GRADIENT_COLOR_COUNT - 1 - Math.floor(i * multiplier); + barCanvasCtx.fillStyle = gradientColors[colorIndex]; + const y = height - i * PIXEL_DENSITY; + barCanvasCtx.fillRect(0, y, BAR_WIDTH, PIXEL_DENSITY); + } + return barCanvas; +} + function Visualizer(props: Props) { const colors = useTypedSelector(Selectors.getSkinColors); const style = useTypedSelector(Selectors.getVisualizerStyle); @@ -67,6 +111,10 @@ function Visualizer(props: Props) { ); }, [colors, height, width, windowShade]); + const barCanvas = useMemo(() => { + return preRenderBar(height, colors, renderHeight); + }, [colors, height, renderHeight]); + const innerProps = { width: renderWidth, height: renderHeight, @@ -77,6 +125,7 @@ function Visualizer(props: Props) { dummyVizData, toggleVisualizerStyle, bgCanvas, + barCanvas, }; return ; } diff --git a/js/components/VisualizerInner.js b/js/components/VisualizerInner.js index e5cbcaee..a231ad59 100644 --- a/js/components/VisualizerInner.js +++ b/js/components/VisualizerInner.js @@ -6,7 +6,6 @@ const PIXEL_DENSITY = 2; const NUM_BARS = 20; const BAR_WIDTH = 3 * PIXEL_DENSITY; const BAR_PEAK_DROP_RATE = 0.01; -const GRADIENT_COLOR_COUNT = 16; const PEAK_COLOR_INDEX = 23; // Return the average value in a slice of dataArray @@ -40,40 +39,6 @@ function octaveBucketsForBufferLength(bufferLength) { return octaveBuckets; } -function preRenderBar(height, colors, renderHeight) { - /** - * The order of the colours is commented in the file: the fist two colours - * define the background and dots (check it to see what are the dots), the - * next 16 colours are the analyzer's colours from top to bottom, the next - * 5 colours are the oscilloscope's ones, from center to top/bottom, the - * last colour is for the analyzer's peak markers. - */ - - // Off-screen canvas for pre-rendering a single bar gradient - const barCanvas = document.createElement("canvas"); - barCanvas.width = BAR_WIDTH; - barCanvas.height = height; - - const offset = 2; // The first two colors are for the background; - const gradientColors = colors.slice(offset, offset + GRADIENT_COLOR_COUNT); - - const barCanvasCtx = barCanvas.getContext("2d"); - const multiplier = GRADIENT_COLOR_COUNT / renderHeight; - // In shade mode, the five colors are, from top to bottom: - // 214, 102, 0 -- 3 - // 222, 165, 24 -- 6 - // 148, 222, 33 -- 9 - // 57, 181, 16 -- 12 - // 24, 132, 8 -- 15 - // TODO: This could probably be improved by iterating backwards - for (let i = 0; i < renderHeight; i++) { - const colorIndex = GRADIENT_COLOR_COUNT - 1 - Math.floor(i * multiplier); - barCanvasCtx.fillStyle = gradientColors[colorIndex]; - const y = height - i * PIXEL_DENSITY; - barCanvasCtx.fillRect(0, y, BAR_WIDTH, PIXEL_DENSITY); - } - return barCanvas; -} class VisualizerInner extends React.Component { componentDidMount() { @@ -134,7 +99,6 @@ class VisualizerInner extends React.Component { } // TODO: Split this into to methods. One for skin update, one for style // update. - this.preRenderBar(); this.props.analyser.fftSize = 2048; if (this.props.style === VISUALIZERS.OSCILLOSCOPE) { this.bufferLength = this.props.analyser.fftSize; @@ -149,15 +113,6 @@ class VisualizerInner extends React.Component { } } - // Pre-render the bar gradient - preRenderBar() { - this.barCanvas = preRenderBar( - this._height(), - this.props.colors, - this._renderHeight() - ); - } - paintFrame() { switch (this.props.style) { case VISUALIZERS.OSCILLOSCOPE: @@ -222,7 +177,7 @@ class VisualizerInner extends React.Component { // Draw the gradient const b = BAR_WIDTH; if (height > 0) { - ctx.drawImage(this.barCanvas, 0, y, b, height, x, y, b, height); + ctx.drawImage(this.props.barCanvas, 0, y, b, height, x, y, b, height); } // Draw the gray peak line