问题
I am able to draw lines around a circle. I have the basic implementation of the AudioContext API setup.
The problem I am facing is when calling lineTo
the line will only grow but not shrink. I am inspired by this https://www.kkhaydarov.com/audio-visualizer/. I am translating this code over into https://codesandbox.io/s/hungry-tereshkova-1pf0c?runonclick=1&file=/src/Visualizer.js:713-725 which is a React.js version.
If you run that code you will see the music play, then the bars will grow once, and then they stick. They refuse to shrink then grow to the beat.
I am not sure where I am going wrong or what I am missing in that code. It seems pretty similar to the other code in the example.
Here is the full code for the Visualizer component.
import React, { useEffect, useRef } from "react";
let frequencyArray = [];
let analyser;
const Visualizer = () => {
const canvasRef = useRef(null);
const requestRef = useRef(null);
useEffect(() => {
initAudio();
requestRef.current = requestAnimationFrame(drawCanvas);
return () => cancelAnimationFrame(requestRef.current);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const initAudio = () => {
const audio = new Audio();
audio.src =
"https://s3.us-west-2.amazonaws.com/storycreator.uploads/ck9kpb5ss0xf90132mgf8z893?client_id=d8976b195733c213f3ead34a2d95d1c1";
audio.crossOrigin = "anonymous";
audio.load();
const context = new (window.AudioContext || window.webkitAudioContext)();
analyser = context.createAnalyser();
const source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
frequencyArray = new Uint8Array(analyser.frequencyBinCount);
audio.play();
};
// draw the whole thing
const drawCanvas = () => {
if (canvasRef.current) {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
const radius = 200;
const bars = 100;
drawCircle(canvas, ctx, radius);
analyser.getByteFrequencyData(frequencyArray);
for (var i = 0; i < bars; i++) {
const height = frequencyArray[i] * 0.3;
drawLine(
{
i,
bars,
height,
radius
},
canvas,
ctx
);
}
requestRef.current = requestAnimationFrame(drawCanvas);
}
};
// draw the main circle
const drawCircle = (canvas, ctx, radius) => {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
ctx.save();
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = "white";
ctx.fill();
ctx.strokeStyle = "#dddddd";
ctx.lineWidth = 5;
ctx.stroke();
ctx.restore();
};
// dray lines around the circle
const drawLine = (opts, canvas, ctx) => {
const { i, radius, bars, height } = opts;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const lineWidth = 10;
const rads = (Math.PI * 2) / bars;
const x = centerX + Math.cos(rads * i) * (radius + lineWidth);
const y = centerY + Math.sin(rads * i) * (radius + lineWidth);
const endX = centerX + Math.cos(rads * i) * (radius + height);
const endY = centerY + Math.sin(rads * i) * (radius + height);
// draw the bar
ctx.strokeStyle = "#ddd";
ctx.lineWidth = lineWidth;
ctx.lineCap = "round";
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(endX, endY);
ctx.stroke();
};
return (
<canvas
ref={canvasRef}
style={{ background: "#f5f5f5" }}
width={window.innerWidth}
height={window.innerHeight}
/>
);
};
export default Visualizer;
回答1:
You just missed a clearRect
in your code...
Without that we see the lines grow only because any following shorter line does not overwrite the previous one, they are still getting drawn just we do not see it.
here is the working code:
https://codesandbox.io/s/dry-cdn-ghu4m?file=/src/Visualizer.js:1247-1276
I hardcoded a ctx.clearRect(0,0, 1000,1000)
just to show you that it works, but you should use the canvas dimensions there, everything else looks good.
Only recommendation will be to somehow move:
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
somewhere global outside the drawCanvas function,
those do not change on every run, will be nice to set them just once.
来源:https://stackoverflow.com/questions/61903270/html5-canvas-draw-lines-in-a-circle-and-move-with-music