Подтвердить что ты не робот

Как нарисовать синусоидальные волны с SVG (+ JS)?

Какое будет самое простое решение для рисования синусоидальных волн в 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>
4b9b3361

Ответ 1

Вот доказательство концепции, которая добавляет несколько элементов 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);
}

Вот демонстрация: http://jsfiddle.net/HyTad/

Ответ 2

Альтернативой прямолинейным аппроксимациям было бы приближение Безье. Довольно хорошим приближением первой четверти одного периода является кубическая кривая Безье со следующими контрольными точками:

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

Edit: Возможны еще более точные аппроксимации со следующими контрольными точками:

0                    0
0.512286623256592433 0.512286623256592433
1.002313685767898599 1
1.570796326794896619 1

(См. примечания NominalAnimal в комментариях)

Демонстрация сравнения элементов линии (серый) и "хороший" Безье (красный) и "лучший" Безье (зеленый).

Аппроксимация, которая точно интерполирует наклон и кривизну в конечных точках сплайна, составляет

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

(См. вывод)

Ответ 3

Следующее добавит однострочную синусоидальную волну к вашему графику 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 вы можете запустить.

Здесь используется элемент PATH, составленный из команд lineto (прямая линия). Это работает, потому что, что неудивительно, оно содержит много (500) небольших сегментов. Вы можете упростить путь, чтобы иметь меньше точек, используя кривые Безье для рисования сегментов, но это усложняет код. И вы попросили простую.:)

Ответ 4

Петли по оси X и для каждой итерации вычисляют положение Y с помощью синусоиды на текущем значении X.

Ответ 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>

Я установил параметр 36.42, минимизируя квадрат квадрата (l2) между кривой безье и истинной косинусной кривой. https://octave-online.net/bucket~AN33qHTHk7eARgoSe7xpYg

Мой ответ частично основан на Как аппроксимировать полукосинусную кривую с помощью траекторий безье в SVG?