2012-11-04 175 views
2

我試圖將全屏背景圖像加載到畫布上,然後將圖像過濾器應用到它,但有幾個問題。我遇到嚴重的性能問題,但只有在調整窗口大小時纔會發生。基本上,我的代碼試圖保持畫布/圖像匹配屏幕尺寸(效果很好)。HTML5畫布圖像過濾器延遲(JavaScript)

UPDATE帆布方法:

的updateCanvas方法稱爲負載到最初創建/加載圖像對象,並將其放置在畫布上。如果選擇了過濾器,則會調用過濾器方法。它接受onResize參數,該參數通過窗口大小調整來縮放畫布/圖像。 MAIN是指用於引用元素的對象。

updateCanvas:function(onResize){ 
     // SETUP VARIABLES 
    var img=new Image(), 
      $this=Main.currentOBJ, // REFERENCE FOR .DATA 
      objData=$this.data, 
      canvas=Main.OBJ.$Canvas[0], 
     ctx=canvas.getContext("2d"), 
      winW=$(window).width(), winH=$(window).height(); 

    // SOURCE CAN BE SET IN .DATA OR DEFAULT 
    img.src=(objData.bg_pic_src!=='') ? objData.bg_pic_src : Main.ConSRC; 

    // LOAD THE IMAGE OBJECT 
    img.onload=function(){ 
     var imgW=img.width, imgH=img.height, 
      ratio=imgW/imgH, newW=winW, newH=Math.round(newW/ratio); 

     // SETUP IMAGE PROPORTIONS 
     if(newH < winH){ var newH=winH, newW=Math.round(newH*ratio); }; 

     // WHEN RESIZING THE BROWSER 
     if(!onResize){ // INTIAL DRAW 
      Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'}); 
      ctx.drawImage(img,0,0,newW,newH); 

      // APPLY FILTERS 
     if(objData.bg_pic_filter > 0){ 
      Main.canvasFilter(ctx,newW,newH); // FILTER METHOD 
     }else{ 
      Main.OBJ.$OverlayPic.animate({opacity:parseFloat(objData.bg_pic_opacity,10)}, 
     {duration:objData.bg_pic_speed_in,queue:false}); 
      }; 
    }else{ // RESIZING 
     Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'}); 
     ctx.drawImage(img,0,0,newW,newH); 

     if(objData.bg_pic_filter > 0){ 
      Main.canvasFilter(ctx,newW,newH); // FILTER METHOD 
     };  
    }; 
}; 

畫布篩選方法: 如果圖像濾波程序待應用於背景圖像,所述方法canvasFilter從canvasUpdate方法調用。

canvasFilter:function(ctx,width,height){ 
     // SETUP VARIABLES 
     var objData=Main.currentOBJ.data, 
     canvasWidth=width, canvasHeight=height, 
     imgdata=ctx.getImageData(0, 0, canvasWidth, canvasHeight), 
     pix=imgdata.data, l=pix.length; 

    // APPLY THE CORRECT LOOP DEPENDING UPON THE FILTER NUMBER 
    switch(objData.bg_pic_filter){ 
    case 1: ... break; 
    case 2: 
     for(var i=l; i>0; i-=4){ 
      var cacher=pix[i+2]; 
      pix[i]=pix[i+1]; 
      pix[i+1]=cacher; 
      pix[i+2]=cacher; 
      pix[i+3]=cacher; 
     }; 
    break; 
    };   

    // APPLY THE FILER & FADE IN THE BACKGROUND 
    ctx.putImageData(imgdata, 0, 0); 
    Main.OBJ.$OverlayPic.fadeTo(parseInt(objData.bg_pic_speed_in,10),  
     parseFloat(objData.bg_pic_opacity,10)); 
}; 

所有這些工作,並且初始繪製/過濾器相當快。但是,當我調整窗口大小時,它非常緩慢。我暫時通過加入一個節流器來解決這個問題,它只是設置一個計時器來避免上述功能太快。這稍微有所幫助,但會保留背景圖像(顯示圖像周圍的開放固體背景區域),直到調節器計時器啓動並觸發方法 - 調整畫布/圖像大小並應用過濾器。

問題:

  1. 有一個更快的方法?我已經閱讀過使用Typed Arrays/Bitwise進行像素操作循環的問題,但似乎支持對此很可怕。我也研究過CSS3過濾器來完成同樣的事情,但是再一次,支持是非常可怕的。那麼,這是否將成爲全屏幕背景圖像過濾器與「現代瀏覽器」兼容性的唯一方法?

  2. updateCanvas方法每次創建一個新的圖像對象,我想這可能是一個瓶頸,但我不確定,也不確定如何解決它?

  3. 我讀過其他人使用單獨的畫布作爲緩衝區?這實際上會提高我的表現嗎?

  4. 我真的認爲在我的代碼中有一個主要的邏輯問題。對我來說,我需要不止一次地遍歷所有的像素信息,但這是我獲得它的唯一方法。是不是有一種方法可以繪製/應用過濾器一次,然後調整大小,只需調整尺寸而無需重新繪製/重新放置/重新應用過濾器?我認爲它會保持過濾後的圖像,但如果我在窗口大小調整中刪除了對canvasFilter方法的調用,它將完全刪除過濾器效果。

  5. 我還沒有使用memoization技術,因爲我從來沒有完全理解它,並從來不明白何時何地使用它。但是,從本質上講,如果我有一個一次又一次返回相同結果的函數(例如canvasFilter方法),我可以記憶以提高性能 - 或者它會有所不同,因爲它在窗口調整大小後拉動不同的像素信息?

  6. 我也聽說webGL渲染可能有幫助嗎?因爲我對webGL一無所知,可能會走開。

所以對於這個loooonng問題感到抱歉,但希望這涵蓋了其他人可以從中受益的一些主題。任何建議/提示將不勝感激。謝謝! :)

+0

我是否正確理解加載時的所有行爲,只是調整窗口大小就是問題所在?如果是,爲什麼你重畫畫布而不是用canvas.style.width =「1234px」調整大小?如果不是這樣,一個在線版本將有助於理解,因爲您似乎期望上面沒有描述的獨特效果。 – noiv

+0

對於其他畫布繪製循環,您可能還需要閱讀有關window.requestAnimationFrame的內容。基本上,瀏覽器會讓你知道什麼時候可以工作,而不是等待任意時間。參見:http://paulirish.com/2011/requestanimationframe-for-smart-animating/ –

回答

1

因爲它聽起來像你的圖像大多是靜態的,你可能想嘗試的方法是使用良好的舊CSS。

這裏的關鍵技巧是使用background-size:cover。請參閱:http://css-tricks.com/perfect-full-page-background-image/

所以從廣義上講:

  1. 載入圖片
  2. 應用您的過濾器中的畫布。 (畫布甚至不需要連接到頁面)。
  3. 出口畫布數據通過URL:ctx.toDataUrl("image/png");
  4. 添加樣式到您的容器元素或身體: background-size:cover;background:url('data:image/png;yourcanvasdata');
  5. 通過JS或CSS的過渡性質
  6. 動畫的容器元素/體的透明度
+0

不錯!這聽起來很棒,我仍然對使用Canvas操作非常陌生,並且不知道.toDataUrl。聽起來很完美 :) – Aaron