【问题标题】:Animate sine wave, fixed start and end points动画正弦波,固定起点和终点
【发布时间】:2019-05-10 18:20:52
【问题描述】:

我的画布中有一个正弦波,它是动画的,左右摇摆。我想要实现的是起点和终点保持固定。如何实现?

这里是Code Pen

function start() {
  var canvas = document.getElementById("canvas");
  var context = canvas.getContext("2d");
  context.clearRect(0, 0, canvas.width, canvas.height);
  drawCurves(context, step);

  step += 5;
  window.requestAnimationFrame(start);
}

var step = -4;

function drawCurves(ctx, step) {
  var width = ctx.canvas.width;
  var height = ctx.canvas.height;
  ctx.beginPath();
  ctx.lineWidth = 2;
  ctx.strokeStyle = "rgb(66,44,255)";

  var x = 4;
  var y = 0;
  var amplitude = 20;
  var frequency = 90;
  while (y < height) {
    x = width / 2 + amplitude * Math.sin((y + step) / frequency);
    ctx.lineTo(x, y);
    y++;
  }
  ctx.stroke();
}
canvas {
  background-color: wheat;
}
<!DOCTYPE html>
<html>

<head>
</head>

<body onload="start()">

  <canvas id="canvas" width="500" height="2000"></canvas>

</body>

</html>

【问题讨论】:

    标签: javascript html5-canvas sine-wave


    【解决方案1】:

    我更改了画布的大小,因为我希望能够看到它。你可以把它改回你需要的。

    我做了两件事:

    1. 频率必须是var frequency = height / (2 * Math.PI);var frequency = height / (4 * Math.PI);。分频器必须是 2 * Math.PI 的倍数

    2. 我将上下文向相反的方向翻译相同的数量:ctx.translate(-amplitude * Math.sin(step / frequency), 0);

    如果您需要更细微的振荡,请使用振幅。

    在我的代码中有一个注释掉的ctx.closePath() 请取消注释这一行以清楚地看到正弦波固定在中心。我希望这就是你要问的。

    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    
    
    function start() {
    
      context.clearRect(0, 0, canvas.width, canvas.height);
      drawCurves(context, step);
    
      step += 5;
      window.requestAnimationFrame(start);
    }
    
    var step = -4;
    
    function drawCurves(ctx, step) {
      var width = ctx.canvas.width;
      var height = ctx.canvas.height;
      ctx.beginPath();
      ctx.lineWidth = 2;
      ctx.strokeStyle = "rgb(66,44,255)";
    
      var x = 0;
      var y = 0;
      var amplitude = 10;
      var frequency = height / (2 * Math.PI);
      ctx.save();
      ctx.translate(-amplitude * Math.sin(step / frequency), 0);
      while (y < height) {
        x = width / 2 + amplitude * Math.sin((y + step) / frequency);
        ctx.lineTo(x, y);
        y++;
      }
      //ctx.closePath();
      ctx.stroke();
      ctx.restore();
    }
    
    start();
    canvas {
      background-color: wheat;
    }
    
    div {
      width: 100px;
      height: 400px;
      border: solid;
    }
    <div class="box">
    <canvas id="canvas" width="100" height="400"></canvas>
    </div>

    更新

    如果你需要使用多条曲线,你可以这样做:

    我将绘制波形的所有功能都放在函数drawWave 中,该函数将幅度和三角函数(正弦或余弦)用作参数:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var width = ctx.canvas.width;
    var height = ctx.canvas.height;
    var step = -4;
    
    function start() {
      window.requestAnimationFrame(start);
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      drawWave(10,"sin");
      drawWave(10,"cos");
      drawWave(5,"sin");
      
      step += 5; 
    }
    
    
      
    function drawWave(amplitude,trig){
      // trig is the trigonometric function to be used: sin or cos
      ctx.beginPath();
      ctx.lineWidth = 2;
      ctx.strokeStyle = "rgb(66,44,255)";
    
      var x = 0;
      var y = 0;
      //var amplitude = 10;
      var frequency = height / (2 * Math.PI);
      ctx.save();
      ctx.translate(-amplitude * Math[trig](step / frequency), 0);
      while (y < height) {
        x = width / 2 + amplitude * Math[trig]((y + step) / frequency);
        ctx.lineTo(x, y);
        y++;
      }
    
      ctx.stroke();
      ctx.restore();
    }
    
    start();
    canvas {
      background-color: wheat;
    }
    
    div {
      width: 100px;
      height: 400px;
      border: solid;
    }
    <div class="box">
    <canvas id="canvas" width="100" height="400"></canvas>
    </div>

    【讨论】:

    • 谢谢你,这就是我要问的!也许你可以进一步帮助我,我想要达到的最终效果是这个(riteshkukreja.github.io/sine-wave)。目前所有波浪都在做完全相同的事情,我无法改变每个波浪的速度和方向!您可以在最初问题中提供的我的代码笔中看到更新。谢谢!
    • 天才!有没有办法设置 closePath() 的样式,比如添加不同的宽度和颜色?
    • closePath()?我不确定我是否理解你。如果你想要不同的颜色波浪,你可以在drawWave 函数中添加第三个参数:颜色。您可以将此颜色用于strokeStyle
    • 海浪很好!但是如果我添加closePath(),它会从右上到下画一条直线吗?这就是我想改变样式的那一行!这有意义吗?
    • 在这种情况下,对于直线,您可以添加另一个振幅 = 0 的波:
    【解决方案2】:

    GLSL 版本

    因为这个片段着色器中的 uv 坐标在 0 到 1 之间变化,所以很容易达到目标,你只需要可以被 pi 整除的波频率。

    let gl = canvas.getContext('webgl');
    gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,  3, -1, -1, 3, -1]), gl.STATIC_DRAW);
    
    let pid = gl.createProgram();
    shader(`attribute vec2 v;void main(void){gl_Position=vec4(v.xy,0.,1.);}`,gl.VERTEX_SHADER);
    shader(document.querySelector(`script[type="glsl"]`).textContent,gl.FRAGMENT_SHADER);
    gl.linkProgram(pid);
    gl.useProgram(pid);
    
    let v = gl.getAttribLocation(pid, "v");
    gl.vertexAttribPointer(v, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(v);
    
    let resolution = gl.getUniformLocation(pid, 'resolution');
    let time = gl.getUniformLocation(pid, 'time');
    
    requestAnimationFrame(draw);
    
    function draw(t) {
      gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
      gl.clearColor(0, 0, 0, 0);
      gl.uniform1f(time, t/500);
      gl.uniform2f(resolution, gl.drawingBufferWidth, gl.drawingBufferHeight);
      gl.drawArrays(gl.TRIANGLES, 0, 3);
      requestAnimationFrame(draw);
    }
    
    function shader(src, type) {
      let sid = gl.createShader(type);
      gl.shaderSource(sid, src);
      gl.compileShader(sid);
      gl.attachShader(pid, sid);
    }
    <canvas width="200" height="600" id="canvas"/>
    <script type="glsl">
    precision highp float;
    uniform float time;
    uniform vec2 resolution;
    
    void main(void) {
      vec2 uv = gl_FragCoord.xy / resolution.xy;
      vec2 p = 20.*uv - 10.;
      vec3 f = vec3(0.);
      f+=pow(abs(p.x+5.*sin(time*2.)*sin(uv.y*6.28*2.)+cos(uv.y*11.)),-0.8)*vec3(.5,.0,.5);
      f+=pow(abs(p.x+4.*sin(time*3.)*sin(uv.y*6.28*.5)+cos(uv.y*21.)),-0.8)*vec3(.5,.5,.0);
      f+=pow(abs(p.x+3.*sin(time*5.)*sin(uv.y*6.28*1.)+cos(uv.y*17.)),-0.8)*vec3(.0,.5,.5);
      gl_FragColor = vec4(f, 1.);  
    }
    </script>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-26
      相关资源
      最近更新 更多