Efek Teks Menggunakan Blotter.js
Persiapan Proyek
Section titled Persiapan%20ProyekSebelum memulai proyek ini, unduh jQuery , Blotter.js dan ChannelSplitMaterial lalu simpan di dalam folder yang sama. Buat file index.html
, tulis template dasar HTML didalamnya dan tautkan semua dependensi yang sudah diunduh sebelumnya. Buat file script.js
untuk kode javascript nanti.
<html> <head> <title>Efek Teks Menggunakan Blotter.js</title> <script src="blotter.min.js"></script> <script src="channelSplitMaterial.js"></script> <style> /* Styling di sini */ </style> </head> <body> <!-- Kode di sini --> </body> <script src="jquery-3.3.1.min.js"></script> <script src="script.js"></script></html>
Struktur HTML
Section titled Struktur%20HTMLSebelum menuliskan kode javascript, tulis HTML untuk mendefinisikan area penempatan teks animasi.
<body> <div class="wrapper"> <div id="stage"> <!-- Di sini efek teks akan dibuat dan simpan melalui javascript --> </div> <div class="container"> <h1>Membuat teks animasi menggunakan Blotter.js</h1> <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit.</p> </div> </div></body>
Styling Layout
Section titled Styling%20LayoutKita tidak banyak melakukan styling di sini. Buat .wrapper
sebagai display: flex
untuk membuat konten berada di tengah layar dengan align-items: center
dan justify-content: center
.
Kita juga menulikan style untuk .blotter-item
yang akan menjadi teks animasi nantinya.
<style> html, body { margin: 0; padding: 0; width: 100%; height: 100%; } .wrapper { display: flex; align-items: center; justify-content: center; height: 100%; } #stage { position: relative; width: 700px; height: 600px; } .container { width: 400px; padding-left: 100px; } .blotter-item { display: inline-block; position: absolute; pointer-events: none; z-index: -1; }</style>
Saatnya Membuat Teks Efek
Section titled Saatnya%20Membuat%20Teks%20EfekBuka file script.js
, buat variables beserta property untuk menyimpan karakter yang nanti akan dianimasikan.
$(function () { "use strict"; var blotterText = [], blotter = [], material = [], scope = [], mRot, mOff, elem, // Karakter yang akan dibuat dan diberi efek letters = ["V", "I", "S", "U", "A", "L", "N", "A", "U", "T"], // Properti tiap karakter lProp = { size: [290, 98, 178, 47, 165, 88, 30, 35, 89, 190], posX: [28, 60, 80, 0, -5, 63, 9, 80, 29, 7], posY: [14, 10, 30, 77, 5, 67, 2, 8, 5, 55], };});
Setelah selesai membuat variable, looping semua karakter di dalam array letters
sebagai Blotter.Text
. Kita bisa atur font yang digunakan dengan parameter family
atau warna teks dengan parameter fill
saat menginisialisasi Blotter.text
.
Untuk dokumentasi parameter apa saja yang bisa ditambah, silakan baca dokumentasi Blotter.js
$(function () { // ... Kode Sebelumnya ...
// Loop berdasarkan banyak karakter di dalam array letters for (let l = 0; l < letters.length; l++) { // Assign tiap karakter beserta property-nya blotterText[l] = new Blotter.Text(letters[l], { family: "'Helvetica', 'Arial', sans-serif", size: lProp.size[l], fill: "#151515", weight: 900, paddingLeft: 80, paddingRight: 80, }); }}
Inisialisasi material untuk Blotter.text
, lalu terapkan material tersebut dengan masing-masing teks yang sudah dibuat sebelumnya sebagai objek Blotter
. Lalu buat dan simpan scope untuk semua karakter sebagai identifier saat nanti diterapkan dalam HTML.
for (let l = 0; l < letters.length; l++) { // ... Kode Sebelumnya ...
// Inisialisasi material untuk tiap karakter material[l] = new Blotter.ChannelSplitMaterial();
// Buat objek Blotter berdasarkan karakter dan material blotter[l] = new Blotter(material[l], { texts: blotterText[l] });
// Scope untuk tiap karakter scope[l] = blotter[l].forText(blotterText[l]);}
Buat elemen DOM dalam bentuk <div>
dengan ID sesuai index karakter dan property CSS yang ditulis sebelumnya untuk posisi karakter lalu append ke dalam #stage
menggunakan jQuery.
for (let l = 0; l < letters.length; l++) { // ... Kode Sebelumnya ...
// Membuat div untuk tiap karakter let blotterDOM = $("<div/>") .addClass("blotter-item") .attr("id", "blotter-" + l) .css({ top: lProp.posY[l] + "%", left: lProp.posX[l] + "%", }); $("stage").append(blotterDOM).clone();}
Setelah itu, kita ambil elemen DOM yang baru saja kita buat berdasarkan ID-nya, dan append ke scope karakter Blotter
untuk kita render.
for (let l = 0; l < letters.length; l++) { // ... Kode Sebelumnya ...
// Render semua karakter sesuai div yang sudah dibuat elem = document.getElementById("blotter-" + l); scope[l].appendTo(elem);}
Jika kita buka index.html
di browser, teks yang baru saja dibuat akan muncul di layar, tetapi teks tidak bergerak berdasarkan cursor seperti halaman utama Blotter.js. Itu karena kita belum membuat teks mendeteksi gerakan cursor.
Membuat Teks Berinteraksi
Section titled Membuat%20Teks%20BerinteraksiJika kalian membaca dokumentasi ChannelSplitMaterial , kita bisa mengatur offset dan rotation dari material tersebut. Dua parameter ini yang akan kita ubah menggunakan value dari posisi dan sudut cursor dengan masing-masing karakter.
Fungsi Mencari Jarak
Section titled Fungsi%20Mencari%20JarakKita buat fungsi dengan 3 parameter untuk menghitung jarak antara cursor dan elemen DOM karakter.
function calOffset(elem, mouseX, mouseY) { let distance = Math.floor( Math.sqrt( Math.pow(mouseX - (elem.offset().left + elem.width() / 2), 2) + Math.pow(mouseY - (elem.offset().top + elem.height() / 2), 2), ), ); let offset = distance / 1000; // Kita limit nilai offset hanya sampai 0.25 if (offset >= 0.25) { return (offset = 0.25); } return offset;}
Parameter elem
adalah elemen DOM yang ingin kita hitung jaraknya, parameter mouseX
dan mouseY
adalah posisi cursor yang akan kita ambil dari event mousemove
nantinya.
Setelah jarak antara cursor dan elemen DOM ditemukan, kita atur batas nilai offset hanya sampai 0.25
, karena kita tidak ingin teks bergerak terlalu jauh. (Offset ChannelSplitMaterial memiliki range dari 0 sampai 1).
Fungsi Mencari Sudut
Section titled Fungsi%20Mencari%20SudutSetelah mendapatkan jarak antara cursor dan elemen DOM, kita akan menghitung sudut yang akan kita gunakan sebagai rotation ChannelSplitMaterial.
Seperti halnya mencari jarak, fungsi ini juga membutuhkan 3 parameter yaitu elem
, mouseX
dan mouseY
.
function calRotation(elem, mouseX, mouseY) { let boxCenter = [ elem.offset().left + elem.width() / 2, elem.offset().top + elem.height() / 2, ]; let rad = Math.atan2(mouseX - boxCenter[0], mouseY - boxCenter[1]); return rad * (180 / Math.PI) * -1 + 90;}
Pasang Semua Di Event mousemove
Section titled Pasang%20Semua%20Di%20Event%20mousemove%7B%3Ajs%7DSetelah fungsi jarak dan sudut kita buat, kita pasang ke dalam event mousemove
menggunakan jQuery untuk mengatur offset dan rotation tiap ChannelSplitMaterial saat cursor kita bergerak.
$(document).mousemove(function (e) { let mX = e.pageX; // posisi X cursor let mY = e.pageY; // posisi Y cursor // Loop semua element blotter untuk kita simpan ke variabel box for (let l = 0; l < letters.length; l++) { let box = $("#blotter-" + l + " canvas"); // Kalkulasi sudut tiap element terhadap cursor mRot = calRotation(box, mX, mY); // Kalkulasi jarak tiap element terhadap cursor mOff = calOffset(box, mX, mY); // Reassign nilai rotation dan offset ke semua material material[l].uniforms.uRotation.value = mRot; material[l].uniforms.uOffset.value = mOff; }});
Hasil Akhir & Source Code
Section titled Hasil%20Akhir%20%26%20Source%20CodeDan selesai, coba buka kembali index.html
dan coba gerakkan cursor mengitari teks yang muncul. Sekarang rotasi dan offset efek ChannelSplitMaterial akan mengikuti cursor kalian.
Kalian bisa menemukan source code untuk contoh proyek di bawah. Semoga bermanfaat.
visualnaut/blotterjs-experiment
Experimenting with Blotter.js recreating their own homepage