I would like to replicate a sine wave function as a spring that expand and contracts without losing its original wave structure, like the spring animation of a bouncing black box (not the red wave), found here. Í am able to draw a sine wave and edit its length but cannot keep the same structure of the sine wave.
Take a look at the animation at https://react-spring.io/#why-springs-and-not-durations
You can see that the spring expands and contracts without losing its wave form.
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;">
To keep the wave form in your canvas you need a smaller iteration increment. You can see below that I used a 0.1 increment.
I also modified the function in order to use scale parameters so that you can modify the period and amplitude:
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;">
In canvas, the simplest way to imitate a sine could be done by ctx.quadraticCurveTo(). Here is one period;
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
Just to give you an idea i prepared a makeshift implementation of the example that you linked. The vertical oscillation is also sinusoidal like shown in the example. As always all modifications and updates of the DOM and canvas shall be done behind requestAnimationFrame and inside a document fragment.
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>