0
votes

I try to write pendulum simulation with canvas. My goal is to change start angle by clicking on Animate button and stop one by clicking Stop. But animate(a0deg) and clearInterval(id) doesn't work inside onClick functions.

If I enter these functions to console everything is ok, it works fine (for example I can write clearInterval(id); and animation will stop and then animate(new_a0deg) and animation will begin with new start angle), but if I put this functions inside onClick events - its doesn't work. It's really strange. Any ideas how to fix it? Please help. Thank you.

By the way link to jsbin: http://jsbin.com/pafoteku/2/edit (Important: in jsbin it works another way, not like in local html file. This is another one strange thing. After click on button everithing disappear).

Problem here:

document.getElementById("animate").onclick = function () {
    //alert('onClick begin');
    clearInterval(id); // < - This doesn't work
    a0deg = document.getElementById("angle").value;
    animate(a0deg); // < - This doesn't work
    //alert('a0deg = '+a0deg);
};

document.getElementById("stop").onclick = function () {
    clearInterval(id); // < - This doesn't work
};

Whole code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Pendulum</title>

<style >
canvas {
  background: #f0f0f0;
  border: 1px solid #ccc;
}

</style>
</head>
  <body>
    <form >
      <label>
        Angle:
        <input type="text" id="angle" name="angle" value="80" />
      </label>
      <button  id="animate" >Animate</button>
      <button id="stop" >Stop</button>
    </form>
    <canvas id="canvas" width="600" height="400">

  <script>
var a0deg = document.getElementById("angle").value;     //a0deg start angle (deg)
var id = null; //id of setInterval

function animate(a0deg) { 

    var canvas = document.getElementById('canvas');
    var ctx    = canvas.getContext('2d');

    var fps = 60;           //fps
    var f = 1000/fps;       //time between frames
    var t = 0;              //current time
    var l = 1;              //phisical length of pendulum

    var a0 = Math.PI*a0deg/180; //a0deg start angle (rad)

    var lCanvas = 300;      //pendulum length on canvas (px) 
    var g = 9.8 ;           //g

    function draw() {
        t += f / 1000;
        ctx.clearRect(0, 0, 600, 400);

        ctx.save();
        ctx.translate(300, 0);

        var theta = a0 * Math.cos(t/(Math.sqrt(l/g)))/Math.exp(t/10); 
        ctx.rotate(theta);

        ctx.strokeStyle = '#000'; /* нить */
        ctx.beginPath();
        ctx.moveTo(0, 0); 
        ctx.lineTo(0, lCanvas);
        ctx.lineWidth = 1;
        ctx.stroke();
        ctx.closePath(); 

        ctx.beginPath();         /* груз */
        ctx.arc(0, lCanvas, 5, 0, 2*Math.PI, false);
        ctx.fill();
        ctx.restore();
    }  
    id = setInterval(draw , f);
}

animate(a0deg); 

document.getElementById("animate").onclick = function () {
    //alert('onClick begin');
    clearInterval(id);
    a0deg = document.getElementById("angle").value;
    animate(a0deg); 
    //alert('a0deg = '+a0deg);
};

document.getElementById("stop").onclick = function () {
    clearInterval(id);
};

</script>
</body>
</html>
3
Try to reduce the code, take out all the parts that are not part of the problem. Make it easier for the users that want to to help you.givanse
Also, have you opened a debugger (firebug etc.)? Do you see any errors? What web browser are you using and what version?givanse
I've tried it in last versions of Chrome and FF. In debugger no any errors.WebBrother

3 Answers

4
votes

Demo

Use

<button type="button" id="animate">Animate</button>
<button type="button" id="stop">Stop</button>

or

<input type="button" id="animate" value="Animate" />
<input type="button" id="stop" value="Stop" />

Note that unless you use type="button", <button> elements can behave buggy in some browsers.

And in this case, they behave like a submit button, so they send the form, reloading the page.

Then, another way of avoiding that problem, could be using

button.onclick = function (e) {
    /* Click event handler */
    e && e.preventDefault && e.preventDefault();
    return false;
};

Where e.preventDefault prevents sending the form. Note that old browsers, which don't support it, may need the nonstandard (DOM0) return false.

4
votes

try add

return false;

at the end of your onclick code.

0
votes

Another solution is to not use form buttons and skip all the browser/forms quircks. Make your own button and everything works fine. This are all the changes I made to your code:

<div id="animate" style="background-color: gray; cursor: pointer;">Animate</div>
<div id="stop"    style="background-color: gray; cursor: pointer;">Stop</div> 

I'm sure you can add CSS styles and make them prettier.