admin管理员组文章数量:1394578
I'm trying to animate a sine wave in JS but it's not acting as expected. I'm using a <canvas>
element along with window.requestAnimationFrame()
method but it's a CPU hog and as i change frequency with the slider it just break and show random waveforms. I also don't know if drawing adjacent lines is the best way to represent a sine wave. Please note that i'll use vanilla JS and that the sine's frequency and amplitude are variables set by sliders. Thanks in advance.
This is what i got so far:
UPDATE: i worked on it and this is the new version:
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
cHeight = canvas.height,
cWidth = canvas.width,
frequency = document.querySelector("#f").value,
amplitude = 80,
x = 0,
y = cHeight / 2,
point_y = 0;
window.onload = init;
function init() {
document.querySelector("#f").addEventListener("input", function() {
frequency = this.value;
document.querySelector("#output_f").value = frequency;
}, false);
drawSine();
}
function drawSine() {
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.beginPath();
ctx.moveTo(0, y);
ctx.strokeStyle = "red";
ctx.lineTo(cWidth, y);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = "black";
for (x = 0; x < 600; x++) {
point_y = amplitude * -Math.sin((frequency / 95.33) * x) + y;
ctx.lineTo(x, point_y);
}
ctx.stroke();
ctx.closePath();
requestAnimationFrame(drawSine);
}
canvas {
border: 1px solid red;
margin: 10px;
}
<input id="f" type="range" min="0" max="20000" value="20" step="1">
<output for="f" id="output_f">20</output>
<canvas width="600px" height="200px"></canvas>
I'm trying to animate a sine wave in JS but it's not acting as expected. I'm using a <canvas>
element along with window.requestAnimationFrame()
method but it's a CPU hog and as i change frequency with the slider it just break and show random waveforms. I also don't know if drawing adjacent lines is the best way to represent a sine wave. Please note that i'll use vanilla JS and that the sine's frequency and amplitude are variables set by sliders. Thanks in advance.
This is what i got so far: http://cssdeck./labs/8cq5vclp
UPDATE: i worked on it and this is the new version: http://cssdeck./labs/sbfynjkr
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
cHeight = canvas.height,
cWidth = canvas.width,
frequency = document.querySelector("#f").value,
amplitude = 80,
x = 0,
y = cHeight / 2,
point_y = 0;
window.onload = init;
function init() {
document.querySelector("#f").addEventListener("input", function() {
frequency = this.value;
document.querySelector("#output_f").value = frequency;
}, false);
drawSine();
}
function drawSine() {
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.beginPath();
ctx.moveTo(0, y);
ctx.strokeStyle = "red";
ctx.lineTo(cWidth, y);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = "black";
for (x = 0; x < 600; x++) {
point_y = amplitude * -Math.sin((frequency / 95.33) * x) + y;
ctx.lineTo(x, point_y);
}
ctx.stroke();
ctx.closePath();
requestAnimationFrame(drawSine);
}
canvas {
border: 1px solid red;
margin: 10px;
}
<input id="f" type="range" min="0" max="20000" value="20" step="1">
<output for="f" id="output_f">20</output>
<canvas width="600px" height="200px"></canvas>
Share
Improve this question
edited Jun 3, 2019 at 9:19
Roko C. Buljan
207k41 gold badges328 silver badges340 bronze badges
asked May 29, 2014 at 8:31
plumbe0plumbe0
1071 gold badge1 silver badge9 bronze badges
5
- It looks blocky and broken because you are doing i*10 as your x co-ordinate. Remove the *10 and reduce the frequency by a few thousand fold and it is much smoother. – Elle Commented May 29, 2014 at 9:02
- @JordanTrudgett i tried removing the *10 but it's still broken. The frequency range needs to be from 20 to 20k Hz as the sine represents a sound. I noticed that it draws the same, wrong, sines periodically: try 440 and 6710 (or 8000 and 17000) and you will get the ~same result. – plumbe0 Commented May 29, 2014 at 11:15
- What's happening is that because x is an integer value (i.e. a pixel) you will get patterns determined by the error from the real curve, try using (x*0.01) and see the values again, you can notice in this smaller sample of the curve the small errors that make the wave look 'bouncy' - if that is what you mean by broken. Or you could explain more what you expect. Perhaps look at Nyquist Frequency for a better explanation of discrete sampling. – Elle Commented May 30, 2014 at 12:53
- @JordanTrudgett i searched a bit and i found that my problem is related to aliasing. Any way i can handle it? Also i discovered AnalyserNode and i think that could really solve the problem, but i didn't understand it fully. – plumbe0 Commented May 30, 2014 at 15:44
- For an inspiration, this can be a good start (though it's not originally in JavaScript). – Mahozad Commented Nov 22, 2024 at 6:40
2 Answers
Reset to default 3I've messed around with sine waves quite a bit, because I'm working on a little project that involves animated sine waves. I've got some code you might be interested in taking a look at. Like mentioned earlier, you need to make sure you are using the right increment in your loop so the lines do not look jagged.
https://jsfiddle/uawLvymc/
window.requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(f) {
return setTimeout(f, 1000 / 60)
};
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var startTime = new Date().getTime();
function getPath(height) {
var width = canvas.width;
var spacing = 0.08;
var loopNum = 0;
var pointList = [];
var i = 0;
for (i = 0; i < width / 2; i++) {
pointList[loopNum] = [loopNum, Math.sin(loopNum * spacing) * (i * height) + 100];
loopNum++;
}
for (i = width / 2; i > 0; i--) {
pointList[loopNum] = [loopNum, Math.sin(loopNum * spacing) * (i * height) + 100];
loopNum++;
}
return pointList;
}
function draw() {
var currentTime = new Date().getTime();
var runTime = currentTime - startTime;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "rgb(80, 100, 230)";
var height = Math.sin(runTime * 0.008) * 0.2;
var pointList = getPath(height);
for (var i = 0; i < 500; i++) {
if (i === 0) {
ctx.moveTo(pointList[0][0], pointList[0][1]);
} else {
ctx.lineTo(pointList[i][0], pointList[i][1]);
}
}
ctx.stroke();
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
Sorry I didn't really edit down the code, it's just a direct copy from what I was working on. Hope it helps though.
See if this example could help you a little
Sine Wave Example canvas
function init()
{
setInterval(OnDraw, 200);
}
var time = 0;
var color = "#ff0000";
function OnDraw()
{
time = time + 0.2;
var canvas = document.getElementById("mycanvas");
var dataLine = canvas.getContext("2d");
var value = document.getElementById("lineWidth");
dataLine.clearRect(0, 0, canvas.width, canvas.height);
dataLine.beginPath();
for(cnt = -1; cnt <= canvas.width; cnt++)
{
dataLine.lineTo(cnt, canvas.height * 0.5 - (Math.random() * 2 + Math.cos(time + cnt * 0.05) * 20 ));
}
dataLine.lineWidth = value.value * 0.1;
dataLine.strokeStyle = color;
dataLine.stroke();
}
本文标签: javascriptAnimating sine wave in jsStack Overflow
版权声明:本文标题:javascript - Animating sine wave in js - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744096901a2590444.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论