Efek Teks Menggunakan Blotter.js

Ditulis

Sebelum memulai proyek ini, unduh jQuery Export Square , Blotter.js Export Square dan ChannelSplitMaterial Export Square 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.

index.html
<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>

Sebelum menuliskan kode javascript, tulis HTML untuk mendefinisikan area penempatan teks animasi.

index.html
<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>

Kita 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.

index.html
<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>

Buka file script.js, buat variables beserta property untuk menyimpan karakter yang nanti akan dianimasikan.

script.js
$(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 Export Square

script.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.

script.js
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.

script.js
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.

script.js
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.

Jika kalian membaca dokumentasi ChannelSplitMaterial Export Square , 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.

Kita buat fungsi dengan 3 parameter untuk menghitung jarak antara cursor dan elemen DOM karakter.

script.js
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).

Setelah 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.

script.js
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;
}

Setelah 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.

script.js
$(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;
}
});

Dan selesai, coba buka kembali index.html dan coba gerakkan cursor mengitari teks yang muncul. Sekarang rotasi dan offset efek ChannelSplitMaterial akan mengikuti cursor kalian.

Hasil Akhir dari Text Effect dengan Blotter.js

Kalian bisa menemukan source code untuk contoh proyek di bawah. Semoga bermanfaat.

Document Code

visualnaut/blotterjs-experiment Export Square

Experimenting with Blotter.js recreating their own homepage