我试图在HTML/JS中建立一个钟摆,它的角速度和角度由范围控制。这两个量程都能改变他们想要的东西,但是每次当量程的值被改变时,如果速度或角度增加或降低速度,那么摆的速度就会大大增加。
以下是HTML/JavaScript片段
var canvas = ctx = false;
var frameRate = 1/40;
var frameDelay = frameRate * 1000;
/*used to change the angle and the velocity of the pendulum*/
var arcSlider = document.getElementById("arc");
var velocitySlider = document.getElementById('velocity');
var arcNumber = document.getElementById("arcNum");
var velocityNumber = document.getElementById("velocityNum");
var arc = (arcSlider.value / 100);
var velocity = velocitySlider.value;
/*sets the values for the pendulum*/
var pendulum = {mass: 100, length:300, theta: (Math.PI/2) - arc , omega: 0, alpha:0, J:0};
/*listener for angl slider*/
arcSlider.addEventListener("change", function(){
arcNumber.innerHTML = "arc: " + (arcSlider.value / 100);
arc = arcSlider.value / 100;
init();
});
/*listener for velocity slider*/
velocitySlider.addEventListener("change", function(){
velocityNumber.innerHTML = "velocity: " + velocitySlider.value;
velocity = velocitySlider.value;
init();
});
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
function init() {
pendulum.J = pendulum.mass * pendulum.length * pendulum.length / velocity;
lastTime = new Date();
requestAnimFrame(draw);
}
/*loop for pendulum*/
function draw(){
var width = 1000, height = 600;
var len = 150;
var timeMs = (new Date()).getTime();
var deltaT = (timeMs - lastTime.getTime()) / 1000;
canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
if (deltaT > 0.050)
{
deltaT = 0.050;
}
deltaT = 0.01;
/* Calculate current position*/
pendulum.theta += pendulum.omega * deltaT + (.5 * pendulum.alpha * deltaT * deltaT );
/* calculates force */
var T = pendulum.mass * 9.81 * Math.cos(pendulum.theta) * pendulum.length;
/* Current acceleration */
var alpha = T / pendulum.J;
/*Calculate current velocity*/
pendulum.omega += .5 * (alpha + pendulum.alpha) * deltaT;
/* Update acceleration */
pendulum.alpha = alpha;
/*sets the current x and y for the pendulum*/
var bobX = width/2 + pendulum.length * Math.cos(pendulum.theta);
var bobY = pendulum.length * Math.sin(pendulum.theta);
/*clears the canvas*/
ctx.clearRect(0,0,width,height)
/*canvas line*/
ctx.strokeStyle = "green";
ctx.beginPath();
ctx.moveTo(width/2,0);
ctx.lineTo(bobX,bobY);
ctx.stroke();
ctx.closePath();
ctx.fillStyle = "red";
/*canvas pendulum*/
ctx.beginPath();
ctx.arc(bobX,bobY,16,0 ,Math.PI * 2 , false);
ctx.fill();
ctx.closePath();
requestAnimationFrame(draw);
}
init(); <div href="#0" class="button">
<canvas id="myCanvas" width="1000" height="400">
</canvas>
</div>
<div class="sliderOutline">
<div class="sliderContainer">
<p>Change the arc of the pendulum:</p>
<input type="range" name="arcRange"min="5" max="80" value="40" class="slider" id="arc">
<p>Change the velocity:</p>
<input type="range" min="0" max="1000" value="500" class="slider" id="velocity" >
<div>
<p id="arcNum">arc: 0.4 </p>
</div>
<div>
<p id="velocityNum">velocity: 500</p>
</div>
</div>
</div>
发布于 2018-03-29 20:27:34
每次调用init()时,init()都调用requestAnimationFrame(draw),当然,draw调用requestAnimationFrame(draw)是一种常见的模式。
但是,当您第二次调用init()时(例如,当用户修改滑块时),则再次调用requestAnimationFrame(draw)。当浏览器确定动画帧的时间时,draw将被调用两次。
每当动画帧准备好请求时,都会调用一堆函数。如果您只调用了一次requestAnimationFrame,那么堆栈get的一个draw条目就会被推到它上。当动画帧准备就绪时,堆栈就会弹出,直到它为空,并且函数一次一个地被调用。通常的做法是将一个函数推回堆栈,最后再调用requestAnimationFrame。
当您从这个普通循环外部多次调用requestAnimationFrame时,您将得到堆栈中的多个函数,每个动画帧都会调用这些函数。因为您的draw函数在每次调用钟摆时都会修改它的状态,所以经常调用它会使钟摆的运动速度提高两倍。在你的滑块上点击5或6次,它会像疯狂一样来回摇摆。
作为一个快速修复,您可以这样修改init:
function init(begin) {
pendulum.mass = 100;
pendulum.theta = (Math.PI/2) - arc;
pendulum.omega = 0;
pendulum.alpha = 0;
pendulum.J = pendulum.mass * pendulum.length * pendulum.length / velocity;
lastTime = new Date();
if (begin) requestAnimFrame(draw);
}在您的javascript的最底层,您可以调用:
init(true);如更新的代码所示。这不是最好的解决方案,只是一个很小的解决方案,可以证明不多次调用requestAnimationFrame应该会提供您想要的结果。
https://stackoverflow.com/questions/49564128
复制相似问题