使用prototype方法在构造函数中设置setTimeout

时间:2017-09-05 01:25:26

标签: javascript html canvas

我有以下构造函数和原型:

function drawCircles() {
    $.each(circles, function() {
        this.draw(context);
    });
}

Circle.prototype.draw = function {
    // Drawing the circle using HTML5 canvas tag
}

circles是一个数组。渲染时,如何在每个圆圈之间以100毫秒的间隔绘制所有圆圈?

我尝试了以下但是它返回了 Uncaught TypeError: this.draw is not a function

function drawCircles() {
    // context.clearRect(0, 0, screenW, screenH);
    var interval;
    $.each(circles, function(index) {
        setTimeout(function(){
            this.draw(context);
        }, interval);
        interval += 500;
    });
}

2 个答案:

答案 0 :(得分:0)

您必须为此使用异步方法(而不是for循环)。

你可以通过制作一个闭包来做到这一点。例如:

function drawCircles() {             // main function
  var i = 0, me = this;              // parent scope: iterator, self
  if (!circles.length) return;       // no circles to draw

  (function loop() {                 // inner loop
    var circle = circles[i++];       // get circle and increment iterator
    me.draw(circle, context);        // draw
    if (i >= circles.length) i = 0;  // reset iterator
    setTimeout(loop, 100);           // wait 100 ms, call inner loop
  })();                              // self-invoked
}

您可以使用flag或取消超时来停止循环。

function CircleCascade(context) {
  this.circles = [];
  this.context = context;
}
CircleCascade.prototype = {
  generate: function(count) {
    for(var i = 0; i < count; i++) {
      this.circles.push({
        x: Math.random() * this.context.canvas.width,
        y: Math.random() * this.context.canvas.height,
        r: Math.random() * 100 + 20,
        c: "hsl(" + (360 * Math.random()) + ",50%,50%)"
      })
    }
  },
  
  drawCircles: function() {            // main function
    var i = 0, me = this;              // parent scope: iterator, self
    if (!me.circles.length) return;    // no circles to draw

    (function loop() {                 // inner loop
      var circle = me.circles[i++];    // get circle and increment iterator
      me.draw(circle, me.context);     // draw
      if (i >= me.circles.length) i=0; // reset iterator
      setTimeout(loop, 100);           // wait 100 ms, call inner loop
    })();                              // self-invoked
  },
  
  draw: function(circle, context) {
    context.beginPath();
    context.fillStyle = circle.c;
    context.arc(circle.x, circle.y, circle.r, 0, 6.28);
    context.fill();
  }
};

var ctx = c.getContext("2d");
var cc = new CircleCascade(ctx);
cc.generate(50);
cc.drawCircles();
<canvas id=c width=600 height=400></canvas>

答案 1 :(得分:0)

将函数绑定到self

您可以将函数绑定到自己的引用,然后直接从setTimeout函数调用它。

首先在Circle构造函数中绑定draw函数。

function Circle(settings){
    Object.assign(this,settings);
    this.draw = Circle.prototype.draw.bind(this);
}

正常构建原型

Circle.prototype = {
    draw(){
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
        ctx.stroke();
    }
}

然后以间隔绘制圆圈,您可以将绑定绘制函数直接传递给setTimeout函数。

const circleInterval = 100;
function drawCircles(){
    circles.forEach((circle, i) => setTimeout(circle.draw, (i + 1) * circleInterval));
}

实施例

&#13;
&#13;
//==========================================================
// helper functions randI for random integer and setOf creates an array
const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
const setOf = (count, cb = (i)=>i) => {var a = [],i = 0; while (i < count) { a.push(cb(i ++)) } return a };
//==========================================================
// get canvas an set example constants
const w = canvas.width = innerWidth;
const h = canvas.height = innerHeight;
const ctx = canvas.getContext("2d");
const circleCount = 1500;
const circleInterval = 100;
//==========================================================
function Circle(settings) {
  Object.assign(this, settings);
  this.draw = Circle.prototype.draw.bind(this);
}
Circle.prototype = {
  draw() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
    ctx.stroke();
  }
}
//==========================================================
// create circle array
const circles = setOf(circleCount, () => new Circle({ x: randI(w), y: randI(h), r: randI(20, 100)}));

//==========================================================
// draw the circles at intervals
function drawCircles() {
  circles.forEach((circle, i) => setTimeout(circle.draw, (i + 1) * circleInterval));
}
drawCircles()
&#13;
canvas {
  position: absolute;
  top: 0px;
  left: 0px;
}
&#13;
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;

相关问题