javascript - HTML slider 使钟摆速度翻倍

标签 javascript html

我正在尝试用 HTML/JS 制作一个钟摆,并使其 Angular 速度和 Angular 由范围控制。这两个范围都在改变他们的意图,但每次改变范围的值时,如果速度或 Angular 增加,它似乎会大大增加钟摆的速度 或降低速度。

这是 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>

最佳答案

每次调用 init() 时,init() 都会调用 requestAnimationFrame(draw),当然还有 draw 按照常见模式调用 requestAnimationFrame(draw)

然而,当您第二次调用 init() 时(例如,当用户修改 slider 时),您会再次调用 requestAnimationFrame(draw)。当浏览器确定是时候播放动画帧时,draw 将被调用两次。

每次准备好请求动画帧时,都会调用一堆函数。如果您调用 requestAnimationFrame 一次,那么堆栈就会将 draw 的一个条目推送到它上面。当动画帧准备好时,弹出堆栈直到它为空,并且一次调用一个函数。插入一个函数是一种常见的做法,该函数会在最后调用 requestAnimationFrame 将自己推回该堆栈。

当您从此正常循环之外多次调用 requestAnimationFrame 时,您最终会在该堆栈中获得多个函数,每个动画帧都会调用这些函数。因为您的 draw 函数在每次调用时都会修改钟摆的状态,所以两次调用它会使钟摆的移动速度提高一倍。在您的 slider 上点击 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);

如图an updated codepen .这不是最好的解决方案,只是一个最小的解决方案,表明不多次调用 requestAnimationFrame 应该会提供您正在寻找的结果。

关于javascript - HTML slider 使钟摆速度翻倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49564128/

相关文章:

javascript - AngularJS 不会在浏览器重新加载时运行

Javascript提交仅影响while循环php中的第一个div

javascript - aws-sdk 获取文件信息

javascript - JavaScript 创建的元素未被 CSS 文件格式化

javascript - 简单的 javascript split() 按预期工作?

javascript - PhoneGap 应用程序适用于 iOS 但不适用于 Android

javascript - 一个可以在 Javascript 中组合和链接(点符号)的函数

java utf-8编码问题

html - 响应式横幅广告

javascript函数将html div拉入master.html div