Làm hiệu ứng búng tay của THANOS bằng Javascript

Trước ngày ra mắt ENDGAME không lâu, mình phát hiện Google có bí mật làm một chức năng hết sức thú vị, đó chính là xuất hiện một hiệu ứng búng tay bay màu như Thanos đã làm trong Infinity War và xoá sổ 50% số kết quả tìm kiếm.

Mình thấy khá thú vị với trò đó của Google, vậy là cũng thử tìm tòi xem làm 1 cái tương tự. Nhưng lần này, Thanos đã là chuyện cũ rồi, nếu ai đã xem phần 4 rồi đều biết, cuối phim Iron-Man sẽ là người búng tay, cái búng tay không chỉ thổi bay Thanos cùng quân đoàn của hắn mà còn lấy đi cả mạng sống của Tony. Hôm nay mình xin được tái hiện lại kết quả của trận chiến trong Hồi Kết vừa ra mắt ngày 26 tháng 4 vừa qua bằng lập trình Javascript.

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Đây là demo của mình LIVE DEMO: https://trandaison.github.io/

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Concept

Nếu inspect code của Google ra xem bạn sẽ dễ dàng nhận thấy Google chuyển đổi các HTML element sang Canvas, tạo ra nhiều lớp canvas chồng lên nhau, cách lớp canvas này sẽ chứa 1 vài phần nhỏ của hình gốc, sau đó kết hợp giữa hiệu ứng xoay (rorate) và transform vị trí cho đến khi chúng bị mờ đi đến mức 0.

Vậy chúng ta cũng sẽ làm với ý tưởng tương tự.

Step 1: Convert HTML Element sang Canvas

Hên là đã có một thư viện hơn 16k sao cho phép làm điều này html2canvas. Bây giờ chỉ cần dựng HTML lên để có được không gian của bãi chiến trường. Trong End Game Tony mang bộ mark 85 bạn nhớ tìm hình cho giống nhé.

Còn đây là the battle field của mình

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Với html2canvas bạn chỉ cần pass element cần chuyển vào trong hàm, hàm sẽ return về một promise với đối số là canvas được tạo.

html2canvas($(“.content”)[0]).then(canvas => {
//capture all div data as image
ctx = canvas.getContext(“2d”);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixelArr = imageData.data;
});

NOTE: Bạn lưu ý element truyền vào phải là HTML element khác thẻ img nhé.

Step 2: Tạo ra các lớp canvas

Sau bước một chúng ta đã có một mảng các pixel của hình ảnh. Việc còn lại chỉ đơn giản là phân số lượng pixel đó vào vài canvas khác nhau là xong.

Tuy nhiên để cho đẹp và hiệu ứng trông sẽ thật hơn nếu bạn làm nó “bay màu” từ đầu xuống chân, hoặc từ chân lên đầu, thay vì tan biến 1 cách ngẫu nhiên ko có tôn ti trật tự.

Nghĩa là chúng ta không thể chỉ đơn giản quất hàm Math.random được. Cần phải đánh trọng số cho việc phân tán các điểm ảnh.

Về cơ bản thì chúng ta sẽ tăng xác suất xuất hiện các điểm ảnh nằm ở phần đầu vào các canvases nằm trên. Tăng xác suất xuất hiện của các điểm ảnh ở phần thân vào các canvases nằm giữa, và tương tự cho phần chân.

Đồ thị biểu diễn nó đại khái như này

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Để làm được điều này thì cũng đã có 1 thư viện hỗ trợ – chance.js. Bạn xem thêm docs của nó nếu có hứng thú nhé, docs cũng dài với nhiều phết đấy.

Đây là hàm trả về mảng các điểm ảnh sau khi đã đánh trọng số.

function weightedRandomDistrib(peak) {
var prob = [], seq = [];
for(let i=0;i<canvasCount;i++) {
prob.push(Math.pow(canvasCount-Math.abs(peak-i),3));
seq.push(i);
}
return chance.weighted(seq, prob);
}

Tiếp theo là tạo ra các lớp canvas cho Thanos từ mảng trên rồi append vào document (nhớ là chồng lên cái ảnh gốc để ko bị lộ, position: absolute; các thứ vào nhé)

//put pixel info to imageDataArray (Weighted Distributed)
for (let i = 0; i < pixelArr.length; i+=4) {
//find the highest probability canvas the pixel should be in
let p = Math.floor((i/pixelArr.length) *canvasCount);
let a = imageDataArray[weightedRandomDistrib(p)];
a[i] = pixelArr[i];
a[i+1] = pixelArr[i+1];
a[i+2] = pixelArr[i+2];
a[i+3] = pixelArr[i+3];
}

//create canvas for each imageData and append to target element
for (let i = 0; i < canvasCount; i++) {
let c = newCanvasFromImageData(imageDataArray[i], canvas.width, canvas.height);
c.classList.add(“dust”);
$(“.wrapper”).append(c);
}

Đây là các lớp canvas theo thứ tự sau khi được tạo ra

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Làm hiệu ứng búng tay bay màu THANOS bằng Javascript

Step 3: Animation

Bước này chỉ cần thêm tí animation cho nó chuyển động các lớp canvas hạt bụi trên kia, như kiểu đang hấp hối bay màu.

Lúc này bạn cần ẩn ảnh gốc đi nhé.

//clear all children except the canvas
$(“.content”).children().not(“.dust”).fadeOut(3500);

Sau đó lặp từng cái canvas, lần lượt thêm vào 3 animations:

  • Blur: Có blur vào mới tạo ra được sự mượt mà khi chuyển động, để chuyển động ko bị “cứng”.
  • Transform: Transform cả vị trí lẫn xoay ảnh, để đẩy các điểm ảnh ra xa dần.
  • Fade out: Cho điểm ảnh mờ dần đến 0.

//apply animation
$(“.dust”).each( function(index){
animateBlur($(this),0.8,800);
setTimeout(() => {
animateTransform($(this),100,-100,chance.integer({ min: -15, max: 15 }),800+(110*index));
}, 70*index);
//remove the canvas from DOM tree when faded
$(this).delay(70*index).fadeOut((110*index)+800,”easeInQuint”,()=> {$( this ).remove();});
});

jQuery không hỗ trợ hiệu ứng blur, check phần final code mình đính kèm nếu bạn có hứng thú nhé.

Nhớ rằng class dust là lớp ảnh chứa các điểm ảnh dùng cho bay màu, phải đặt chồng lên nhau nhé.

.dust {
position: absolute;
}

Lời kết

Final source code mình đặt ở đây, mình thực hiện trên VueJS, nên nếu bạn có ý định chạy thử thì vào fork repo này về https://github.com/trandaison/fingerSnap

  • Chạy yarn install để cài các package.
  • Chạy yarn serve để chạy server node và vào localhost:8080 để xem.

Hướng dẫn chi tiết bằng Video:

Xem thêm:

Nguồn: trandaison

Reply