使用canvas(2d)+js实现一个简单的傅里叶级数绘制方波图

先看效果

查看页面右下角,嘿嘿

简要说明

  1. 创建具有不同半径与角速度的圆集合;(截图中展现的效果为5个,代码是30个,运行后效果会不同)
const getCircles = (N = 10) => {
  const ret = [];
  for (let i = 0; i < N; i += 1) {
    ret.push({ r: 100 / (i * 2 + 1), ω: i * 2 + 1, φ: 0 });
  }
  return ret;
};
const circles = getCircles(30);
  1. 计算某时刻相应圆的位置与旋转角度,并记录"叶圆端点"坐标值(画出来的形状有点怪啊,卧槽)
    let x = 0;
    let y = 0;
    circles.forEach((c) => {
      drawCircle(ctx, x, y, c);
      const st = { x, y };
      x += c.r * Math.cos((c.ω * idx * Math.PI) / 180);
      y += c.r * Math.sin((c.ω * idx * Math.PI) / 180);
      const sp = { x, y };
      drawVector(ctx, st, sp);
    });

    points.push(x);
    points.push(y);

3.将"叶圆端点"坐标集合使用bezier曲线逼近绘制曲线()

function drawSolve(ctx, data, k = null, color = null) {
  if (k === null) k = 1;
  var size = data.length;
  var last = size - 4;
  ctx.strokeStyle = color || "#Fff0f0";
  ctx.beginPath();
  ctx.moveTo(data[0], data[1]);
  for (var i = 0; i < size - 2; i += 2) {
    var x0 = i ? data[i - 2] : data[0];
    var y0 = i ? data[i - 1] : data[1];
    var x1 = data[i + 0];
    var y1 = data[i + 1];
    var x2 = data[i + 2];
    var y2 = data[i + 3];
    var x3 = i !== last ? data[i + 4] : x2;
    var y3 = i !== last ? data[i + 5] : y2;
    var cp1x = x1 + ((x2 - x0) / 6) * k;
    var cp1y = y1 + ((y2 - y0) / 6) * k;
    var cp2x = x2 - ((x3 - x1) / 6) * k;
    var cp2y = y2 - ((y3 - y1) / 6) * k;
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2);
  }
  ctx.stroke();
}
  1. 方波y值取"叶圆端点"坐标,x值随意;绘制方波图(依旧使用bezier)
    pssine.unshift(y);
    if (pssine.length > canvas.height * canvas.width) {
      pssine.pop();
    }
    const pp = [];
    pssine.forEach((p, i) => {
      pp.push(i / 2 + 200);
      pp.push(p);
    });
    drawSolve(ctx, pp, null, "#0000ff");

总结

大概就实现了此功能;但许多细节没有深究;需要优化;源码:fourier

参考

一组点怎么平滑地用曲线连接呢?
使用贝塞尔曲线绘制多点连接曲线
Catmull-Rom Spline

posted @ 2023-08-14 12:07  lenkaset  阅读(403)  评论(2编辑  收藏  举报