2015-09-25 90 views
2

我對此有些麻煩,因爲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(); 

的問題是,它只是繪製三角形曾經如此我不確定我在這裏做錯了什麼。

回答

1

這裏的問題在於,您打電話給​​並將回調傳遞給相同的功能,但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>

+0

他們也可以在'Triangle'中定義'draw()'。 –

+0

啊謝謝你指出。 – samuelk71

0

你有兩種方法可以做到這一點作爲一個JavaScript對象(不認爲他們是類)。

第一種使用原型來定義對象方法的方法。

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;如果創建一次並經常使用,則使用閉包。

+0

這兩個示例都不起作用,因爲requestAnimationFrame更改上下文的問題仍然存在。 – Buzinas

+0

哦,是的,...會解決的。 – Blindman67

+0

現在通過將draw函數綁定到Triangle的'this' – Blindman67