Spring-mass-damper
Пружина+амортизатор (колебания, damping)
by schrodingers
HTML
<canvas id="canvas" width=400 height=200></canvas>
<div class="controls">
<div>
<label>Stiffness (<span id="k_slider_label">-20</span> kg / s<sup>2</sup>)</label>
<input id="k_slider" type="range" min=0 max=100 value=20></input>
</div>
<div>
<label>Damping (<span id="b_slider_label">-0.5</span> kg / s)</label>
<input id="b_slider" type="range" min=0 max=10 value=0.5 step=0.1></input>
</div>
<div>
<label>Frequency (<span id="f_slider_label">0</span>) Hz</label>
<input id="f_slider" type="range" min=0 max=10 value=0 step=0.1></input>
</div>
<div>
<label>Mass (<span id="m_slider_label">0.5</span>) kg</label>
<input id="m_slider" type="range" min=0.1 max=5 value=0.5 step=0.05></input>
</div>
</div>
CSS
body {
font-family:Helvetica, Arial, sans-serif;
font-size:12px;
}
canvas {
display:block;
margin:20px auto;
width:400px;
height:200px;
border:1px solid #333;
}
.controls {
width:400px;
margin:10px auto;
}
.controls > div {
border-bottom:1px solid #EEE;
padding:5px 0;
}
.controls label {
width:200px;
display:inline-block;
}
.controls input {
vertical-align:middle;
}
JavaScript
/* Spring stiffness, in kg / s^2 */
var k = -20;
var spring_length = 180;
/* Damping constant, in kg / s */
var b = -0.5;
/* Block position and velocity. */
var block = {x: 100, v: 0, mass: 0.5};
var wall = {x: 30, lx: 30, v: 0, t: 0, frequency: 0};
var frameRate = 1/30;
var frameDelay = frameRate * 1000;
var canvas;
var ctx;
var width = 400;
var height = 200;
var loop = function() {
/* Move the wall. */
wall.t += frameRate;
wall.lx = wall.x;
wall.x = 30 + 70 * Math.sin(2 * Math.PI * wall.frequency * wall.t);
wall.v = (wall.x - wall.lx) / frameRate;
/* Move the block. */
if ( ! mouse.isDown )
{
var F_spring = k * ( (block.x - wall.x) - spring_length );
var F_damper = b * ( block.v - wall.v );
var a = ( F_spring + F_damper ) / block.mass;
block.v += a * frameRate;
block.x += block.v * frameRate;
}
/* Drawing */
ctx.clearRect(0, 0, width, height);
ctx.save();
for (x = wall.x; x < block.x; x += 20)
{
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.moveTo(x, height / 2 - 10);
ctx.lineTo(x + 10, height / 2);
ctx.lineTo(x + 20, height / 2 - 10);
ctx.stroke();
ctx.closePath();
}
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(0, height / 2 + 10);
ctx.lineTo(block.x, height / 2 + 10);
ctx.stroke();
ctx.closePath();
ctx.fillStyle = '#CCCCCC';
ctx.fillRect(0, 0, wall.x, height);
ctx.fillStyle = 'black';
ctx.fillRect(block.x, height - (height / 2 + 25), 50, 50);
ctx.restore();
};
var setup = function() {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
canvas.onmousemove = getMousePosition;
canvas.onmousedown = function(e) {
if (e.which == 1) {
getMousePosition(e);
mouse.isDown = true;
block.x = mouse.x - 25;
}
};
canvas.onmouseup =...