简体   繁体   English

JavaScript canvas 使用函数一一画圆

[英]JavaScript canvas draw circle one by one using function

My goal is to detect where does my function crosses first the Axes X on the negative side.我的目标是检测我的函数在哪里首先与负侧的 Axes X 交叉。 For that, I check from all the range at first, then I divide by two in one of the sides, depending the result.为此,我首先检查所有范围,然后根据结果在一侧除以 2。 I'd like to draw 1 by 1 all my circles.我想一一画我所有的圈子。 First time i got something like this:我第一次得到这样的东西:

在此处输入图片说明

and then i searched and tried this :然后我搜索并尝试了这个:

window.requestAnimationFrame(drawDicho(a,b));

And i thought it would draw each circle individually.我认为它会单独绘制每个圆圈。 But instead, it only draws the circle on coordinates (0,0).但相反,它只在坐标 (0,0) 上绘制圆。 If i click again, it draws on it again.如果我再次单击,它会再次绘制。

在此处输入图片说明

¨ ¨

I've tried window.setInterval(...) but nothing happened as well.我试过 window.setInterval(...) 但也没有发生任何事情。

I can recover the correct value, but I'd like to show the circles one by one and not all at the same time.我可以恢复正确的值,但我想一个一个地显示圆圈,而不是同时显示所有圆圈。 Does anyone have an idea ?有没有人有想法? Maybe I'm placing the code in the wrong place, i don't know..也许我把代码放在错误的地方,我不知道..

@UPDATE FULL CODE: @更新完整代码:

    <script type="text/javascript">
      window.onload = function(){
        var canvas = $('myCanvas');
        if(!canvas){
          alert("Impossible to recover canvas");
          return;
        }

        var context = canvas.getContext('2d');
        if(!context){
          alert("Impossible dto recover canvas context");
          return;
        }

        context.fillStyle = 'rgba(255, 255, 255, 1)';
        context.fillRect(0, 0, 500, 500);
        context.strokeStyle = 'rgba(0, 0, 0, 1)';

        var width = canvas.width;
        var height = canvas.height;

        //draw axis Y
        context.beginPath();
        context.moveTo(width/2, 0);
        context.lineTo(width/2, height);
        context.closePath();
        context.stroke();

        //draw axis X
        context.beginPath();
        context.moveTo(0, height/2);
        context.lineTo(width, height/2);
        context.closePath();
        context.stroke();


      }


      function function1(x){
        return Math.sin(x)-(x/13);
      }

      function function2(x){
        return x/(1-Math.pow(x, 2));
      }

      function draw(func){
        var canvas = $('myCanvas');
        var context = canvas.getContext('2d');
        var dx = canvas.width;
        var dy = canvas.height;
        var scale = dx/40; // echelle (nb pixels between x=0 et x=1)
        var x0 = dx/2;
        var y0 = dy/2;
        var iMax = 20;
        var x, y;
        var iMin = -20;
            context.translate(x0,y0);
      context.scale(1, -1);
            context.strokeStyle = 'rgba(255, 0, 0, 1)';
      context.beginPath();
      context.arc(-100, 0, 5, 0, 2*Math.PI, false);
      context.arc(100, 0, 5, 0, 2*Math.PI, false);

      for(i = -100; i<=100; i=i+0.01){
                x=i*4;
                y = scale * func(x/scale);
        context.lineTo(x, y);

          }
          context.closePath();
          context.stroke();
      }

      function drawF1(){
        draw(function1);
      }

      function drawF2(){
        draw(function2);
      }

      function drawDicho(a, b){
        var canvas = $('myCanvas');
        var context = canvas.getContext('2d');
        context.beginPath();
        context.arc(a, 0, 5, 0, 2*Math.PI, false);
        context.arc(b, 0, 5, 0, 2*Math.PI, false);
        context.closePath();
        context.stroke();
      }

      function dichotomie(func){
        var a = -100;
        var b = 100;
        var fa = func(a);
        var fb = func(b);
        var delta = 0.01;

        while(Math.abs(b-a) > delta){
        //drawDicho(a,b);
          var m = (a+b)/2;
          var fm = func(m);
          if(fm * fa <= 0){
            b = m;
            fb = fm;
          }
          else{
            a = m;
            fa = fm;
          }
          window.requestAnimationFrame(drawDicho(a,b));
        }
        if(fa * fb <= 0){
          return m.toFixed(3);

        }
        else{
          return 'no 0';
        }

      }

      function $(id){
        return document.getElementById(id);
      }

      function solvef1()
      {
        var result = dichotomie(function1);
        alert(result);
      }

      function solvef2(){
        var result = dichotomie(function2);
        alert(result);
      }

    </script>
</head>
<body style="background-color:grey">
  <p>
    <label>draw fonction: </label>
    <input type="button" name="function1" value="fonction 1" id="drawF1" onclick="drawF1()">
    <input type="button" name="function2" value="fonction 2" id="drawF2" onclick="drawF2()">
    <input type="button" name="solvef1" value="solvef1" id="solvef1" onclick="solvef1()">
    <input type="button" name="solvef2" value="solvef2" id="solvef2" onclick="solvef2()">
  </p>
    <br>
    <canvas id="myCanvas" width="500" height="500">
      Message bla bla bla
    </canvas>
</body>

(the dichotomie function which calc and draw circles is used when i click on button "solve f1") (当我点击按钮“solve f1”时使用计算和绘制圆圈的dichotomie功能)

Thank you.谢谢你。

window.requestAnimationFrame expects a function reference as parameter, such that the given function can be called a soon as the browser has finished rendering, but not faster than 60Hz. window.requestAnimationFrame需要一个函数引用作为参数,这样可以在浏览器完成渲染后立即调用给定的函数,但速度不超过 60Hz。

By doing:通过做:

while (…) {
  …
  window.requestAnimationFrame(drawDicho(a,b));
  …
}

you are calling drawDicho(a,b) right away within the while loop and assign the return value to requestAnimationFrame , which is undefined.您在while循环中立即调用drawDicho(a,b)并将返回值分配给未定义的requestAnimationFrame

What you need, at least I think you do, is an animation loop like this:你需要的,至少我认为你需要的是一个像这样的动画循环:

const DELAY = 1000;

let 
  last = new Date().getTime(),
  circles = [
    [10,10],
    [100, 100],
    [10, 100]
  ]
;

//replace while () {} with the loop below,
//this way the execution is scheduled
(function loop () {
  const 
    now = new Date().getTime(),
    delta = now - last;

  if (delta >= DELAY && circles.length > 0) {
    drawCircle(...circles.shift());
    last = now;
  }


  window.requestAnimationFrame(loop);

})();

This way loop will be called frequently.这种方式loop将被频繁调用。 A while loop is not an animation loop, the code is called right away. while 循环不是动画循环,代码会立即调用。 An animation loop runs with a certain »frame rate, what a while loop does not.动画循环以特定的 » 帧速率运行,而 while 循环则不然。

I update your dichotomie in following way ( 300 is number of miliseconds between draw circles) (run snippet on "Full page")我按以下方式更新您的dichotomie300是绘制圆圈之间的毫秒数)(在“完整页面”上运行代码段)

function dichotomie(func){
    ...
    var circs=[];

    while(Math.abs(b-a) > delta){
      ...
      circs.push([a,b])
    }

    circs.map((x,i) => setTimeout(y=> drawDicho(...x),i*300) );
    ...
  }

In this solution we use arrow functions and array map在这个解决方案中,我们使用箭头函数数组映射

 <script type="text/javascript"> window.onload = function(){ var canvas = $('myCanvas'); if(!canvas){ alert("Impossible to recover canvas"); return; } var context = canvas.getContext('2d'); if(!context){ alert("Impossible dto recover canvas context"); return; } context.fillStyle = 'rgba(255, 255, 255, 1)'; context.fillRect(0, 0, 500, 500); context.strokeStyle = 'rgba(0, 0, 0, 1)'; var width = canvas.width; var height = canvas.height; //draw axis Y context.beginPath(); context.moveTo(width/2, 0); context.lineTo(width/2, height); context.closePath(); context.stroke(); //draw axis X context.beginPath(); context.moveTo(0, height/2); context.lineTo(width, height/2); context.closePath(); context.stroke(); } function function1(x){ return Math.sin(x)-(x/13); } function function2(x){ return x/(1-Math.pow(x, 2)); } function draw(func){ var canvas = $('myCanvas'); var context = canvas.getContext('2d'); var dx = canvas.width; var dy = canvas.height; var scale = dx/40; // echelle (nb pixels between x=0 et x=1) var x0 = dx/2; var y0 = dy/2; var iMax = 20; var x, y; var iMin = -20; context.translate(x0,y0); context.scale(1, -1); context.strokeStyle = 'rgba(255, 0, 0, 1)'; context.beginPath(); context.arc(-100, 0, 5, 0, 2*Math.PI, false); context.arc(100, 0, 5, 0, 2*Math.PI, false); for(i = -100; i<=100; i=i+0.01){ x=i*4; y = scale * func(x/scale); context.lineTo(x, y); } context.closePath(); context.stroke(); } function drawF1(){ draw(function1); } function drawF2(){ draw(function2); } function drawDicho(a, b){ var canvas = $('myCanvas'); var context = canvas.getContext('2d'); context.beginPath(); context.arc(a, 0, 5, 0, 2*Math.PI, false); context.arc(b, 0, 5, 0, 2*Math.PI, false); context.closePath(); context.stroke(); } function dichotomie(func){ var a = -100; var b = 100; var fa = func(a); var fb = func(b); var delta = 0.01; var circs=[]; while(Math.abs(ba) > delta){ //drawDicho(a,b); var m = (a+b)/2; var fm = func(m); if(fm * fa <= 0){ b = m; fb = fm; } else{ a = m; fa = fm; } circs.push([a,b]) } console.log(circs); circs.map((x,i) => setTimeout(y=> drawDicho(...x),i*300) ); if(fa * fb <= 0){ return m.toFixed(3); } else{ return 'no 0'; } } function $(id){ return document.getElementById(id); } function solvef1() { var result = dichotomie(function1); alert(result); } function solvef2(){ var result = dichotomie(function2); alert(result); } </script> </head> <body style="background-color:grey"> <p> <label>draw fonction: </label> <input type="button" name="function1" value="fonction 1" id="drawF1" onclick="drawF1()"> <input type="button" name="function2" value="fonction 2" id="drawF2" onclick="drawF2()"> <input type="button" name="solvef1" value="solvef1" id="solvef1" onclick="solvef1()"> <input type="button" name="solvef2" value="solvef2" id="solvef2" onclick="solvef2()"> </p> <br> <canvas id="myCanvas" width="500" height="500"> Message bla bla bla </canvas> </body>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM