2016-11-28 32 views
0

これは私にとってはうまくいくものではありません。drawImage()でキャンバスに複数のイメージを描画する問題

私はdrawImage()を使用して複数の画像をキャンバスに描画しようとしています。私は何かを少し見落としているような気がする。

キャンバスに18枚のカードを描画する必要があります。左から50px、上から下に向かい、各カードを100w * 150hで描きます。各カードの画像の間に25ピクセルが必要です。キャンバスの寸法は825w * 600hに設定されています。

普通のJavascript(jQueryなし)でこれを達成しようとしています。どんな助けもありがとうございます。

イメージは現在キャンバスに描画されています。 How it is outputting to the canvas currently.

// Draw the cards to the canvas. 
function drawCards() 
{ 
    // Starting positions. 
    var x = 50; 
    var y = 50; 

    // Counter that will hold current card position. 
    var cardCount = 0; 

    var img = new Image(100, 150); 

    // How many rows. 
    for (var row = 0; row < 3; row++) 
    { 
     // How many columns. 
     for (var column = 0; column < 6; column++) 
     { 
      // Store the current card. 
      var card = memoryDeck[cardCount]; 

      // Check if the card is flipped, if it is set an image with url to face card. 
      if (card.flipped == true) 
      { 
       img.onload = function() { 
        ctx.drawImage(this, x, y, 100, 150); 
       } 
       img.src = card.faceImage; 
      } 
      // Otherwise set image url to back of card. 
      else 
      { 
       img.onload = function() { 
        ctx.drawImage(this, x, y, 100, 150); 
       } 
       img.src = card.backImage;   
      } 

      // Increase the x position (the width of a card, plus the space in between), and the current card position being stored. 
      x += 125; 
      cardCount++; 
     } 

     // We are on a new row, reset the column card position and increase the row card position. 
     x = 50; 
     y += 175; 
    } 
} 

答えて

0

JS変数をブロックするようにスコープされていない、彼らは機能するようにスコープされています。したがって、img.onloadがxyにアクセスするとき、それらはxとyの最終値を参照します。 ブロックスコープ変数を作成するには、let文またはIIFEを使用します。

// Draw the cards to the canvas. 
function drawCards() 
{ 
    // Starting positions. 
    var x = 50; 
    var y = 50; 

    // Counter that will hold current card position. 
    var cardCount = 0; 

    var img = new Image(100, 150); 

    // How many rows. 
    for (var row = 0; row < 3; row++) 
    { 
     // How many columns. 
     for (var column = 0; column < 6; column++) 
     { 
      // Store the current card. 
      var card = memoryDeck[cardCount]; 

      // Check if the card is flipped, if it is set an image with url to face card. 
      if (card.flipped == true) 
      { 
       (function(x, y) { 
       img.onload = function() { 
        ctx.drawImage(this, x, y, 100, 150); 
       } 
       img.src = card.faceImage; 
       })(x, y); 
      } 
      // Otherwise set image url to back of card. 
      else 
      { 
       (function(x, y) { 
       img.onload = function() { 
        ctx.drawImage(this, x, y, 100, 150); 
       } 
       img.src = card.backImage; 
       })(x, y);   
      } 

      // Increase the x position (the width of a card, plus the space in between), and the current card position being stored. 
      x += 125; 
      cardCount++; 
    } 

     // We are on a new row, reset the column card position and increase the row card position. 
     x = 50; 
     y += 175; 
    } 

} 

同様の単純な問題は、このている:それはループ内の関数呼び出しを宣言するように指定された答えは問題がある

READ THE SOURCE CODE! 
 
<script> 
 
    function demo1() { 
 
    for (var i = 0; i <= 5; i++) { 
 
    setTimeout(function(){alert('i === ' + i)}, i * 200); 
 
    } 
 
    // i === 6 
 
    
 
    
 
    // You expect this to happen: 
 
    // [alerts "i === 1"] 
 
    // [alerts "i === 2"] 
 
    // [alerts "i === 3"] 
 
    // [alerts "i === 4"] 
 
    // [alerts "i === 5"] 
 
    
 
    // What actually happens: 
 
    // [alerts "i === 6"] 
 
    // [alerts "i === 6"] 
 
    // [alerts "i === 6"] 
 
    // [alerts "i === 6"] 
 
    // [alerts "i === 6"] 
 
    // [alerts "i === 6"] 
 
    } 
 
</script> 
 
<button onclick="demo1();">Demo 1 </button> 
 
<script> 
 
    function demo2(){ 
 
    for (var i = 0; i <= 5; i++) { 
 
     // IIFE for the win! 
 
     (function(i) { 
 
     setTimeout(function(){alert('i === ' + i)}, i * 200); 
 
     })(i); 
 
    } 
 
    
 
    // Expected: 
 
    // [alerts "i === 0"] 
 
    // [alerts "i === 1"] 
 
    // [alerts "i === 2"] 
 
    // [alerts "i === 3"] 
 
    // [alerts "i === 4"] 
 
    // [alerts "i === 5"] 
 
    
 
    // Actual: 
 
    // [alerts "i === 0"] 
 
    // [alerts "i === 1"] 
 
    // [alerts "i === 2"] 
 
    // [alerts "i === 3"] 
 
    // [alerts "i === 4"] 
 
    // [alerts "i === 5"] 
 
    } 
 
</script> 
 
<button onclick="demo2();">Demo 2</button>

+0

これは私の問題の半分を解決しました。ありがとう!私はまだ最後のイメージを描くのはなぜなのか、まだ分かりません。:/ –

+0

これを完全には適用しなかったようです。これを使用してわずかな調整を行い、全体を修正することができました。どうもありがとうございます! –

0

。宣言のこのパターンは危険であり、閉包を理解していないとメモリリークにつながる可能性があります。スコープの問題を克服するために使用される方法もまた非常に非効率的である。そして、コードは1つのイメージしか作成されていないので動作せず、srcが設定されるたびに以前のロードsrcが取り消され、プロセスが再び開始されます。

また、匿名関数を作成すると、エラーをトレースするのが困難になり、プロファイリングも読みにくくなるため、コードをデバッグするのが難しくなります。常に関数に名前を付け、関数を常にスコープの上部に配置します。

function drawCards(){ 
    // declare all variables and functions 
    var row, column, src, cardIndex, card; 
    function loadThenDisplayImage (src, x, y) { 
     var image; 
     function onImageload() { 
      ctx.drawImage(this, x, y, cardW, cardH); 
     } 
     image = new Image(cardW, cardH); 
     image.src = src; 
     image.onload = onImageLoad; 
    } 
    // define constants and variables. 
    const left = 50; 
    const top = 50; 
    const cardW = 100; 
    const cardH = 150; 
    const xSpacing = 25; 
    const ySpacing = 25; 
    cardIndex= 0; 

    // function logic 
    for (row = 0; row < 3; row += 1) { 
     for (column = 0; column < 6; column += 1) { 
      card = memoryDeck[cardIndex += 1]; 
      scr = card.flipped ? card.faceImage : card.backImage; 
      loadThenDisplayImage( // long function call best split for readbility 
       src, 
       left + (cardW + xSpacing) * column, 
       top + (cardH + ySpacing) * row 
      ); 
     } 
    } 
} 
関連する問題