精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

看HTML 5如何創建一個圖片瀏覽器

開發 前端
通過如何用 Canvas 來制作一個圖片瀏覽器的具體實例,來說明 Canvas 的各種 API,如何使用這些 API 以及如何應用到工程中去。

HTML Canvas 介紹

HTML5 是目前正在討論的新一代 HTML 標準,它代表了現在 Web 領域的最新的發展方向。在 HTML5 標準中,加入了新的多樣的內容描述標簽,直接支持表單驗證,視頻和音頻標簽,網頁元素的拖拽,離線存儲,工作線程等等。當然,其中一個最令人激動的新特性就是新的標簽類型 Canvas,開發人員可以通過該標簽,在網頁上直接用腳本進行繪圖,產生各種 2D 渲染的效果。所以有人預言,HTML5 將是 Flash 和 Silverlight 的“殺手”。從 Firefox 1.5 開始就已經支持 Canvas,Safari 也是很早就開始支持 Canvas。新的瀏覽器比如 Chrome 也是從一開始就支持。但遺憾的是,到目前為止,IE 一直不支持該標準。

下面內容將通過如何用 Canvas 來制作一個圖片瀏覽器的具體實例,來說明 Canvas 的各種 API,如何使用這些 API 以及如何應用到工程中去。本文將首先介紹如何創建圖片瀏覽器的網頁和 JavaScript 類,介紹整體界面的設計,然后介紹如何用 Canvas 的 API 來繪制 2D 圖形,然后介紹如何在 Canvas 上加載和繪制圖像,接下來本例會在圖片瀏覽器中加入其他基于 Canvas 的效果,最后是總結和展望。

創建圖片瀏覽器框架

創建文件

首先我們創建一個新的 html 文件 thumbnail.html,加入如清單 1 所示的內容:


清單 1.thumbnail.html

  1. <!DOCTYPE HTML>   
  2.  <html>   
  3.  <head>   
  4.   <title>Canvas Based Thumbnail</title>   
  5.   <style type="text/css">   
  6.     body {   
  7.     background: black;   
  8.     color: white;   
  9.    font: 24pt Baskerville, Times, Times New Roman, serif;   
  10.     padding: 0;   
  11.     margin: 0;   
  12.     overflow: hidden;   
  13.     }   
  14.   </style>   
  15.   <script type="text/javascript" src="thumbnail.js"></script>   
  16.  </head>   
  17.  <body>   
  18.   <canvas id="canvas"></canvas>   
  19.  </body>   
  20.  </html>   

這里我們可以看到,canvas 是 html 的一個新的標簽,其用法和其他標簽一樣,只不過它的高和寬有獨立的屬性而不是在 css 定義的。如果我們要設置一個 Canvas 區域的寬高,必須定義為 <canvas width="100" height="100"> 而不能是 <canvas style="width:100,height:100">。在上面的 html 文件中我們沒有直接定義 Canvas 區域的大小,而是在 JavaScript 中動態定義,下面將要詳細說明。

現在我們創建一個新的 JavaScript 文件 thumbnail.js 來在 Canvas 中繪制圖像,我們設計一個 thumbnail 類,該類可以處理用戶事件,繪制圖形,顯示圖像。然后在 window.onload 事件中加載該類,代碼如清單 2 所示:

清單 2 .thumbnail.js

  1. function thumbnail() {   
  2.     this.load = function()   
  3.     }   
  4.  }   
  5.  
  6.  window.onload = function() {   
  7.     thumb = new thumbnail();   
  8.     thumb.load();   
  9.  }   

代碼定義了一個初始化函數 load,并且聲明了 thumbnail 類,這樣我們就可以在 thumbnail 類中添加代碼,在 Canvas 上繪制各種圖形以及圖像了。

設計界面

我們為這個圖片瀏覽頁面設計這樣一種界面,圖片通過縮放占滿全部網頁空間,在中間下方,繪制一個導航欄,顯示縮略圖,當點擊縮略圖時,該圖片顯示到網頁中。同時,如果鼠標懸停在某個縮放圖上,則顯示一個大一點的預覽圖用來供用戶預覽。在導航欄的左右兩邊,添加 2 個按鈕,用于翻頁顯示上一頁和下一頁的縮略圖。對導航欄上所有控件的尺寸大小和位置如圖所示的方案。這樣,我們就可以按照該方案在 Canvas 上繪制這些控件了。

界面設計
圖 1 界面設計 

 

用 Canvas 繪制圖形

繪制導航框

首先我們繪制如圖所示的一個導航欄。在左右兩邊各有一個按鈕,按鈕上顯示一個三角形的指示圖形。當鼠標放到一個按鈕上時,按鈕的背景色能變成高亮的顏色,顯示當前選中的按鈕。

導航框
圖 2 導航框 

清單 3 顯示了繪制圖 2 所示的導航欄的代碼片段。

清單 3 . 繪制導航框代碼

  1.               
  2. function thumbnail() {   
  3.    const NAVPANEL_COLOR = 'rgba(100, 100, 100, 0.2)';    // 導航欄背景色  
  4.    const NAVBUTTON_BACKGROUND = 'rgb(40, 40, 40)';  // 導航欄中 button 的背景色  
  5.    const NAVBUTTON_COLOR = 'rgb(255, 255, 255)';   //button 的前景色  
  6.    const NAVBUTTON_HL_COLOR = 'rgb(100, 100, 100)';   //button 高亮時的前景色  
  7.  
  8.    var canvas = document.getElementById('canvas');   // 獲得 canvas 對象  
  9.    var context = canvas.getContext('2d');    // 獲得上下文對象  
  10.  
  11.    // 繪制左邊 button   
  12.    function paintLeftButton(navRect, color) {   
  13.        //left button   
  14.        lButtonRect = {   
  15.            x: navRect.x + NAVBUTTON_XOFFSET,   
  16.            y: navRect.y + NAVBUTTON_YOFFSET,   
  17.            width: NAVBUTTON_WIDTH,   
  18.            height: navRect.height - NAVBUTTON_YOFFSET * 2   
  19.        }   
  20.  
  21.        context.save();   
  22.        context.fillStyle = color;   
  23.        context.fillRect(lButtonRect.x, lButtonRect.y,   
  24. lButtonRect.width, lButtonRect.height);   
  25.  
  26.        //left arrow   
  27.        context.save();   
  28.        context.fillStyle = NAVBUTTON_COLOR;   
  29.        context.beginPath();   
  30.        context.moveTo(lButtonRect.x + NAVBUTTON_ARROW_XOFFSET,   
  31. lButtonRect.y + lButtonRect.height/2);   
  32.        context.lineTo(lButtonRect.x + lButtonRect.width - NAVBUTTON_ARROW_XOFFSET,   
  33. lButtonRect.y + NAVBUTTON_ARROW_YOFFSET);   
  34.        context.lineTo(lButtonRect.x + lButtonRect.width - NAVBUTTON_ARROW_XOFFSET,   
  35. lButtonRect.y + lButtonRect.height - NAVBUTTON_ARROW_YOFFSET);   
  36.        context.lineTo(lButtonRect.x + NAVBUTTON_ARROW_XOFFSET,   
  37. lButtonRect.y + lButtonRect.height/2);   
  38.        context.closePath();   
  39.        context.fill();   
  40.        context.restore();   
  41.  
  42.        context.restore();   
  43.    }   

如上所述,在頁面 html 中我們聲明了 <canvas> 元素。當需要在 <canvas> 區域繪制圖形時,我們需要獲得繪制圖形的上下文對象,在一個上下文對象中,保存了當前的初始坐標位置,顏色,風格等等信息。這里我們通過如清單 4 的語句獲取 Canvas 的 2 維繪圖的上下文對象。

清單 4. 獲得繪圖上下文

  1. var canvas = document.getElementById('canvas');   
  2. var context = canvas.getContext('2d');   

獲得上下文對象之后,我們就可以通過 Canvas 提供的 API 來進行繪畫了。在清單 5 中,我們使用了矩形的繪制函數來繪制整個導航欄背景和左右兩個按鈕。所下所示:

清單 5. 矩形繪制函數

  1. fillRect(x,y,width,height): 繪制一個填充的矩形  
  2. strokeRect(x,y,width,height): 給一個矩形描邊  
  3. clearRect(x,y,width,height): 清除該矩形內所有內容使之透明  

例如,我們要繪制一個簡單的矩形可以用如清單 6 所示代碼:

清單 6. 繪制簡單矩形

  1. var canvas = document.getElementById('canvas');   
  2. var context = canvas.getContext('2d');   
  3. context.fillStyle = 'black';   
  4. context.fillRect(0, 0, 50, 50);   
  5. context.clearRect(0, 0, 20, 20);   
  6. context.strokeRect(0, 0, 20, 20);   

我們繪制該導航框時,需要在左右兩邊各繪制一個三角形,對于除了矩形以外的所有多邊形,必須得通過路徑來繪制,常用的路徑相關函數有 :

清單 7. 繪制路徑函數

  1. beginPath(): 開始一段路徑   
  2. closePath(): 結束一段路徑  
  3. moveTo(x,y)  : 移動起始點到某點  
  4. lineTo(x,y) : 繪制線段到目標點  

這樣,我們在繪制三角形的時候,只需要確定三個頂點的坐標,就可以通過 lineTo 函數繪制三條線段,但是,我們還需要一個函數在該三角形區域內填充顏色,這樣需要用到填充和描邊的函數和樣式:

清單 8. 填充和描邊樣式

  1. fillStyle = color : 設置填充顏色  
  2. storkeStyle = color : 設置描變顏色  

這里 color 值可以是標準的 CSS 顏色值,還可以通過 rgba 函數設置透明度。我們可以如下設置:

清單 9. 填充樣式舉例

  1. context.fillStyle = "white";   
  2. context.strokeStyle = "#FFA500";   
  3. context.fillStyle = "rgb(255,165,0)";   
  4. context.fillStyle = "rgba(255,165,0,1)";   

同樣,當需要填充顏色樣式或者描邊時,有如下函數:

清單 10. 填充和描邊函數

  1. stroke() : 按照當前描邊樣式描邊當前路徑  
  2. fill() : 按照當前填充樣式填充路徑所描述的形狀  

這樣,用上述幾個函數,我們繪制一個三角形時,可以用如下語句:

清單 11. 繪制三角形代碼

  1. var canvas = document.getElementById('canvas');   
  2. var context = canvas.getContext('2d');   
  3. context.fillStyle = 'black';   
  4. context.beginPath();   
  5. context.moveTo(0,0);   
  6. context.lineTo(10,0);   
  7. context.lineTo(10,10);   
  8. context.lineTo(0,0);   
  9. context.closePath();   
  10. context.fill();   

在清單 3 中,我們還聲明了一些常量來定義導航欄的各種控件的大小,其中長度值都是以像素為單位的。這樣我們繪制了整個導航欄,但我們現在需要當鼠標放到按鈕上時,按鈕的前景色能夠高亮,顯示當前選中的按鈕。這就需要我們在代碼中響應用戶事件,并進行不同類型的繪制。

響應用戶事件

響應用戶事件和普通的 DOM 編程類似,如清單 12 所示:

清單 12. 響應鼠標移動時間

  1. var lastMousePos;    // 當前鼠標位置  
  2. this.load = function() {   
  3.     //event binding   
  4.     canvas.onmousemove = onMouseMove;   
  5. }   
  6. function onMouseMove(event) {   
  7.     lastMousePos = {x:event.clientX, y:event.clientY};   
  8.     paint();   
  9. }   
  10. function pointIsInRect(point, rect) {   
  11.     return (rect.x < point.x && point.x < rect.x + rect.width &&   
  12.             rect.y < point.y && point.y < rect.y + rect.height);   
  13. }   
  14. function paint() {   
  15.     context.clearRect(0, 0, canvas.width, canvas.height);   
  16.     var paintInfo = {inLeftBtn:false, inRightBtn:false}   
  17.  
  18.     if (lastMousePos && navRect && lButtonRect && rButtonRect) {   
  19.         if (pointIsInRect(lastMousePos, navRect)) {   
  20.             paintInfo.inLeftBtn = pointIsInRect(lastMousePos, lButtonRect);   
  21.             paintInfo.inRightBtn = pointIsInRect(lastMousePos, rButtonRect);   
  22.         }   
  23.     }   
  24.     paintNavigator(paintInfo);   
  25. }   

這樣我們就繪制了一個完整的導航欄,它能夠響應鼠標移動事件,并高亮當前選中的按鈕。下面我們需要加載和顯示圖片,這就需要用到 Canvas 的繪制圖像函數。


用 Canvas 繪制圖像

加載和顯示圖像

加載和顯示圖像的代碼片段如清單 13 所示:

清單 13. 加載和顯示圖像

  1.    const PAINT_INTERVAL = 20;  // 循環間隔  
  2.    const PAINT_SLOW_INTERVAL = 20000;     
  3.    const IDLE_TIME_OUT = 3000;  // 空閑超時時間  
  4.  
  5.    // 定義全部圖片 URL 數組,在本例中,所有圖片保存在和網頁同目錄中  
  6.    var imageLocations = [   
  7.    '2006109173628.jpg',   
  8.    '2007310132939.jpg',   
  9.    '200733094828-1.jpg'  
  10.    ];   
  11.   // 加載圖片  
  12.    function loadImages() {   
  13.        var total = imageLocations.length;   
  14.        var imageCounter = 0;   
  15.        var onLoad = function(err, msg) {   
  16.            if (err) {   
  17.                console.log(msg);   
  18.            }   
  19.            imageCounter++;   
  20.            if (imageCounter == total) {   
  21.                loadedImages = true;   
  22.            }   
  23.        }   
  24.  
  25.        for (var i = 0; i < imageLocations.length; i++) {   
  26.            var img = new Image();   
  27.            img.onload = function() { onLoad(false); };   
  28.            img.onerror = function() { onLoad(true, e);};   
  29.            img.src = imageLocations[i];   
  30.            images[i] = img;   
  31.        }   
  32.    }   
  33.    // 繪制圖片  
  34.    function paintImage(index) {   
  35.        if (!loadedImages)   
  36.            return;   
  37.        var image = images[index];   
  38.        var screen_h = canvas.height;   
  39.        var screen_w = canvas.width;   
  40.        var ratio = getScaleRatio({width:image.width, height:image.height},   
  41. {width:screen_w, height:screen_h});   
  42.    var img_h = image.height * ratio;   
  43.    var img_w = image.width * ratio;   
  44.  
  45.    context.drawImage(image, (screen_w - img_w)/2, (screen_h - img_h)/2, img_w, img_h);   
  46.    }   

在清單 13 的代碼中,我們更新了主繪制函數 paint,加入了 paintImage 函數,在 paintImage 函數中,利用 Canvas 的 drawImage 函數,在整個 Canvas 區域,盡可能大地縮放圖片并顯示在 Canvas 中,其最佳縮放比例如所示 :

最佳縮放比例示例
圖 3 . 最佳縮放比例示例 

這里縮放比例是通過本例所定義的函數 getScaleRatio 來獲得的,其詳細代碼見附件。這樣我們可以在 Canvas 上繪制圖像,繪制圖像的函數定義如下 :

清單 14. 繪制圖像函數

  1. drawImage(image, x, y)   image 為一個圖像或者 Canvas 對象,x,y 為圖片所要放至位置的左上角坐標  

但該函數還無法滿足我們的要求,我們需要縮放圖片到一個最佳大小,這就需要 Canvas 繪制圖片函數的另外一種形式:

清單 15. 繪制圖像函數 2 

  1. drawImage(image, x, y, width, height)     width, height 為圖像在目標 Canvas 上的大小  

該函數將圖片縮放到 width 和 height 所指定的大小并顯示出來。我們通過函數 getScaleRatio 來計算最佳縮放大小,然后就可以通過如清單 15 所示來繪制最佳大小的圖片。

繪制圖片需要傳入一個 image 對象,它一般是一個圖片或者 Canvas 對象。也就是說你可以從一個 URL 中下載圖片顯示在 Canvas 中,也可以在一個 Canvas 中顯示另外一個 Canvas 中繪制的圖形。通過如清單 16 所示的代碼來加載圖片:

清單 16. 加載圖片代碼

  1. var onLoad = function(err, msg) {   
  2.     if (err)   console.log(msg);   
  3. }   
  4. var img = new Image();   
  5. img.onload = function() { onLoad(false); };   
  6. img.onerror = function() { onLoad(true, e);};   
  7. img.src = ‘ myImage.png ’ ;  // 設置源路徑  

在整個程序中,我們利用了 setInterval 函數加入了一個定時器來觸發主循環,用于不斷循環等待全部圖片加載。當等待時間超過一個閥值之后,主循環進入 idle 狀態,該循環不僅能夠用于等待全部圖片加載,也可以用于繪制動畫效果,我們在后面將會講到如何利用該主循環來制作動態效果。

繪制縮略圖

下一步需要在導航欄中繪制每個圖片的縮略圖,該縮略圖必須按照最優的大小和間隔排列在導航欄中,同時縮略圖必須經過裁剪,獲得最優的顯示區域。整體效果如圖所示:

縮略圖效果
圖 4 . 縮略圖效果 

實現代碼片段如清單 17 所示:

清單 17. 縮略圖代碼

  1.    const HL_OFFSET = 3;     
  2.    const THUMBNAIL_LENGTH = NAVPANEL_HEIGHT - NAVBUTTON_YOFFSET*2;   // 縮略圖顯示區域的高度  
  3.    const MIN_THUMBNAIL_LENGTH = 10;  // 最小縮略圖間隔  
  4.  
  5.    var currentImage = 0;   // 當前圖片序號  
  6.    var firstImageIndex = 0;  // 當前縮略圖中第一張圖片序號  
  7.    var thumbNailCount = 0;  // 當前顯示的縮略圖數  
  8.    var maxThumbNailCount = 0;  // 最大能夠顯示的縮略圖數  
  9.    // 繪制縮略圖  
  10.    function paintThumbNails(inThumbIndex) {   
  11.        if (!loadedImages)   
  12.            return;   
  13.          
  14.        if(inThumbIndex != null) {   
  15.            inThumbIndex -firstImageIndex;   
  16.        } else {   
  17.            inThumbIndex = -1;   
  18.        }   
  19.  
  20.        var thumbnail_length = rButtonRect.x - lButtonRect.x - lButtonRect.width;   
  21.        maxThumbNailCount = Math.ceil(thumbnail_length / THUMBNAIL_LENGTH);   
  22.        var offset = (thumbnail_length - THUMBNAIL_LENGTH * maxThumbNailCount) /   
  23. (maxThumbNailCount + 1);   
  24.        if (offset < MIN_THUMBNAIL_LENGTH) {   
  25.            maxThumbNailCount = Math.ceil(thumbnail_length/ (THUMBNAIL_LENGTH +   
  26. MIN_THUMBNAIL_LENGTH));   
  27.            offset = (thumbnail_length - THUMBNAIL_LENGTH * maxThumbNailCount) /   
  28. (maxThumbNailCount + 1);   
  29.        }   
  30.  
  31.        thumbNailCount = maxThumbNailCount > imageCount - firstImageIndex?   
  32. imageCount - firstImageIndex: maxThumbNailCount;   
  33.  
  34.        imageRects = new Array(thumbNailCount);   
  35.  
  36.        for (var i = 0; i < thumbNailCount; i++) {   
  37.            image = images[i+firstImageIndex];   
  38.            context.save();   
  39.            var x = lButtonRect.x + lButtonRect.width + (offset+THUMBNAIL_LENGTH)*i;   
  40.            srcRect = getSlicingSrcRect({width:image.width, height:image.height},   
  41. {width:THUMBNAIL_LENGTH, height: THUMBNAIL_LENGTH});   
  42.            imageRects[i] = {   
  43.                image:image,   
  44.                rect: {   
  45.                    x:x+offset,   
  46.                    y:inThumbIndex == i? navRect.y+NAVBUTTON_YOFFSET-HL_OFFSET:   
  47. navRect.y+NAVBUTTON_YOFFSET,   
  48.                    height: THUMBNAIL_LENGTH,   
  49.                    width: THUMBNAIL_LENGTH   
  50.                }   
  51.            }   
  52.  
  53.            context.translate(x, navRect.y);   
  54.            context.drawImage(image, srcRect.x, srcRect.y,   
  55. srcRect.width, srcRect.height,   
  56. offset, imageRects[i].rect.y - navRect.y,   
  57. THUMBNAIL_LENGTH, THUMBNAIL_LENGTH);   
  58.            context.restore();   
  59.        }   
  60.    }   

清單 17 的代碼使用了 Canvas 中坐標轉換的方法來繪制每張縮略圖。轉換坐標函數如清單 18 所示:

清單 18. 轉換坐標函數

  1. translate(x, y)  x 為橫軸偏移方向大小,y 為縱軸方向偏移大小  

其原理如圖所示:

轉換坐標

Canvas 繪圖的坐標系和大部分操作系統繪圖的坐標系一致,都是左上角為原點,向右為 x 方向,向下為 y 方向。從圖 5 中我們看出,新的坐標原點平移到了 (x,y) 位置,后面的 Canvas 繪圖函數都是以新的原點為基準繪圖。清單 17 在繪制每張縮略圖時,首先轉換原點到縮略圖的左上角,然后在固定的 x 和 y 坐標位置顯示圖片,將這個過程做成一個循環,就繪制了所有等間距的縮略圖。

將圖片顯示到縮略圖中,我們還需要把圖片縮放到其中較短的一邊能夠和縮略圖的邊長重合,同時截去超出縮略圖大小的圖片部分,從而達到最優的顯示縮略圖的效果。其示意圖如所示。

截取最佳圖片部分
圖 6. 截取最佳圖片部分 

為了獲得這種最優的縮略圖顯示效果,我們需要獲得如下信息:1. 原圖中應該截取哪些部分圖片;2 . 縮放多大的比例到目標區域中。本例定義了函數 getSlicingSrcRect 實現了這個功能,它返回一個 rect 對象,包括了應該截取原圖的哪些區域,其詳細代碼見附件。但還需要一個函數來將這個截取的圖片部分縮放到目標區域中,這就用到了 Canvas 繪制圖像函數 drawImage 的另外一種形式:

清單 19. 繪制圖像函數 3

  1. drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)     
  2.  sx, sy, sWidth, sHeight 為原圖中的需要截取的區域,  dx, dy, dWidth, dHeight 為目標區域的位置大小  

該函數截取原圖片的部分區域,然后縮放顯示到目標區域中。我們利用這個函數,就能夠實現截取最佳區域以顯示在縮略圖中的效果。

在繪制縮略圖我們還實現了一個小技巧:縮略圖大小是固定的,但之間的間距是動態調整的,當縮略圖之間的間距小于一個閥值的時候,我們強制最小間隔不小于閥值,詳細代碼請看清單 17。

響應點擊事件

顯示縮略圖以后,我們需要響應點擊事件,即能夠點擊縮略圖,顯示所對應的圖片。同時,我們還需要點擊左右兩邊的按鈕,能夠實現縮略圖的翻頁。這是通過清單 20 所示的代碼實現的:

清單 20 . 響應鼠標點擊事件

  1.    // 加入了鼠標點擊事件的響應  
  2.    this.load = function() {   
  3.        //event binding   
  4.        canvas.onclick = onMouseClick;   
  5.        canvas.onmousemove = onMouseMove;   
  6. }   
  7. // 鼠標點擊事件處理  
  8.    function onMouseClick(event) {   
  9.        point = {x: event.clientX, y:event.clientY};   
  10.        lastMousePos = point;   
  11.  
  12.        if (pointIsInRect(point, lButtonRect)) {   
  13.            nextPane(true);   
  14.        } else if (pointIsInRect(point, rButtonRect)) {   
  15.            nextPane(false);   
  16.        } else {   
  17.            var selectedIndex = findSelectImageIndex(point);   
  18.            if (selectedIndex != -1) {   
  19.                selectImage(selectedIndex);   
  20.            }   
  21.        }   
  22.        updateIdleTime();   
  23.    }   
  24.    // 返回所點擊的縮略圖序號,如果沒有點擊縮略圖則返回 -1   
  25.    function findSelectImageIndex(point) {   
  26.        for(var i = 0; i < imageRects.length; i++) {   
  27.            if (pointIsInRect(point, imageRects[i].rect))   
  28.                return i + firstImageIndex;          
  29. }   
  30.        return -1;   
  31.    }   
  32.    // 將當前圖片序號設為 index,重畫  
  33.    function selectImage(index) {   
  34.        currentImage = index;   
  35.        paint();   
  36.    }   
  37.    // 將縮略圖翻頁,更新縮略圖中第一張圖片的序號  
  38.    function nextPane(previous) {   
  39.        if (previous) {   
  40.            firstImageIndexfirstImageIndex = firstImageIndex - maxThumbNailCount < 0?   
  41. 0 : firstImageIndex - maxThumbNailCount;   
  42.        } else {   
  43.            firstImageIndexfirstImageIndex = firstImageIndex + maxThumbNailCount*2 - 1 > imageCount - 1?   
  44. (imageCount - maxThumbNailCount > 0? imageCount - maxThumbNailCount: 0) :   
  45. firstImageIndex + maxThumbNailCount;   
  46.              
  47.        }   
  48.        currentImage = (firstImageIndex <= currentImage &&   
  49. currentImage <= firstImageIndex + maxThumbNailCount)? currentImage : firstImageIndex;   
  50.        paint();   
  51.    }   

這里我們通過 2 個變量 firstImageIndex 和 currentImage 來控制縮略圖和當前圖片的顯示,并能夠根據鼠標點擊來改變當前選中的圖片。


加入其他效果

根據當前窗口大小調整 Canvas 大小

當瀏覽器的大小改變的時候,我們的圖片瀏覽器就會由于沒能重畫導致部分區域無法顯示。我們需要根據瀏覽器當前頁面大小來動態定義整個圖片瀏覽器的大小,從而能夠調整整個圖片瀏覽器的最佳大小。代碼如清單 21 所示:

清單 21 .Resize 支持

  1. this.load = function() {   
  2.     //resize   
  3.     resize();   
  4.     window.onresize = resize;   
  5.       
  6.     //event binding   
  7.     canvas.onclick = onMouseClick;   
  8.     canvas.onmousemove = onMouseMove;   
  9.  
  10.     loadImages();          
  11.  
  12.     startLoop();   
  13.     updateIdleTime();   
  14. }   
  15. function resize() {   
  16.     var size = getScreenSize();   
  17.     canvas.width = size.width;   
  18.     canvas.height = size.height;   
  19.     paint();   
  20. }   
  21.  
  22. function getScreenSize() {   
  23.     return { width: document.documentElement.clientWidth,   
  24. ght: document.documentElement.clientHeight};   
  25. }   

這里代碼響應了 window 對象的 onresize 事件,從而能夠響應整個瀏覽器頁面大小改變的事件,通過 document.documentElement.clientWidth 和 document.documentElement.clientHeight 這兩個 DOM 屬性,我們獲得了當前頁面顯示范圍大小,從而能夠動態調整 Canvas 的大小到最佳位置。

顯示縮略圖預覽

我們還需要實現這種效果:當鼠標放置在某個縮略圖上方時,能夠顯示一個縮略圖預覽界面,其效果如圖所示:

縮略圖預覽
圖 7 . 縮略圖預覽 

實現代碼如清單 22 所示:

清單 22 . 縮略圖預覽代碼

  1. const ARROW_HEIGHT = 10;  // 下方三角形的高度  
  2. const BORDER_WRAPPER = 2;   // 邊緣白框的厚度  
  3. // 繪制預覽圖  
  4. function paintHighLightImage(srcRect, imageRect) {   
  5.   var ratio = imageRect.image.width == srcRect.width?   
  6.     
  7.   THUMBNAIL_LENGTH/imageRect.image.width:THUMBNAIL_LENGTH/imageRect.image.height;   
  8.   ratio *= 1.5;   
  9.  
  10.     var destRect = {   
  11.         x:imageRect.rect.x + imageRect.rect.width/2 - imageRect.image.width*ratio/2,   
  12.         y:navRect.y - ARROW_HEIGHT - BORDER_WRAPPER - imageRect.image.height*ratio,   
  13.         width: imageRect.image.width * ratio,   
  14.         height: imageRect.image.height * ratio   
  15.     }   
  16.  
  17.     var wrapperRect = {   
  18.         x: destRect.x - BORDER_WRAPPER,   
  19.         y: destRect.y - BORDER_WRAPPER,   
  20.         width: destRect.width + BORDER_WRAPPER * 2,   
  21.         height: destRect.height + BORDER_WRAPPER * 2   
  22.     }   
  23.  
  24.     var arrowWidth = ARROW_HEIGHT * Math.tan(30/180*Math.PI);   
  25.  
  26.     context.save();   
  27.     context.fillStyle = 'white';   
  28.     context.translate(wrapperRect.x, wrapperRect.y);   
  29.     context.beginPath();   
  30.     context.moveTo(0, 0);   
  31.     context.lineTo(wrapperRect.width, 0);   
  32.     context.lineTo(wrapperRect.width, wrapperRect.height);   
  33.     context.lineTo(wrapperRect.width/2 + arrowWidth, wrapperRect.height);   
  34.     context.lineTo(wrapperRect.width/2, wrapperRect.height+ARROW_HEIGHT);   
  35.     context.lineTo(wrapperRect.width/2 - arrowWidth, wrapperRect.height);   
  36.     context.lineTo(0, wrapperRect.height);   
  37.     context.lineTo(0, 0);   
  38.     context.closePath();   
  39.     context.fill();   
  40.     context.drawImage(imageRect.image, BORDER_WRAPPER, BORDER_WRAPPER,   
  41. tRect.width, destRect.height);   
  42.     context.restore();   
  43. }   

在函數 paintHighLightImage 中大量使用了 Canvas 的路徑繪圖函數來繪制這個底部為三角形箭頭,上部為矩形的形狀。感興趣的讀者可以研究這些 Canvas 繪圖函數的使用。

自動隱藏

最后我們在加入一個動態的效果:當鼠標不再移動超過一定時刻的時候,導航欄能夠自動隱藏。其代碼如清單 23 所示:

清單 23 . 自動隱藏代碼

  1. // 加入了自動隱藏導航欄的功能  
  2.    function paint() {   
  3.        context.clearRect(0, 0, canvas.width, canvas.height);   
  4.        paintImage(currentImage);   
  5.        var paintInfo = {inLeftBtn:false, inRightBtn:false, inThumbIndex: null}   
  6.  
  7.        if (lastMousePos && navRect && lButtonRect && rButtonRect) {   
  8.            if (pointIsInRect(lastMousePos, navRect)) {   
  9.                paintInfo.inLeftBtn = pointIsInRect(lastMousePos, lButtonRect);   
  10.                paintInfo.inRightBtn = pointIsInRect(lastMousePos, rButtonRect);   
  11.                if (!paintInfo.inLeftBtn && !paintInfo.inRightBtn) {   
  12.                    var index = findSelectImageIndex(lastMousePos);   
  13.                    if (index != -1) {   
  14.                        paintInfo.inThumbIndex = index;   
  15.                    }   
  16.                }   
  17.            }   
  18.        }   
  19.        if(idleTime && getTime() - idleTime <= IDLE_TIME_OUT) {   
  20.            paintNavigator(paintInfo);   
  21.        }   
  22.    }   

當空閑時間超過閥值時,導航欄能夠自動隱藏,這樣瀏覽圖片更加方便。

最終效果

在合并了上述所有清單代碼之后,我們在瀏覽器上就可以看到如圖 所示的效果。

完整的圖片瀏覽器效果
圖 8 . 完整的圖片瀏覽器效果 

完整的代碼請看附件。運行代碼需要 Firefox 1.5, Chrome 1, Safari 3 以上版本的瀏覽器。


總結及展望

本文用圖片瀏覽器的例子來說明 Canvas 的各種函數的使用。該例子也只是一個簡單的 demo,并未涉及更為高級的 Canvas 使用,例如旋轉坐標轉換,繪制曲線,組合圖形,漸變色彩等等。該例子也可以進一步改進,加入更多動態效果并提高效率。本文就不一一敘述。

從上述例子我們也能看到,Canvas 作為 HTML 5 新的元素,其繪圖功能已經很接近操作系統的渲染函數。Canvas 元素可以進行矢量繪圖也可以進行位圖的繪制,在不久的將來,Canvas 還能利用 WebGL 技術支持 3D 繪圖,這為未來的的網頁游戲制作和更為豐富的 Web 用戶體驗提供了便利。在最新的 Google Wave 平臺中,就已經大量使用了 Canvas 技術來渲染用戶界面。我相信,在不久的將來,Canvas 能夠大量被廣大網頁設計師和架構師所使用,并進一步被得到完善和加強。

責任編輯:張偉 來源: HTML5China
相關推薦

2012-05-07 14:24:15

HTML 5Web App

2012-05-28 13:09:12

HTML5

2011-04-14 15:55:35

WPF.NET

2019-12-02 13:46:35

瀏覽器前端開發

2012-04-23 13:43:02

HTML5瀏覽器

2009-05-27 08:54:15

瀏覽器平臺Chrome

2017-12-14 15:45:02

2015-03-24 13:39:08

IE

2012-09-03 10:24:16

果粉瀏覽器

2012-05-17 09:45:30

2014-08-18 14:58:25

微軟IE

2022-06-13 06:33:04

瀏覽器瀏覽器插件

2013-02-21 16:03:52

瀏覽器

2012-03-06 09:18:38

Silverlight

2021-08-02 13:05:49

瀏覽器HTTP前端

2010-11-15 13:34:13

瀏覽器

2017-02-28 10:05:56

Chrome源碼

2017-11-21 14:56:59

2021-08-06 16:52:10

瀏覽器HTTPS通信

2022-06-20 09:01:56

Plasmo開源
點贊
收藏

51CTO技術棧公眾號

手机av免费看| 一区二区三视频| 日本网站在线播放| 天堂在线精品| 日本道精品一区二区三区| 青青草久久网络| 国产日韩欧美视频在线观看| 亚洲日产国产精品| 亚洲三级免费看| 成人高清在线观看视频| 色在线免费观看| 国产精品传媒入口麻豆| 91亚洲精品久久久| 国产在线观看黄色| 希岛爱理一区二区三区| 亚洲国产小视频在线观看| 成人性生生活性生交12| 色呦呦在线观看视频| 91麻豆国产福利在线观看| 国产欧美日韩中文字幕| 天天操天天干视频| 伊人久久大香线蕉综合四虎小说 | 欧州一区二区三区| 一本色道久久加勒比精品| 国产经典久久久| 久久久pmvav| 成人午夜视频免费看| 国产精品美女免费| 青青草成人av| 伊人久久亚洲美女图片| 久久精品精品电影网| 亚洲午夜久久久久久久久红桃| 国产精品va视频| 欧美在线观看视频一区二区| 国产精品国产亚洲精品看不卡| 久草资源在线观看| 国产日韩精品久久久| 国产在线视频欧美一区二区三区| 中文在线免费看视频| 亚洲欧美视频| 57pao精品| 91看片在线播放| 亚洲高清二区| 欧美激情综合亚洲一二区| 一级片一级片一级片| 日韩精品2区| 一区二区三区日韩在线| 日韩av一二区| 亚洲另类春色校园小说| 日韩av一区在线观看| av天堂一区二区| 99精品中文字幕在线不卡| 日韩美一区二区三区| 国产乱码一区二区三区四区| 欧美性www| 欧美日本在线一区| 97超碰人人爽| 91麻豆精品国产综合久久久| 欧美疯狂做受xxxx富婆| 中文字幕国产高清| 日本在线视频一区二区三区| 日韩一级二级三级精品视频| 青青草原播放器| 欧美影院精品| 亚洲成人xxx| 日本三级日本三级日本三级极| julia中文字幕一区二区99在线| 欧美成人精精品一区二区频| 污污污www精品国产网站| theporn国产在线精品| 亚洲第一av网| www.色多多| 国产精品最新| www.日韩.com| 唐朝av高清盛宴| 雨宫琴音一区二区在线| 欧美一级电影久久| 无码久久精品国产亚洲av影片| 日韩福利视频导航| 成人a级免费视频| 亚洲欧美黄色片| 91视频免费看| 亚洲一区二区三区午夜| 中文字幕有码在线观看| 午夜精品福利一区二区三区av | 免费不卡在线视频| 成人在线激情视频| 人妻丰满熟妇av无码区hd| 91蜜桃网址入口| 一区二区在线观看网站| 日本动漫理论片在线观看网站 | 黄色成人在线看| 超碰一区二区| 7777女厕盗摄久久久| 国产精品日日摸夜夜爽| 日韩精品导航| 菠萝蜜影院一区二区免费| 久久久精品99| 日韩精品1区2区3区| 亚洲综合日韩中文字幕v在线| 欧美 日韩 国产 成人 在线 91| 久久久99久久精品欧美| 成人性做爰片免费视频| 中文不卡1区2区3区| 欧美精品久久一区二区三区| 国产精品久久无码| 99久久激情| 日本精品一区二区三区在线| 99久久一区二区| 久久久99免费| 免费无码毛片一区二三区| 欧美91在线|欧美| 亚洲国产精品久久久久| 日韩一卡二卡在线观看| 国产一区二区三区的电影 | 国产午夜精品一区二区三区视频 | 亚洲高清资源| 国产日韩欧美在线观看| 人妻精品一区二区三区| 亚洲码国产岛国毛片在线| 狠狠热免费视频| 欧美毛片免费观看| 精品自拍视频在线观看| 最近免费中文字幕大全免费版视频| 国内外成人在线| 青青草成人激情在线| 看黄在线观看| 亚洲成人久久一区| 国产少妇在线观看| 久久成人免费电影| 色狠狠久久av五月综合|| 欧美极品videos大乳护士| 欧美一区二区三区成人| 亚洲精品自拍视频在线观看| 老司机免费视频久久| 久久精品一二三区| segui88久久综合| 欧美日韩卡一卡二| x88av在线| 久久在线91| 免费试看一区| 免费观看欧美大片| 日韩激情在线视频| 国产精品黄色网| gogogo免费视频观看亚洲一| 免费一级淫片aaa片毛片a级| 日韩三级av高清片| 久久99久久99精品免观看粉嫩| 国产一区二区三区黄片| 国产精品看片你懂得| 九色porny自拍| 日韩免费视频| 成人激情av在线| 毛片网站在线免费观看| 欧美日韩高清一区| 看黄色录像一级片| 激情六月婷婷久久| 六月婷婷激情网| 亚洲一区二区三区四区电影| 欧美高清激情视频| 后进极品白嫩翘臀在线视频| 亚洲成av人影院在线观看网| 波多野结衣有码| 午夜亚洲性色视频| 色99中文字幕| 91视频亚洲| 欧美激情在线一区| 色中色在线视频| 日本久久电影网| 91禁男男在线观看| 国产麻豆精品视频| 男人添女人下部高潮视频在观看| 欧美日韩另类图片| 国产成人精品电影| 欧美成人性生活视频| 日韩欧美国产wwwww| 国产在线拍揄自揄拍| 91蜜桃免费观看视频| 粉色视频免费看| 欧美精品综合| 久久久婷婷一区二区三区不卡| 奇米777日韩| 久久精品亚洲精品| 乱精品一区字幕二区| 色综合激情五月| 三上悠亚在线观看视频| 成人激情文学综合网| 日本中文字幕片| 欧美电影一区| 国产综合精品一区二区三区| 九九九伊在线综合永久| 九九热这里只有在线精品视| 午夜影院免费视频| 欧美日韩国产高清一区| 日本一区二区网站| 国产女主播一区| 337p日本欧洲亚洲大胆张筱雨| 国产精品日韩| 裸体裸乳免费看| 自拍偷拍精品| 成人毛片网站| 国产精品99精品一区二区三区∴| 欧美激情极品视频| 成人在线免费电影| 欧美精品一区二区精品网| 国产情侣呻吟对白高潮| 亚洲自拍偷拍欧美| 少妇愉情理伦三级| 91偷拍与自偷拍精品| 日韩av加勒比| 视频一区欧美日韩| 免费一级特黄毛片| 99久久婷婷这里只有精品 | 亚洲精品中文在线观看| 国产精品三级在线观看无码| 激情六月婷婷综合| 日本一极黄色片| 日韩一级精品| 麻豆传媒网站在线观看| 男男gay无套免费视频欧美| 999久久久| 国产人与zoxxxx另类91| 国产成人在线一区| 性欧美18~19sex高清播放| 欧美猛交免费看| 久操视频在线| 亚洲精品在线视频| 欧美性受xxxx狂喷水| 欧美一区二区在线看| 中文字幕一区二区三区免费看| 狠狠色狠狠色综合日日小说| 九九九国产视频| 有坂深雪av一区二区精品| 91大神福利视频| 欧美国产一区二区在线观看| 亚洲一区二区三区蜜桃| www.日韩在线| 网站免费在线观看| kk眼镜猥琐国模调教系列一区二区| 亚洲熟女一区二区三区| 国产精品1区2区| 亚洲成人av免费观看| 韩国一区二区视频| 日本特黄在线观看| 国产一区久久久| 日本美女久久久| 国产精品1区二区.| 绯色av蜜臀vs少妇| 成人av电影在线播放| 男人的天堂免费| 成人精品小蝌蚪| 97香蕉碰碰人妻国产欧美 | а√天堂中文在线资源8| 欧美国产精品va在线观看| 影音先锋中文在线视频| 美女av一区二区| 黄色小说在线播放| 高清欧美性猛交| 午夜久久中文| 国产成人高清激情视频在线观看| 欧美韩国亚洲| 国产精品一区二区三区在线播放 | 阿v天堂2014| 国产精品国产三级国产专播品爱网| 久久中文字幕精品| 综合久久久久久| 久久免费公开视频| 欧美日韩裸体免费视频| 无码人妻丰满熟妇奶水区码| 在线亚洲精品福利网址导航| 夜夜狠狠擅视频| 欧美一级高清片在线观看| 黄色av一区二区三区| 日韩电影免费观看中文字幕 | 亚洲精品国产九九九| 国产乱码精品一区二区三区日韩精品| 麻豆精品少妇| 亚洲国产欧美日韩| 欧美午夜在线视频| 激情综合在线观看| 麻豆一区二区99久久久久| 99热这里只有精品2| 91日韩一区二区三区| 国产白丝一区二区三区| 亚洲国产aⅴ成人精品无吗| 国产99免费视频| 欧美一区二区三区性视频| 天天色综合av| 色琪琪综合男人的天堂aⅴ视频| 日本欧美电影在线观看| 欧洲s码亚洲m码精品一区| 色综合视频一区二区三区44| 国产私拍一区| 欧美xxxxx视频| 国产精品网站免费| 久久www免费人成看片高清| 亚洲熟女一区二区| 国产精品久久久久影视| 免费观看一区二区三区毛片| 欧美视频一区在线观看| 手机看片一区二区三区| 俺去了亚洲欧美日韩| 一个人www视频在线免费观看| 国产在线观看一区二区三区| 欧美日韩破处| 久久久久久av无码免费网站下载| 久久亚洲影院| 亚洲精品国产成人av在线| 国产精品成人免费在线| 日韩精品在线观看免费| 日韩亚洲欧美高清| 永久免费av在线| 88xx成人精品| 一区中文字幕电影| 伊人久久婷婷色综合98网| 老鸭窝亚洲一区二区三区| 四虎国产精品免费| 国产精品激情偷乱一区二区∴| 国产原创视频在线| 精品不卡在线视频| а√天堂官网中文在线| 国产精品久久国产精品99gif| 欧美电影在线观看免费| 激情六月天婷婷| 国产曰批免费观看久久久| 女人十八毛片嫩草av| 天天影视涩香欲综合网| 午夜精品久久久久久久99老熟妇 | 国产又粗又硬视频| 色综合一个色综合| 天天干,夜夜操| 欧美日韩第一页| 国产aⅴ精品一区二区四区| 亚洲精品9999| 日本不卡高清视频| 欧美做受xxxxxⅹ性视频| 精品久久久久久久久久久| 亚洲精品一区二区三区蜜桃| 欧美成人剧情片在线观看| 警花av一区二区三区| 国产手机视频在线观看| 国产一区二区网址| 神马午夜精品91| 欧美高清hd18日本| 黄网址在线观看| 91久久久久久久一区二区| 欧美大人香蕉在线| 中日韩av在线播放| 国产精品传媒入口麻豆| 国产伦精品一区二区三区免.费| 日韩视频精品在线| 欧美成人一级| 97中文字幕在线| 成人午夜看片网址| 久久精品女人毛片国产| 亚洲成人免费在线视频| 咪咪网在线视频| 久久久久综合一区二区三区| 老牛影视一区二区三区| 女人黄色一级片| 91精品午夜视频| 青青草视频在线免费直播| 国产精品一区二区三区免费观看| 亚洲麻豆视频| 国产精品一二三区在线观看| 欧美视频在线观看一区二区| 黄视频在线观看网站| 成人在线观看av| 99在线|亚洲一区二区| 中文幕无线码中文字蜜桃| 欧美日韩国产综合一区二区三区 | 一区二区三区在线看| 黄色a在线观看| 国产精品第三页| 国产精品成人一区二区不卡| 日本一区二区三区在线免费观看| 亚洲自拍偷拍麻豆| 日本ー区在线视频| 国产精品偷伦视频免费观看国产| 欧美一区综合| 朝桐光av一区二区三区| 欧美在线视频全部完| 国产日产一区二区| 久久精品一二三区| 久久精品99国产国产精| 久久综合亚洲色hezyo国产| 亚洲美女福利视频网站| 亚洲精品66| 免费不卡av在线| 国产精品久久久久婷婷二区次| 国精品人妻无码一区二区三区喝尿| 1769国产精品| 91精品婷婷色在线观看| 免费在线观看成年人视频| 在线成人免费视频| 日韩精品极品| 日韩中文在线字幕| 久久久久久综合| 韩国av在线免费观看| 国产精品爽爽ⅴa在线观看|