Slideshow với HTML5 canvas và jQuery
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