使用D3绘制傅里叶最简单的展开表达式

438 阅读1分钟

最近要绘制大量的正弦函数,使用到了一些傅里叶变换的基础知识。

首先科普一下,任何周期函数都可以用傅里叶变换表示成正弦或余弦函数的组合。

最终绘制出的效果如下

刚开始想用svg的node元素来绘制,但是发现节点数量较多时,延迟卡顿现象非常严重。本来想使用canvas来绘制,但是发现数量并非特别巨大,svg的path就可以胜任。 path的有好几个属性:

  • M = moveto
  • L = lineto
  • H = horizontal lineto
  • V = vertical lineto
  • C = curveto
  • S = smooth curveto
  • Q = quadratic Belzier curve
  • T = smooth quadratic Belzier curveto
  • A = elliptical Arc
  • Z = closepath 我这里其实只使用到了M和L属性就完成了曲线的绘制。

html部分

<svg>
  <defs>
    <marker id="Triangle" viewBox="0 0 20 20" refX="0" refY="10"
        markerWidth="10" markerHeight="10" orient="auto">
      <path d="M 0 0 L 20 10 L 0 20 z" />
    </marker>
  </defs>
  <circle className="circles" r={this.state.radius} cx={this.state.radius + 5} cy={this.state.radius + 5}></circle>
  <line className="lines" x1={this.state.radius + 5} y1={this.state.radius + 5} x2={this.state.lineX2} y2={this.state.lineY2}></line>
  <line markerEnd="url(#Triangle)" className="lines2" x1={this.state.lineX2} y1={this.state.lineY2} x2={this.state.lineX2 + this.state.radius*3 - 10} y2={this.state.lineY2}></line>
  <path className="paths" d={this.state.path}></path>
</svg>

JS部分

startRotate () {
  let data = this.state.data
  setInterval(() => {
    const angle = (Math.PI / 180) * this.state.num;
    const x2 = Math.cos(angle) * this.state.radius + this.state.radius + 5;
    const y2 = Math.sin(angle) * this.state.radius + this.state.radius + 5;
    data = [{x2, y2}, ...this.state.data];
    let path = '';
    let path2 = '';
    data.forEach((item, index) => {
      if (index === 0) {
        path += `M${x2 + index + this.state.radius*3} ${Math.sin((Math.PI / 180) * (this.state.num + index)) * this.state.radius + this.state.radius + 5}`
      } else {
        path += ` L${x2 + index + this.state.radius*3} ${Math.sin((Math.PI / 180) * (this.state.num + index)) * this.state.radius + this.state.radius + 5}`
      }
    })
    this.setState({
      num: this.state.num + 1,
      width: this.state.data.length,
      lineX2: x2,
      lineY2: y2,
      data,
      path,
      path2
    })
  }, 1000/144)
}

总结

这里的主要难点在于曲线坐标的确定,着实花费了小半天功夫才调试好。说明自己对傅里叶变换理解还不是很透彻,还需要再学一下。

查看demo