使用canvas创建和使用类

时间:2015-09-25 23:59:26

标签: javascript

我遇到了一些麻烦,因为Javascript对于类来说似乎很糟糕,而且实现很有趣。我试图让这个块工作,所以我可以创建多个三角形:

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
var phase = 0;
var tau = 2 * Math.PI;

function animate() {
    requestAnimationFrame(animate);
    var sides = 3;
    var size = 100;
    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;
    phase += 0.005 * tau;

    context.clearRect(0, 0, canvas.width, canvas.height);
    context.beginPath();
    for (var i = 0; i <= sides; i++) {
        context[i ? 'lineTo' : 'moveTo'](
            centerX + size * Math.cos(phase + i / sides * tau),
            centerY + size * Math.sin(phase + i / sides * tau)
        );
    }
    context.stroke();
}

animate(); 

在这里,我尝试将它变成一个类:

var canvas = document.querySelector('canvas');
        var context = canvas.getContext('2d');
        var phase = 0;
        var tau = 2 * Math.PI;

        function Triangle(cntx, canvs) {
            this.ctx = cntx;
            this.canv = canvs;
            this.draw = drawTriangle;
        }
        function drawTriangle() {
            requestAnimationFrame(drawTriangle);
            var sides = 3;
            var size = 100;
            var centerX = this.canv.width / 2;
            var centerY = this.canv.height / 2;
            phase += 0.005 * tau;

            this.ctx.clearRect(0, 0, this.canv.width, this.canv.height);
            this.ctx.beginPath();
            for (var i = 0; i <= sides; i++) {
                this.ctx[i ? 'lineTo' : 'moveTo'](
                    centerX + size * Math.cos(phase + i / sides * tau),
                    centerY + size * Math.sin(phase + i / sides * tau)
                );
            }
            this.ctx.stroke();
        }

        var triangle1 = new Triangle(context,canvas);
        triangle1.draw();

问题是它只绘制了三角形,所以我不确定我在这里做错了什么。

2 个答案:

答案 0 :(得分:1)

这里的问题是您正在调用requestAnimationFrame并将回调传递给同一个函数,但this关键字将引用window对象,而不是您的类了。

因此,您必须明确表示要将回调函数的上下文设置为相同的上下文,并且可以通过调用.bind(this)来实现。看一下下面的例子:

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
var phase = 0;
var tau = 2 * Math.PI;

function Triangle(cntx, canvs) {
  this.ctx = cntx;
  this.canv = canvs;
  this.draw = drawTriangle;
}

function drawTriangle() {
  requestAnimationFrame(drawTriangle.bind(this));
  var sides = 3;
  var size = 100;
  var centerX = this.canv.width / 2;
  var centerY = this.canv.height / 2;
  phase += 0.005 * tau;

  this.ctx.clearRect(0, 0, this.canv.width, this.canv.height);
  this.ctx.beginPath();
  for (var i = 0; i <= sides; i++) {
    this.ctx[i ? 'lineTo' : 'moveTo'](
      centerX + size * Math.cos(phase + i / sides * tau),
      centerY + size * Math.sin(phase + i / sides * tau)
    );
  }
  this.ctx.stroke();
}

var triangle1 = new Triangle(context, canvas);
triangle1.draw();
<canvas></canvas>

答案 1 :(得分:0)

您可以通过两种方式将其作为javascript对象(不要将它们视为类)。

首先使用prototype来定义对象方法。

function Triangle(cntx, canvs) {  // define the triange
    this.ctx = cntx;
    this.canv = canvs;
    this.draw = this.drawTriangle.bind(this);
}
// this creates and compiles the draw function ready to be used for any Triangle object you create.
Triangle.prototype.drawTriangle = function() {  // define the draw method as part of
                                        // triangle's prototype
    requestAnimationFrame(this.draw);   // all properties of Triangle.prototype can be referenced via 'this'
    var sides = 3;
    var size = 100;
    var centerX = this.canv.width / 2;
    var centerY = this.canv.height / 2;
    phase += 0.005 * tau;

    this.ctx.clearRect(0, 0, this.canv.width, this.canv.height);
    this.ctx.beginPath();
    for (var i = 0; i <= sides; i++) {
        this.ctx[i ? 'lineTo' : 'moveTo'](
            centerX + size * Math.cos(phase + i / sides * tau),
            centerY + size * Math.sin(phase + i / sides * tau));
    }
    this.ctx.stroke();
}

var triangle1 = new Triangle(context, canvas);
triangle1.draw();

或者您可以使用以下内容创建更安全的三角形。在这种情况下,我们通过使用闭包来封装我们想要的变量ctxcanv不再公开并且只能从三角形对象调用中访问,从而最小化此标记的使用。使用闭合在运行时会快一些,在创建时会慢一些。

function Triangle(cntx, canvs) {
    var ctx = cntx;   // create closure vars
    var canv = canvs;
    this.draw = (function() { // draw run faster because it does not have
                             // to search the prototype for the values
                             // of ctx and canv.
        requestAnimationFrame(this.draw);
        var sides = 3;
        var size = 100;
        var centerX = this.canv.width / 2;
        var centerY = this.canv.height / 2;
        phase += 0.005 * tau;

        ctx.clearRect(0, 0, canv.width, canv.height); // dont need the this keyword
        ctx.beginPath();
        for (var i = 0; i <= sides; i++) {
            ctx[i ? 'lineTo' : 'moveTo'](
                centerX + size * Math.cos(phase + i / sides * tau),
                centerY + size * Math.sin(phase + i / sides * tau));
        }
        ctx.stroke();
    }).bind(this); // because requestAnimationFrame sets this wee need to bind the current this to the method.
}
var triangle1 = new Triangle(context, canvas);  // It takes a little longer to invoke
                                                // because it will need to create and compile
                                                // the draw function.

triangle1.draw();  // but call this now runs a little faster.

在这种情况下速度的差异非常小,一个优于另一个的优势将取决于您创建新对象的频率以及调用其方法的频率。如果您经常创建,请使用prototype,如果您创建一次并经常使用,请使用闭包。

相关问题