Slideshow với HTML5 canvas và jQuery

Đăng bởi Neo trong mục Hướng dẫn vào 18 tháng 9, 2010 | Comments

Phần tử canvas trong HTML5, giúp bạn dễ dàng tạo và thay đổi đồ họa trên website. Chúng ta có thể sử dụng canvas như mọi phần tử HTML khác, tức là có thể áp dụng các hiệu ứng của jQuery, kiểm tra các sự kiện, áp dụng vào trong layout...

Các bài hướng dẫn canvas trước đây thường về game hoặc hiệu ứng ảnh. Hôm nay bạn sẽ được học cách sử dụng canvas để tạo hiệu ứng cho jquery slideshow.

Ý tưởng

Sử dụng JavaScript, chúng ta sẽ áp dụng bộ lọc đặc biệt vào các ảnh trong slideshow. Chúng ta sẽ tạo một phiên bản mới của ảnh trong slideshow và lưu vào trong phần tử canvas. Khi người xem click để chuyển ảnh, canvas sẽ xuất hiện với hiệu ứng fadeIn.

Mã HTML

Trước tiên, bạn cần có file HTML, tạm đặt tên là html5-slideshow.html như sau:

<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>An HTML5 Slideshow w/ Canvas & jQuery | Tutorialzine Demo</title>
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>
<div id="slideshow">
    <ul class="slides">
        <li><img src="img/photos/1.jpg" width="620" height="320" alt="Marsa Alam" /></li>
        <li><img src="img/photos/2.jpg" width="620" height="320" alt="Turrimetta Beach" /></li>
        <li><img src="img/photos/3.jpg" width="620" height="320" alt="Power Station" /></li>
        <li><img src="img/photos/4.jpg" width="620" height="320" alt="Colors of Nature" /></li>
    </ul>

    <span class="arrow previous"></span>
    <span class="arrow next"></span>
</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="script.js"></script>
</body>
</html>

Đây là kiểu khai báo doctype của HTML5, bạn có thể thấy nó hơi khác so với HTML4.1 hiện tại. Mã HTML cho slideshow rất đơn giản, tất cả nằm trong thẻ div#slideshow và mỗi ảnh nằm trong một phần tử li của unordered list.

Ở dưới chúng ta thêm jquery và script.js (phần cuối bài viết) để xử lý các hiệu ứng (bạn hoàn toàn có thể chuyển thẻ script này vào trong thẻ <head>).

Mã CSS

Tất cả các mã CSS được lưu vào style.css, ở đây tác giả sử dụng #slideshow trước các thuộc tính CSS khác. Việc này giúp bạn có thể gắn vào website của mình mà không lo bị xung đột.

#slideshow{
    background-color:#F5F5F5;
    border:1px solid #FFFFFF;
    height:340px;
    margin:150px auto 0;
    position:relative;
    width:640px;

    -moz-box-shadow:0 0 22px #111;
    -webkit-box-shadow:0 0 22px #111;
    box-shadow:0 0 22px #111;
}

#slideshow ul{
    height:320px;
    left:10px;
    list-style:none outside none;
    overflow:hidden;
    position:absolute;
    top:10px;
    width:620px;
}

#slideshow li{
    position:absolute;
    display:none;
    z-index:10;
}

#slideshow li:first-child{
    display:block;
    z-index:1000;
}

#slideshow .slideActive{
    z-index:1000;
}

#slideshow canvas{
    display:none;
    position:absolute;
    z-index:100;
}

#slideshow .arrow{
    height:86px;
    width:60px;
    position:absolute;
    background:url('img/arrows.png') no-repeat;
    top:50%;
    margin-top:-43px;
    cursor:pointer;
    z-index:5000;
}

#slideshow .previous{ background-position:left top;left:0;}
#slideshow .previous:hover{ background-position:left bottom;}

#slideshow .next{ background-position:right top;right:0;}
#slideshow .next:hover{ background-position:right bottom;}

Chúng ta có thể chia thành 3 nhóm người xem slideshow như sau:

  • Người xem tắt JavaScript trên trình duyệt: chỉ nhìn thấy ảnh đầu tiên và không thể click sang ảnh tiếp theo.
  • Người xem bật JavaScript (mặc định), nhưng trình duyệt không hỗ trợ canvas: vẫn thấy slide chuyển động nhưng không đi kèm hiệu ứng.
  • Người xem bật JavaScript và sử dụng trình duyệt hỗ trợ canvas: thấy đầy đủ nhất hiệu ứng của slideshow (Các phiên bản mới nhất của Firefox, Safari, Chrome, Opera và IE9).

Với 2 nhóm đầu tiên, sử dụng cách chọn first-child để hiển thị slide đầu tiên và áp dụng thuộc tính overflow:hidden để che đi các phần khác.

Mã JavaScript

Cuối cùng là phần quan trọng nhất của bài hướng dẫn: mã Javascript và jQuery.

script.js – Phần 11

$(window).load(function(){

    // Chờ sự kiện window.load, để biết chắc là ảnh đã tải xong.

    // Kiểm tra xem trình duyệt có hỗ trợ canvas hay không:
    var supportCanvas = 'getContext' in document.createElement('canvas');

    // sử dụng setTimeout giúp đồng bộ và cải thiện tốc độ đáp ứng của trang
    // (do canvas xử lý ảnh tốn tài nguyên máy tính)

    setTimeout(function(){

        if(supportCanvas){
            $('#slideshow img').each(function(){

                // Tạo ảnh mới (được sửa từ ảnh gốc)
                createCanvasOverlay(this);
            });
        }

        var slides = $('li'),
            current = 0;

        $('#slideshow .arrow').click(function(){
            var li            = slides.eq(current),
                canvas        = li.find('canvas'),
                nextIndex    = 0;

            // Tùy thuộc sự kiện là "next" hay "previous"
            // mà ta tính toán chỉ số của slide

            if($(this).hasClass('next')){
                nextIndex = current >= slides.length-1 ? 0 : current+1;
            }
            else {
                nextIndex = current <= 0 ? slides.length-1 : current-1;
            }

            var next = slides.eq(nextIndex);

            if(supportCanvas){

                // Trình duyệt hỗ trợ canvas, sử dụng fadeIn để hiển thị canvas

                canvas.fadeIn(function(){

                    // Hiển thị slide tiếp lên trên
                    next.show();
                    current = nextIndex;

                    // fadeOut slide hiện tại
                    li.fadeOut(function(){
                        li.removeClass('slideActive');
                        canvas.hide();
                        next.addClass('slideActive');
                    });
                });
            }
            else {

                // Nếu trình duyệt không hỗ trợ canvas
                // sử dụng show() và hide()

                current=nextIndex;
                next.addClass('slideActive').show();
                li.removeClass('slideActive').hide();
            }
        });

    },100);

Với document.createElement(), bạn có thể tạo bất kỳ phần từ DOM nào. Vì vậy để kiểm tra trình duyệt có hỗ trợ canvas hay không, bạn có thể sử dụng toán tử inđể kiểm tra phương thức getContext(). Kết quả của phép thử sẽ được dùng để kiểm tra trình duyệt có hỗ trợ canvas hay không.

Bạn cần chú ý là khi gọi hàm createCanvasOverlay chúng ta cần đặt vào trong setTimeout vì hàm này chạy khá nặng và có thể kiến trình duyệt bị treo (nếu cấu hình máy của bạn yếu). Và khi đó setTimeout sẽ giúp chia nhỏ thời gian xử lý giúp cải thiện tốc độ.

script.js – Phần 2

    // Hàm createCanvasOverlay sẽ lấy ảnh và xử lý
    // tạo phiên bản tương tự Overlay blending trong photoshop

    function createCanvasOverlay(image){

        var canvas            = document.createElement('canvas'),
            canvasContext    = canvas.getContext("2d");

        // Đặt chiều rộng và cao bằng với kích thước ảnh
        canvas.width = image.width;
        canvas.height = image.height;

        // Vẽ lại ảnh trên canvas:
        canvasContext.drawImage(image,0,0);

        // Lấy các dữ liệu ảnh và lưu vào mảng imageData:
        var imageData    = canvasContext.getImageData(0,0,canvas.width,canvas.height),
            data        = imageData.data;

        // Lặp trên từng pixel của ảnh và sửa các giá trị màu red, green và blue

        for(var i = 0;i<imageData.height*imageData.width*4;i++){

            // Các giá trị của màu red, green và blue là liên tục trong các phần tử
            // nên chúng ta sẽ xử lý cả 3 một lần trong mảng imageData

            data[i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) :
                        (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
            data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) :
                        (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
            data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) :
                        (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));

            // Để nguyên giá trị alpha trong kênh màu RGB
            ++i;
        }

        // Chuyển ảnh đã xử lý trở lại canvas
        canvasContext.putImageData(imageData,0,0,0,0,imageData.width,imageData.height);

        // Đưa canvas vào DOM, bên trên ảnh
        image.parentNode.insertBefore(canvas,image);
    }

});

Có thể nói hàm createCanvasOverlay là phần chính của bài hướng dẫn. Bạn có thể hiểu canvas là một tờ giấy trắng mà bạn có thể vẽ vào nhờ cái bút javascript. Đoạn mã trong hàm tạo một phần tử canvas trắng và đưa ảnh vào sử dụng phương thức drawImage(). Sau đó, chúng ta sử dụng tiếp getImageData() để lấy từng điểm ảnh trong canvas vào mảng imageData.

Tiếp tục, với từng điểm ảnh chúng ta áp dụng bộ lọc đặc biệt (màu sáng thì sáng hơn và màu tối sẽ tối hơn) tương tự với chế độ overlay blending trong photoshop.

Vòng lặp for xử lý rất nhiều – với một bức ảnh 600×400 pixel sẽ phải có 240 000 lần lặp! Lý do đó bạn phải thực sự cẩn thận với đoạn mã, sao cho nó nhẹ nhất có thể, cũng vì vậy tác giả copy công thức 3 lần thay vì chuyển nó vào hàm. Việc này giúp vòng lặp chạy nhanh gấp ba lần

Bài viết được dịch lại từ tutorialzine

Bạn có thích bài viết này?

Neo's picture

Neo

Nhìn mặt trời từ năm 1984 nhưng tới tận 2002 mới được thấy cái máy tính đầu tiên của mình. Đầu năm 2007 thì quyết định theo cái nghề cao quý là thiết kế web Big Grin. Hiện mình đang sống tại Hà Nội. Sở thích: làm website và giúp đỡ mọi người phát triển website theo chiều hướng tốt đẹp hơn.

Trang chủ - Twitter