如何用SVG(+ JS)绘制正弦波?

Sk8*_*ter 19 javascript html5 svg

在SVG中绘制正弦波最简单的解决方案是什么?我想正弦波应该用一个简单的循环用JavaScript重复... :)

这里是XY坐标作为一个良好的开端...... :)

http://jsbin.com/adaxuy/1/edit

<svg>
  <line x1="0" y1="250" x2="500" y2="250"
        style="stroke:black;stroke-width:1"/>
  <line x1="250" y1="0" x2="250" y2="500"
        style="stroke:black;stroke-width:1"/>
</svg>
Run Code Online (Sandbox Code Playgroud)

Tho*_*s W 26

直线近似的替代方案是贝塞尔近似.一个周期的第一个四分之一的相当好的近似值是具有以下控制点的立方贝塞尔曲线:

 0   0
1/2 1/2
 1   1
?/2  1
Run Code Online (Sandbox Code Playgroud)

编辑: 使用以下控制点可以实现更精确的近似:

0                    0
0.512286623256592433 0.512286623256592433
1.002313685767898599 1
1.570796326794896619 1
Run Code Online (Sandbox Code Playgroud)

(参见评论中的NominalAnimal的解释)

演示比较线元素(灰色)和"好"Bézier(红色)和"更好"Bézier(绿色).

精确插值样条曲线端点中的斜率和曲率的近似值是

       0                0 
(6?(3/2??3)²)/6  (6?(3/2??3)²)/6
       1                1
      ?/2               1
Run Code Online (Sandbox Code Playgroud)

(见派生)

  • 您可以使用`0,0`,`0.512286623256592433,0.512286623256592433`,`1.002313685767898599,1`,`1.570796326794896619,1`获得绝对误差(当将结果图与y = sin x进行比较时)0.0000584414≃1/ 17111正弦波的四分之一周期.@broofa:请注意,这是一个立方Bézier,而不是二次Bézier,并且Béziers通常比类似折线更快更平滑. (5认同)
  • @broofa:实际上*很简单.使用线性x,并使用分段立方体插值y.因此,使用由'x [n],y [n]`,`x [n]*2/3 + x [n + 1]/3,y [n] + dy定义的Bézier曲线段而不是线段[n]*(x [n + 1] -x [n])/ 3`,`x [n]/3 + x [n + 1]*2/3,y [n + 1] -dy [n +1]*(x [n + 1] -x [n])/ 3`,和`x [n + 1],y [n + 1]`,其中`x [n]`是采样点, `y [n] = f(x [n])`(即f在x [n]处),和`dy [n] = d(f(t)/ dt)[t = x [n]]` (即x [n]处的f的导数或斜率).*最优*曲线更难找到,但这会产生*可接受的*分段三次近似. (4认同)

Asa*_*din 9

以下是line向SVG元素添加多个元素的概念验证:

var svg = document.getElementById('sine_wave').children[0];
var origin = { //origin of axes
    x: 100,
    y: 100
};
var amplitude = 10; // wave amplitude
var rarity = 1; // point spacing
var freq = 0.1; // angular frequency
var phase = 0; // phase angle

for (var i = -100; i < 1000; i++) {
    var line = document.createElementNS("http://www.w3.org/2000/svg", "line");

    line.setAttribute('x1', (i - 1) * rarity + origin.x);
    line.setAttribute('y1', Math.sin(freq*(i - 1 + phase)) * amplitude + origin.y);

    line.setAttribute('x2', i * rarity + origin.x);
    line.setAttribute('y2', Math.sin(freq*(i + phase)) * amplitude + origin.y);

    line.setAttribute('style', "stroke:black;stroke-width:1");

    svg.appendChild(line);
}
Run Code Online (Sandbox Code Playgroud)
html, body, div{
    height:100%;
}
Run Code Online (Sandbox Code Playgroud)
<div id="sine_wave">

  <svg width="1000" height="1000">
    <line x1="100" y1="0" x2="100" y2="200"
          style="stroke:black;stroke-width:1"/>
    <line x1="0" y1="100" x2="1000" y2="100"
          style="stroke:black;stroke-width:1"/>
  </svg>

</div>
Run Code Online (Sandbox Code Playgroud)


bro*_*ofa 8

以下内容将为您的SVG图添加一个周期的正弦波:

var XMAX = 500;
var YMAX = 500;

// Create path instructions
var path = [];
for (var x = 0; x <= XMAX; x++) {
    var angle = (x / XMAX) * Math.PI * 2;  // angle = 0 -> 2?
    var y = Math.sin(angle) * (YMAX / 2) + (YMAX / 2);
    // M = move to, L = line to
    path.push((x == 0 ? 'M' : 'L') + x + ',' + y);
}

// Create PATH element
var pathEl = document.createElementNS("http://www.w3.org/2000/svg", "path");
pathEl.setAttribute('d', path.join(' ') );
pathEl.style.stroke = 'blue';
pathEl.style.fill = 'none';

// Add it to svg element
document.querySelector('svg').appendChild(pathEl);

?    ?
Run Code Online (Sandbox Code Playgroud)

这是你可以运行jsfiddle.

这使用由'lineto'(直线)命令组成的PATH元素.这是有效的,因为毫不奇怪,它包含许多(500)小线段.您可以通过使用贝塞尔曲线绘制段来简化路径以获得更少的点,但这会使代码复杂化.你要求简单.:)


sff*_*ffc 5

如果它对任何人都有用:这是一个单线 SVG,它使用三次贝塞尔曲线近似近似正弦波的一半。

<svg width="100px" height="100px" viewBox="0 0 100 100">
    <path stroke="#000000" fill="none" d="M0,0 C36.42,0,63.58,100,100,100" />
</svg>
Run Code Online (Sandbox Code Playgroud)

36.42我通过最小化贝塞尔曲线和真实余弦曲线之间的平方和 (l2) 距离来拟合参数。https://octave-online.net/bucket~AN33qHTHk7eARgoSe7xpYg

我的答案部分基于How to approximation a half-cosine curve with bezier paths in SVG?