最近要绘制大量的正弦函数,使用到了一些傅里叶变换的基础知识。
首先科普一下,任何周期函数都可以用傅里叶变换表示成正弦或余弦函数的组合。
最终绘制出的效果如下
刚开始想用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)
}
总结
这里的主要难点在于曲线坐标的确定,着实花费了小半天功夫才调试好。说明自己对傅里叶变换理解还不是很透彻,还需要再学一下。