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

时间:2012-12-18 12:11:11

标签: javascript html5 svg

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

以下是X-Y坐标作为一个良好的开端......:)

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>

5 个答案:

答案 0 :(得分:25)

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

 0   0
1/2 1/2
 1   1
π/2  1

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

0                    0
0.512286623256592433 0.512286623256592433
1.002313685767898599 1
1.570796326794896619 1

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

Demo comparing line elements (gray) and "good" Bézier (red) and "better" Bézier (green).

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

       0                0 
(6−(3/2π−3)²)/6  (6−(3/2π−3)²)/6
       1                1
      π/2               1

See derivation

答案 1 :(得分: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);

​    ​

这是jsfiddle you can run

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

答案 2 :(得分:8)

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

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);
}
html, body, div{
    height:100%;
}
<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>

答案 3 :(得分:3)

如果它对任何人都有用:这是一个单线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>

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

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

答案 4 :(得分:1)

在X轴上循环,每次迭代使用当前X值的正弦函数计算Y位置。