Me gustaría replicar una función de onda sinusoidal como un resorte que se expande y contrae sin perder su estructura de onda original, como la animación de resorte de una caja negra que rebota (no la onda roja), que se encuentra aquí. Puedo dibujar una onda sinusoidal y editar su longitud, pero no puedo mantener la misma estructura de la onda sinusoidal.
Eche un vistazo a la animación en https://react-spring.io/#why-springs-and-not-durations
Puedes ver que el resorte se expande y se contrae sin perder su forma de onda.
var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); var i; for(i=0; i<360; i+= 20){ ctx.moveTo(i+5,180); ctx.lineTo(i,180); } ctx.stroke(); var counter = 0, x=0,y=180; //100 iterations var increase = ((110/180)*(Math.PI / 3)); for(i=0; i<=270; i+=10){ ctx.moveTo(x,y); x = i; y = 180 - Math.sin(counter) * 113; counter += increase; ctx.lineTo(x,y); ctx.stroke(); //alert( " x : " + x + " y : " + y + " increase : " + counter ) ; } <canvas id="myCanvas" width="360" height="360" style="border:1px solid #d3d3d3;">Para mantener la forma de onda en su lienzo, necesita un incremento de iteración más pequeño. Puede ver a continuación que usé un incremento de 0.1 .
También modifiqué la función para usar parámetros de scale para que puedas modificar el período y la amplitud:
var c = document.getElementById("myCanvas"); var ctx = c.getContext("2d"); var i; for (i = 0; i < 360; i += 20) { ctx.moveTo(i + 5, 180); ctx.lineTo(i, 180); } ctx.stroke(); const increase = 0.1; const scale = { x: 18, y: 90 }; for (let x = 0; x <= 360 / scale.x;) { ctx.moveTo(x * scale.x, Math.sin(x) * scale.y + 180); x += increase; ctx.lineTo(x * scale.x, Math.sin(x) * scale.y + 180); ctx.stroke(); } <canvas id="myCanvas" width="360" height="360" style="border:1px solid #d3d3d3;">En canvas, la forma más sencilla de imitar un seno podría ser ctx.quadraticCurveTo() . Aquí hay un período;
ctx.beginPath(); ctx.moveTo(150,50); // starting point of the curve ctx.quadraticCurveTo(160,60,150,70); // control point and final point ctx.quadraticCurveTo(140,80,150,90); // control point and final point Solo para darle una idea, preparé una implementación improvisada del ejemplo que vinculó. La oscilación vertical también es sinusoidal como se muestra en el ejemplo. Como siempre, todas las modificaciones y actualizaciones del DOM y el lienzo se realizarán detrás de requestAnimationFrame y dentro de un fragmento de documento.
var cont = document.getElementById("container"), frag = new DocumentFragment(), canvas, ctx; function drawSpring(startX, startY, spins = 10, radius = 20, period = 15){ ctx.beginPath(); ctx.moveTo(startX, startY); ctx.lineTo(startX,startY += 10); // increment startY by 10 and draw a line to startX startY while (spins--){ ctx.quadraticCurveTo(startX+radius, startY+period*0.25, startX, startY+period*0.5); ctx.quadraticCurveTo(startX-radius, startY+period*0.75, startX, startY+period); startY += period; } ctx.lineTo(startX, startY += 10); ctx.stroke(); ctx.fillRect(startX -= radius, startY,radius*2 , radius*2); } function oscillator(freq, amp, step = 0, spins = 10){ var delta = Math.sin(Math.PI*step)*amp/spins, period = 15 + delta; canvas = cont.children[0].cloneNode("true"); ctx = canvas.getContext('2d'); step = (step + Math.PI * freq / 60) % 120; requestAnimationFrame(_ => ( drawSpring(150,25,spins,20,period) , frag.appendChild(canvas) , cont.children[0].replaceWith(frag) , oscillator(freq,amp,step,spins) ) ); } oscillator(1,60); <div id="container"> <canvas width="300" height="300"></canvas> </div>