问题描述
我正在尝试在画布上制作正弦波,该画布会被填充某种颜色。我成功创建了wave动画。但是,我似乎无法正确地填补空缺。您可以在下面的代码段中看到我的代码的工作方式
const canvas = document.querySelector('canvas')
const gui = new dat.GUI()
const c = canvas.getContext('2d')
canvas.width = innerWidth
canvas.height = innerHeight
const wave = {
y: canvas.height / 2,length: 0.01,amplitude: 150,frequency: 0.01
}
const strokeColor = {
h: 200,s: 50,l: 50
}
const backgroundColor = {
r: 255,g: 50,b: 255,a: 1
}
const waveFolder = gui.addFolder('wave')
waveFolder.add(wave,'y',canvas.height)
waveFolder.add(wave,'length',-0.01,0.01)
waveFolder.add(wave,'amplitude',-300,300)
waveFolder.add(wave,'frequency',1)
const strokeFolder = gui.addFolder('stroke')
strokeFolder.add(strokeColor,'h',255)
strokeFolder.add(strokeColor,'s',100)
strokeFolder.add(strokeColor,'l',100)
const backgroundFolder = gui.addFolder('background')
backgroundFolder.add(backgroundColor,'r',255)
backgroundFolder.add(backgroundColor,'g',255)
backgroundFolder.add(backgroundColor,'b','a',1)
let increment = 0
function drawSineWave() {
c.fillStyle = `rgba(${backgroundColor.r},${backgroundColor.g},${backgroundColor.b},${backgroundColor.a})`
c.clearRect(0,canvas.width,canvas.height)
increment++
c.beginPath()
c.moveto(0,canvas.height / 2)
c.lineto(0,canvas.height)
c.lineto(canvas.width,canvas.height / 2)
c.moveto(0,canvas.height / 2)
for (let i = 0; i < canvas.width; i++) {
c.lineto(i,wave.y + Math.sin(increment / 50) * wave.amplitude * Math.sin(i * wave.length + wave.frequency))
}
c.lineto(canvas.width,canvas.height / 2)
c.strokeStyle = `hsl(${strokeColor.h},${strokeColor.s}%,${strokeColor.l}%)`
c.fill()
c.stroke()
}
function animate() {
requestAnimationFrame(animate)
drawSineWave()
}
animate()
* {
margin: 0;
padding: 0;
Box-sizing: border-Box;
}
canvas {
width: 100%;
height: 100%;
}
<head>
<title>Waves</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<canvas></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<script src="index.js"></script>
</body>
我希望波浪的外观是这样的:
有人可以帮助我达到预期的结果吗?谢谢!
解决方法
您只需要按正确的顺序绘制下半部分
结果是
function drawSineWave() {
c.fillStyle = `rgba(${backgroundColor.r},${backgroundColor.g},${backgroundColor.b},${backgroundColor.a})`
c.clearRect(0,canvas.width,canvas.height)
increment++
c.beginPath()
for (let i = 0; i < canvas.width; i++) {
c.lineTo(i,wave.y + Math.sin(increment / 50) * wave.amplitude * Math.sin(i * wave.length + wave.frequency))
}
c.strokeStyle = `hsl(${strokeColor.h},${strokeColor.s}%,${strokeColor.l}%)`
c.stroke(); // draw stroke along wave top only
c.lineTo(canvas.width,canvas.height) // bottom right
c.lineTo(0,canvas.height) // bottom left
c.fill()
}
示例
我玩了一点。
const canvas = document.querySelector('canvas')
const gui = new dat.GUI()
const c = canvas.getContext('2d')
canvas.width = innerWidth
canvas.height = innerHeight
const wave = {
offset: canvas.height/2,speed: 1,amplitude:50,frequency: 1,}
var disFreq = wave.frequency,disFreqChase = 0;
var disAmp = wave.amplitude,disAmpChase = 0;
var disY = wave.offset,disYChase = 0;
var disSp = wave.speed,disSpChase = 0;
const strokeColor = {width: 2,h:200,s:50,l:50 }
const backgroundColor = { r:255,g:50,b:255,a:1 }
const waveFolder = gui.addFolder('wave')
waveFolder.add(wave,'speed',-1,1); // peeks per second
waveFolder.add(wave,'offset',canvas.height);
waveFolder.add(wave,'amplitude',-100,100)
waveFolder.add(wave,'frequency',0.5,10); // frequency also defines wave length
// Value is fraction of canvas width
const strokeFolder = gui.addFolder('stroke')
strokeFolder.add(strokeColor,'width',18)
strokeFolder.add(strokeColor,'h',255)
strokeFolder.add(strokeColor,'s',100)
strokeFolder.add(strokeColor,'l',100)
const backgroundFolder = gui.addFolder('background')
backgroundFolder.add(backgroundColor,'r',255)
backgroundFolder.add(backgroundColor,'g','b','a',1)
let increment = 0
function drawSineWave() {
// smooth out changes
disFreq += disFreqChase = (disFreqChase += (wave.frequency - disFreq)*0.2)* 0.2;
disAmp += disAmpChase = (disAmpChase += (wave.amplitude - disAmp) * 0.2) * 0.2;
disY += disYChase = (disYChase += (wave.offset - disY) * 0.2) * 0.2;
disSp += disSpChase = (disSpChase += (wave.speed - disSp) * 0.2) * 0.2;
c.lineWidth = strokeColor.width;
c.fillStyle = `rgba(${backgroundColor.r},${backgroundColor.a})`
c.clearRect(0,canvas.height)
//increment++
increment += (disSp / 60);
c.beginPath()
const h = canvas.height;
for (let i=0;i<canvas.width;i++){
const a = (disAmp / 200) * h;
const x = ((i / canvas.width) * disFreq) % 1 + increment;
const p = x * Math.PI * 2;
c.lineTo(i,disY + Math.sin(p)*a);
}
c.strokeStyle = `hsl(${strokeColor.h},${strokeColor.l}%)`
c.stroke()
c.lineTo(canvas.width,canvas.height)
c.lineTo(0,canvas.height)
c.fill()
}
function animate(){
requestAnimationFrame(animate)
drawSineWave()
}
animate()
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
canvas{
width: 100%;
height: 100%;
}
<canvas></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<script src="index.js"></script>
</body>