HTML5+JS
Efek dibuat menggunakan JavaScript vanilla pada elemen canvas HTML5. Di bagian ini, kita akan membahas dasar-dasarnya: menggambar bentuk, menggambar dengan iterasi, dan menambahkan gerakan.
Menggambar Bentuk
Section titled “Menggambar Bentuk”Untuk tutorial ini saya akan menggunakan template lightscript generik:
<head> <meta description="Template"/> <meta publisher="WhirlwindFX" /></head>
<body style="margin: 0; padding: 0;"> <canvas id="exCanvas" width="320" height="200"></canvas></body>
<script> // Get the canvas element from the DOM var c = document.getElementById("exCanvas"); var ctx = c.getContext("2d");
var width = 320; var height = 200; var hue = 0;
function update() { // Code goes here window.requestAnimationFrame(update); }
window.requestAnimationFrame(update);</script>Baik menggunakan satu garis maupun banyak, prosesnya tetap sama.
- ctx.beginPath() memulai bentuk Anda
- ctx.moveTo(x, y) menetapkan titik pertama
- ctx.lineTo(x, y) menetapkan titik berikutnya dan garis kembali ke yang pertama. Gunakan beberapa lineTo untuk menggambar bentuk yang lebih besar.
- Atur ctx.strokeStyle dan/atau ctx.fillStyle (jika bentuknya tertutup)
- Gunakan ctx.stroke() untuk menggambar garis, dan ctx.fill() untuk mengisi bentuk yang tertutup. Penting untuk dicatat bahwa hingga titik ini, semuanya masih bersifat hipotetis - tidak ada yang digambar sampai perintah-perintah ini dieksekusi.
Berikut tiga contoh menggunakan garis:
function update() { // One Line ctx.beginPath(); ctx.moveTo(30, 30); ctx.lineTo(30, 170); ctx.strokeStyle = "blue"; ctx.stroke();
// L ctx.beginPath(); ctx.moveTo(80, 30); ctx.lineTo(80, 100); ctx.lineTo(120, 100); ctx.strokeStyle = "blue"; ctx.stroke();
// Filled Triangle ctx.beginPath(); ctx.moveTo(130, 30); ctx.lineTo(130, 100); ctx.lineTo(170, 100); ctx.lineTo(130, 30); ctx.fillStyle = "red"; ctx.strokeStyle = "blue"; ctx.fill(); ctx.stroke();
window.requestAnimationFrame(update);}
Penting untuk dicatat urutan penggambaran di sini: segitiga yang terisi digambar terakhir, sehingga akan menutupi dua bentuk lainnya jika berada di posisi yang sama. Selain itu, stroke pada segitiga digambar setelah fill. Jika kita membalik langkah-langkah ini, bagian dalam stroke akan tertutup oleh fill merah.
Persegi Panjang
Section titled “Persegi Panjang”Persegi panjang sederhana dan berguna, terutama untuk resolusi rata-rata keyboard RGB. Prosesnya mirip dengan menggambar garis - cukup ganti perintah moveTo dan lineTo dengan rect(x, y, width, height).
function update() { // Basic Square ctx.beginPath(); ctx.rect(30, 30, 75, 75); ctx.strokeStyle = "blue"; ctx.stroke();
// Filled Rectangle ctx.beginPath(); ctx.rect(125, 30, 125, 100); ctx.fillStyle = "red"; ctx.strokeStyle = "blue"; ctx.fill(); ctx.stroke();
window.requestAnimationFrame(update); }
Busur digambar dengan memutar titik luar di sekitar titik pusat, dan dapat digunakan untuk membuat lingkaran penuh. Perintah busur adalah ctx.arc(x, y, radius, sudut awal, sudut akhir), di mana kedua ukuran sudut diberikan dalam radian. Tidak seperti persegi panjang, busur digambar dengan asal (x, y) di tengah busur.
function update() { // Half-circle ctx.beginPath(); ctx.arc(70, 100, 30, 0, Math.PI); ctx.strokeStyle = "blue"; ctx.stroke();
// 3/4 circle ctx.beginPath(); ctx.arc(140, 100, 30, 0, Math.PI * (3/2)); ctx.strokeStyle = "blue"; ctx.stroke();
// Full circle ctx.beginPath(); ctx.arc(210, 100, 30, 0, Math.PI * 2); ctx.strokeStyle = "blue"; ctx.stroke(); ctx.fillStyle = "red"; ctx.fill();
window.requestAnimationFrame(update); }
Seperti yang Anda lihat, busur digambar searah jarum jam secara default. Ini dapat dibalik dengan sudut akhir yang lebih kecil dari sudut awal, atau dengan menambahkan “true” sebagai argumen terakhir ke metode ctx.arc().
Menggambar Dengan Iterasi
Section titled “Menggambar Dengan Iterasi”Menggambar tiga bentuk secara manual dapat dengan mudah membutuhkan dua puluh baris kode, jadi jika Anda perlu menggambar seratus bentuk, kita memerlukan pendekatan yang lebih efisien. Loop dalam JavaScript adalah cara sederhana untuk mengulang tugas, dan dapat diterapkan pada penggambaran juga.
Berikut adalah contoh menggunakan for-loop untuk menggambar baris kotak-kotak berselang:
function update() {
for(let i = 0; i < 8; i++){
// 1. Create rectangle path and draw the stroke for each. ctx.beginPath(); ctx.rect(i * 20, 20, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 2. If 'i' is even, the fillStyle is black. Otherwise it's white. if(i % 2 == 0){ ctx.fillStyle = "black"; } else { ctx.fillStyle = "white"; } // 3. Fill the shape after setting the fillStyle. ctx.fill(); }
window.requestAnimationFrame(update); }
Berikut adalah contoh while-loop untuk menggambar grid berselang. Saya akan mengubah lightness kotak hitam dan hue kotak putih sedikit dalam setiap iterasi menggunakan template literal.
function update() {
var i = 0;
while(i < 16){
// 1. X and Y calculations with 'row' and 'column' // This operation rounds the result down to the nearest integer. For i = (0-3) the row will be 0, for i = (4-7) the row will be 1, and so on var iRow = Math.floor(i / 4); // This operation finds the remainder after division, limiting column to the (0-3) range. var iCol = i % 4; // Multiply by the square width to find this square's x-origin var ix = iCol * 20; // Multiply by the square height to find this square's y-origin var iy = iRow * 20;
// 2. Path and stroke ctx.beginPath(); ctx.rect(ix, iy, 20, 20); ctx.strokeStyle = "black"; ctx.stroke();
// 3. If the row is even, every other square is filled black. If odd, switch the black squares. Each iteration adds a small amount of the lightness component to the black, and hue to the white. if(iRow % 2 == 0){ if(i % 2 == 0){ // 'Black' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } else { // 'White' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } } else { if(i % 2 == 0){ // 'White' ctx.fillStyle = `hsl(${10 * i}, 100%, 50%)`; } else { // 'Black' ctx.fillStyle = `hsl(1, 0%, ${5 * i}%)` } }
ctx.fill(); i++; }
window.requestAnimationFrame(update); }
Menambahkan Gerakan
Section titled “Menambahkan Gerakan”Animasi dalam canvas hanya dibatasi oleh imajinasi dan pengetahuan matematika Anda. Jika Anda merasa kurang dalam trigonometri atau geometri, saya sarankan untuk melakukan sedikit riset agar dapat meningkatkan kemampuan Anda ke level berikutnya. Dalam beberapa contoh berikutnya, saya akan mengambil lingkaran yang tidak bergerak dan melampirkan setiap variabel yang mungkin pada gerakan osilasi sederhana.
Standar emas untuk osilasi (gerakan bolak-balik yang teratur) adalah mengambil sin() atau cosinus() dari timer. Kedua operasi akan mengembalikan nilai antara -1 dan 1 untuk NILAI APA PUN yang dimasukkan, bahkan jika hanya terus menghitung naik. Satu-satunya perbedaan antara keduanya adalah bahwa mereka sedikit tidak sinkron - ketika cos adalah 0 sin adalah -1 atau 1, dan sebaliknya. Kita dapat menggunakan ini untuk keuntungan kita dalam animasi ini -
function update() {
// Find current time in milliseconds, then divide to slow down the animation speed let time = Date.now() / 100;
// Draw a background so the old shapes don't stick around ctx.fillStyle = "white"; ctx.fillRect(0, 0, 320,200);
ctx.beginPath();
//USE ONE EXAMPLE AT A TIME // 1st example - side to side, y is constant ctx.arc(15 * Math.cos(time) + 160, 100, 30, 0, Math.PI * 2); // 2nd example - up and down, x is constant ctx.arc(160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2); // 3rd example - circle, x and y are variable ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30, 0, Math.PI * 2);
ctx.fillStyle = "black"; ctx.fill();
window.requestAnimationFrame(update); }Kiri-Kanan
Section titled “Kiri-Kanan”
Atas-Bawah
Section titled “Atas-Bawah”
Lingkaran Penuh
Section titled “Lingkaran Penuh”
Kita hanya memiliki beberapa atribut lagi yang perlu diubah seiring waktu - radius lingkaran, fill, dan stroke. Saya akan membiarkan sudut busur untuk saat ini agar bentuknya tetap sederhana karena sisanya akan cukup mencolok.
function update() {
let time = Date.now() / 100;
ctx.fillStyle = "white"; ctx.fillRect(0, 0, 320,200);
ctx.beginPath(); ctx.arc(15 * Math.cos(time) + 160, 15 * Math.sin(time) + 100, 30 + 15 * Math.sin(time), 0, Math.PI * 2);
ctx.fillStyle = `hsl(${180 + 180 * Math.cos(time)}, 100%, 50%)`; ctx.fill();
ctx.strokeStyle = `hsl(${180 + 180 * Math.sin(time)}, 100%, 50%)`; ctx.stroke();
window.requestAnimationFrame(update); }
Setiap atribut dari setiap bentuk yang telah kita buat sejauh ini dapat diubah seiring waktu, dan setiap animasi yang saya buat adalah kombinasi dari keterampilan di atas. Untuk lebih detail tentang membuat animasi yang dapat digunakan kembali dan efisien, lihat halaman Callbacks kami!