2010-05-09 2 views
4

을 설정할 수 없습니다. 각 모자이크 이미지를 다운로드 한 후에 .Done 속성을 true로 설정하려고하는데 어떤 이유로 든 항상 거짓입니다. 내가 뭘 잘못하고 있니? 자바 스크립트 - 이미지로드 함수에서 객체에 Settting 속성, 속성은 때로는 자바 스크립트, 나에게 의미가 X/Y 타일 기반의 사진 모자이크를 생성하는 다음 코드를 고려하지 않습니다 일단 외부 기능

var tileData = []; 

function generate() 
{ 
    var image = new Image(); 
    image.onload = function() 
    { 
     // Build up the 'tileData' array with tile objects from this Image 

     for (var i = 0; i < tileData.length; i++) 
     { 
      var tile = tileData[i]; 

      var tileImage = new Image(); 
      tileImage.onload = function() 
      { 
       // Do something with this tile Image 
       tile.Done = true; 
      }; 
      tileImage.src = tile.ImageUrl; 
     } 
    }; 
    image.src = 'Penguins.jpg'; 

    tryDisplayMosaic(); 
} 

function tryDisplayMosaic() 
{ 
    setTimeout(function() 
    { 
     for (var i = 0; i < tileData.length; i++) 
     { 
      var tile = tileData[i]; 

      if (!tile.Done) 
      { 
       tryDisplayMosaic(); 
       return; 
      } 
     } 

     // If we get here then all the tiles have been downloaded 
     alert('All images downloaded'); 
    }, 2000); 
} 

지금 어떤 이유로 tile 개체에 .Done 속성은 명시 적으로 tileImage.onload = function() 내부 true로 설정되는 경우에도, 항상 false입니다. 그리고 그 안에 alert() 호출을 배치 했으므로이 함수가 호출되는지 확인할 수 있습니다. 지금은 그냥 무한 루프 안에 붙어있어서 tryDisplayMosaic()을 끊임없이 호출합니다.

또한 나는 tryDisplayMosaic()가 호출되기 직전에 루프를 배치하고 그 루프에서 나는 그 .Done 속성이 true이고 alert('All images downloaded');가 호출되는 것, .Done = true을 설정합니다.

+0

코드에서와 같이'tileData'가 비어 있으면 for-loops가 실행되지 않기 때문에 올바르게 작동 할 것이라고 확신합니다. 하지만 비어 있지 않은 경우 루프 내에서 함수를 정의하면 작동하지 않습니다. 'tileData'가 정확히 무엇인지 말할 수 있습니까? – Harmen

답변

2

최상위 루프의 변수 "tile"은 사용자가 생성 한 "onload"함수 모두가 공유합니다. 즉, 매우 동일한 단일 변수입니다. 각 변수마다 고유 한 변수를 제공하십시오.

tileImage.onload = (function(myTile) { 
    return function() 
     { 
      // Do something with this tile Image 
      myTile.Done = true; 
     }; 
})(tile); 

왜 이렇게할까요? C 또는 Java와 달리 루프 내에서 "tile"을 선언하면 이 아닌이 루프 본문의 명령문 블록으로 범위가 지정됩니다. Javascript에서 범위를 제공하는 유일한 것은 함수 본문입니다. 내가 볼 무엇

+0

완벽하게 작동했습니다. 감사합니다! 그 구문이 나에게는 꽤 이상 하긴하지만 JavaScript를 좀 배워야합니다. –

+1

사용해보기 : http://ejohn.org/apps/learn/ :] – Harmen

2

a common mistake있는 루프, 내부에 폐쇄를 만드는 것입니다. 이 문제를 방지하려면 모든로드 이벤트를 처리하고 모든 이미지가로드 된 후 함수 실행 루프 외부의 일반적인 폐쇄, 만들 수 있습니다

// This array must be filled somewhere... 
var tileData = []; 

var ImageLoader = function(){ 
    var numOfImages = 0; 
    var numLoaded = 0; 
    var callBack = function(){}; 

    function imageLoaded(){ 
     numLoaded++; 
     if(numLoaded===numOfImages){ 
      // All images are loaded, now call the callback function 
      callBack.call(this); 
     } 
    } 

    function init(numberOfImages, fn){ 
     numOfImages = numberOfImages; 
     callBack = fn; 
    } 

    return { 
     imageLoaded: imageLoaded, 
     init: init 
    }; 
}(); 

function tryDisplayMosaic(){ 
    alert('All images downloaded'); 
} 

function generate(){ 
    // (1) Set the number of images that are to be loaded and (all tiles + penguin) 
    // (2) Set the function that must be called after all images are loaded 
    ImageLoader.init(tileData.length+1, tryDisplayMosaic); 

    // Load this Penguins image 
    var image = new Image(); 
    image.src = 'Penguins.jpg'; 
    image.onload = ImageLoader.imageLoaded; 

    // Go through each image and load it 
    for (var i=0; i<tileData.length; i++) { 
     image = new Image(); 
     image.src = tileData[i].ImageUrl; 
     image.onload = ImageLoader.imageLoaded; 
    } 
} 

이 코드는 코드는 완전히 다른,하지만 그건 내 생각에 훨씬 더 예쁘다. 로드해야하는 이미지의 수와 모든 이미지가로드 된 후에 실행해야하는 기능을 설정해야합니다.

참고 : 테스트를 거치지 않았으므로이 부분은 .call(this) 부분에 대해 확실하지 않습니다. 잘못된 부분이 있으면 포럼에서 도움을받을 수 있습니다.

나는 내 코드를 테스트했으며 정상적으로 작동합니다. 또한 개선 했으므로 tileData 배열 안에로드 된 이미지에 대한 포인터를 저장합니다 (작동 예제는 JSBin 참조).