5 poin oleh GN⁺ 2024-04-26 | 1 komentar | Bagikan ke WhatsApp
  • canvas-confetti adalah library klien untuk menjalankan animasi confetti berbasis canvas di halaman web, mendukung instalasi NPM maupun penyertaan langsung lewat CDN
  • API dasar confetti() mengatur jumlah partikel, sudut, sebaran, kecepatan, gravitasi, warna, bentuk, posisi, z-index, dan lainnya hanya dengan satu objek opsi; di lingkungan yang mendukung Promise, waktu selesai animasi juga bisa diterima
  • Untuk pengguna Reduced Motion, tersedia opsi disableForReducedMotion; nilainya secara default false, tetapi ada kemungkinan berubah pada rilis mayor mendatang
  • Dapat membuat bentuk kustom berbasis SVG Path dan teks, serta mengimplementasikan efek seperti emoji confetti selain bentuk bawaan square, circle, dan star
  • confetti.create() membuat instance pada canvas tertentu dan mendukung opsi global seperti resize dan useWorker, tetapi pada useWorker: true, kendali canvas dipindahkan ke web worker sehingga manipulasi dari main thread akan menyebabkan error

Cara instalasi dan eksekusi

  • Anda dapat melihat cara kerja library di halaman demo
  • Dapat diinstal sebagai paket NPM
npm install --save canvas-confetti
  • Dalam build proyek, dapat digunakan dengan require('canvas-confetti')
  • Library ini adalah komponen klien dan tidak berjalan di Node
    • README menjelaskan bahwa proyek harus dibuild dengan alat seperti webpack
  • Di halaman HTML, dapat disertakan langsung sebagai skrip CDN
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.4/…;
  • Saat menggunakan CDN, disarankan memakai versi terbaru pada saat disertakan ke proyek; daftar versi lengkap dapat dilihat di releases page

Dukungan Reduced Motion

  • Sebagian pengguna mungkin tidak menginginkan atau lebih memilih mengurangi gerakan di situs web, dan browser dapat menyampaikan preferensi ini melalui prefers-reduced-motion
  • Dengan opsi disableForReducedMotion, confetti dapat tidak ditampilkan bagi pengguna yang kesulitan dengan animasi yang mengganggu
  • Nilai default opsi ini saat ini adalah false
  • Perubahan nilai default sedang dipertimbangkan untuk rilis mayor mendatang, dan jika memiliki pendapat kuat, dapat disampaikan melalui issue
  • Jika confetti dinonaktifkan karena disableForReducedMotion diterapkan, Promise confetti() akan langsung resolve

API dasar dan perilaku Promise

  • Saat diinstal lewat NPM, library dapat di-require sebagai komponen klien dalam build proyek; pada versi CDN, library diekspos sebagai fungsi confetti di window
  • confetti([options]) menerima satu objek opsi opsional
  • Jika window.Promise tersedia, fungsi ini mengembalikan Promise yang memberi tahu saat animasi selesai
    • Di lingkungan seperti IE yang tidak memiliki Promise, fungsi ini mengembalikan null
    • Promise polyfill dapat digunakan
    • Implementasi Promise juga dapat diberikan langsung dalam bentuk confetti.Promise = MyPromise
  • Jika confetti dipanggil beberapa kali sebelum selesai, Promise yang sama akan dikembalikan setiap kali
  • Secara internal, elemen canvas yang sama digunakan kembali, dan confetti baru ditambahkan sambil melanjutkan animasi yang sudah ada
  • Promise yang dikembalikan oleh setiap pemanggilan akan resolve setelah semua animasi selesai

Opsi utama

  • particleCount: jumlah confetti yang ditembakkan, default 50
  • angle: sudut tembakan, default 90, dengan 90 berarti ke arah atas
  • spread: rentang sebaran dari pusat, default 45
  • startVelocity: kecepatan awal, default 45
  • decay: tingkat berkurangnya kecepatan, default 0.9
    • Harus dijaga di antara 0 dan 1; jika keluar dari rentang ini, kecepatan dapat meningkat
  • gravity: seberapa kuat partikel tertarik ke bawah, default 1
    • 0.5 berarti setengah gravitasi, dan karena tidak ada batasan, juga bisa dibuat bergerak ke atas
  • drift: tingkat pergeseran ke kiri atau kanan, default 0
    • Nilai negatif berarti ke kiri, nilai positif berarti ke kanan
  • flat: dapat mematikan efek miring dan bergoyang seperti confetti 3D di dunia nyata, default false
  • ticks: jumlah langkah pergerakan confetti, default 200
  • origin: posisi awal tembakan
    • origin.x: posisi x pada halaman, 0 berarti kiri, 1 berarti kanan, default 0.5
    • origin.y: posisi y pada halaman, 0 berarti atas, 1 berarti bawah, default 0.5
  • colors: array string warna dalam format HEX
  • shapes: array bentuk confetti
    • Nilai bawaan adalah square, circle, star
    • Secara default, square dan circle dicampur merata
    • Rasio campuran dapat diatur melalui proporsi array, misalnya ['circle', 'circle', 'square']
  • scalar: skala setiap partikel, default 1
  • zIndex: lapisan tampilan confetti, default 100
  • disableForReducedMotion: menonaktifkan confetti untuk pengguna yang memilih Reduced Motion

Membuat bentuk kustom

  • confetti.shapeFromPath({ path, matrix? }) membuat bentuk confetti kustom dari SVG Path string
  • Bentuk berbasis Path memiliki beberapa batasan
    • Semua path diperlakukan sebagai bentuk terisi, dan stroke path tidak diimplementasikan
    • Path dibatasi pada satu warna
    • Semua path memerlukan transform matrix yang valid
    • Perhitungan matrix memiliki biaya, jadi sebaiknya dihitung sekali per path selama pengembangan lalu di-cache
    • Matrix selalu sama untuk nilai path yang sama
    • Saat memperbarui library, sebaiknya matrix dibuat ulang dan di-cache kembali demi forward compatibility
    • Confetti berbasis path terbatas pada browser yang mendukung Path2D
  • Nilai kembaliannya adalah objek Shape, dan dapat langsung dimasukkan ke array shapes
var triangle = confetti.shapeFromPath({ path: 'M0 10 L5 0 L10 10z' });

confetti({
  shapes: [triangle]
});
  • confetti.shapeFromText({ text, scalar?, color?, fontFamily? }) membuat bentuk confetti berbasis teks dan dapat menggunakan emoji Unicode standar
  • Bentuk berbasis teks cocok untuk emoji confetti
    • Untuk confetti yang bergoyang, umumnya satu karakter yang mendekati persegi, terutama emoji, bekerja dengan baik
    • Karena teks dirasterisasi alih-alih digambar ulang setiap kali, perubahan skala besar setelah pembuatan dapat membuatnya tampak buram
    • Jika berencana menggunakan scalar pada opsi confetti, sebaiknya gunakan nilai scalar yang sama saat membuat shape
  • Opsi teks menerima text, scalar, color, dan fontFamily
    • Default fontFamily mengikuti praktik rendering emoji native OS dan fallback ke sans-serif
    • Saat menggunakan web font, font harus sudah dimuat sebelum rendering confetti
var scalar = 2;
var pineapple = confetti.shapeFromText({ text: '🍍', scalar });

confetti({
  shapes: [pineapple],
  scalar
});

Canvas kustom dan rendering worker

  • confetti.create(canvas, [globalOptions]) membuat instance fungsi confetti yang menggunakan canvas tertentu
  • Berguna saat ingin membatasi confetti hanya pada area tertentu di halaman
  • Secara default, metode ini tidak mengubah canvas selain menggambar di atasnya
  • Jika ukuran tampilan canvas diubah lewat CSS, ukuran gambar canvas sebenarnya tidak ikut berubah sehingga dapat meregang dan terlihat buram
    • Jika opsi resize diaktifkan, library akan menyesuaikan ukuran gambar canvas dan merespons perubahan ukuran jendela atau rotasi perangkat mobile
  • Jangan menginisialisasi instance confetti berkali-kali dengan elemen canvas yang sama; simpan instance kustom yang sudah dibuat
  • Opsi global

    • resize: menentukan apakah ukuran gambar canvas diatur dan dipertahankan sesuai perubahan jendela, default false
    • useWorker: jika memungkinkan, merender animasi confetti secara asinkron di web worker, default false
    • Pada default, animasi selalu berjalan di main thread
    • Jika didukung browser, animasi berjalan di luar main thread agar tidak memblokir main thread
    • Pada browser yang tidak mendukung, nilai ini diabaikan
    • disableForReducedMotion: membuat instance confetti tersebut selalu menghormati permintaan Reduced Motion pengguna
  • Catatan untuk useWorker: true

    • Jika memakai useWorker: true, kendali canvas dipindahkan ke web worker
    • Dalam kondisi ini, selain menghapus canvas dari DOM, manipulasi dari main thread akan menyebabkan error
    • Jika perlu memanipulasi canvas secara langsung, jangan gunakan opsi useWorker
    var myCanvas = document.createElement('canvas');
    document.body.appendChild(myCanvas);
    
    var myConfetti = confetti.create(myCanvas, {
      resize: true,
      useWorker: true
    });
    myConfetti({
      particleCount: 100,
      spread: 160
    });
    

Menghentikan animasi dan pola contoh

  • confetti.reset() menghentikan animasi, menghapus semua confetti, dan langsung me-resolve Promise yang sedang menunggu
  • Instance terpisah yang dibuat dengan confetti.create() memiliki metode reset sendiri
confetti();

setTimeout(() => {
  confetti.reset();
}, 100);
  • Eksekusi dasar dilakukan dengan memanggil confetti() tanpa argumen
  • Banyak confetti dapat ditembakkan dengan particleCount: 150
  • Confetti yang menyebar luas dapat dibuat dengan spread: 180
  • Menggunakan Math.random() pada origin dapat membuat efek ledakan kecil dari posisi acak di halaman
  • Contoh README menunjukkan pola yang menggunakan requestAnimationFrame untuk terus menembakkan confetti dari tepi kiri dan kanan selama 30 detik

1 komentar

 
GN⁺ 2024-04-26
Komentar Hacker News
  • Trik membuat animasi yang berperforma baik di sini adalah menggambarnya di canvas, lalu menaruh canvas itu di depan semua elemen lain, tetapi mematikan pointer events agar pengguna tetap bisa berinteraksi dengan halaman

    • Benar. Menonaktifkan pointer events ternyata berguna dalam banyak situasi
    • Ini disebut trik untuk animasi berperforma baik, tetapi saya tidak bisa langsung membayangkan cara lain untuk mengimplementasikan hal seperti ini. Implementasi naifnya akan seperti apa?
  • Mengingatkan pada masa-masa indah ketika saya membuat web di SMA pada 2015. Saya membuat situs web kecil dengan confetti untuk mengajak seorang cewek pergi ke homecoming bersama, dan kalau dipikir lagi itu sangat nerd
    Saat itu, membuat situs web untuk seorang anak terasa seperti kekuatan super. Dari waktunya, sepertinya bukan paket ini, tetapi animasinya cukup bagus
    Saya suka proyek-proyek kecil yang murni menyenangkan seperti ini. Itu juga alasan saya mulai memprogram, dan sampai sekarang masih menjadi pendorong besar

    • Berhasil? Dia bilang yes?
  • Saya suka bagian ini di halaman demo:

    If you happened to get curious and changed the particle count to 400 or so, you saw something disappointing. An even "flattened cone" look to the confetti, making it look way too perfect and ruining the illusion.

    Obsesi terhadap detail seperti ini jarang, dan setiap kali menemukannya—entah di visualisasi statistik, properti film, atau confetti situs web—rasanya berharga
    Sebagai solusinya, saya mungkin akan mencoba mengubah distribusi acaknya sendiri. Perlu dicek langsung, tetapi dugaan saya distribusi di dunia nyata lebih mendekati distribusi Gaussian

  • Kami menambahkan confetti di dashboard admin yang muncul saat staf sales berhasil menutup penjualan, dan ternyata cukup menyenangkan serta memotivasi

  • Seandainya fungsi reset dinamai confetti.resetti()

    • Karena ini JavaScript, setidaknya secara lokal bisa diperbaiki dengan mudah lewat "confetti.resetti = confetti.reset"
      Pendekatan ini mungkin punya sedikit biaya rekayasa perangkat lunak, tetapi seperti yang jelas bagi pengamat yang cermat, manfaatnya jauh lebih besar, jadi menurut saya lakukan saja
    • Orang ini harus diberi pekerjaan. Kalau sudah punya pekerjaan, setidaknya beri dia kukis
    • Bisa juga coba membuat PR
  • Terlepas dari ini pustaka yang keren dan berguna, ini juga contoh bagus dari modul dalam yang dibicarakan John Ousterhout dalam Philosophy of Software Design
    Versi paling dasar, yaitu memunculkan confetti, sangat mudah digunakan, tetapi kalau melihat opsinya, ada cukup banyak hal yang bisa didapat: salju, warna tertentu, berbagai efek confetti, dan lain-lain

  • Keren dan impresif
    Pada saat yang sama, saya tidak ingin melihatnya berjalan di situs web apa pun yang saya gunakan. Terutama popup newsletter atau confetti yang muncul saat memasukkan barang ke keranjang belanja

    • Anehnya, efek ini bisa digunakan dengan cukup efektif. Entah untuk pendekatan layar penuh seperti ini, tetapi di software manajemen proyek yang dipakai klien yang baru-baru ini saya kunjungi, ketika sebuah item ditutup, tombolnya berubah hijau dan efek seperti ini muncul
      Efeknya halus tetapi cukup terlihat, dan setelah rapat saya dan developer lain sama-sama berkata, “efeknya lumayan bagus ya.” Rasanya menyampaikan, “Oke, ada kemajuan!”
      Namun cukup buat bisa dipilih saja

    • Penggunaan yang sah mungkin seperti tombol suka di YouTube. Ada animasi yang bagus, dan di aplikasi mobile perangkatnya juga bergetar. Itu pengalaman pengguna yang sangat menyenangkan

    • https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pref...

      Di browser, pengguna bisa mengatur preferensi mengurangi gerakan. Operator situs dan maintainer pustaka harus menghormati ini saat mengimplementasikan hal seperti confetti. Pustaka ini secara khusus punya opsi disableForReducedMotion

    • Ada tempat yang cocok untuk efek seperti ini. Misalnya saat menyelesaikan game

    • Kami memakai pustaka ini saat seseorang memenuhi kualifikasi tertentu. Efeknya cukup bagus untuk alur onboarding

  • Ada juga pustaka Party.js: https://party.js.org/

    • Kalau begitu, mana yang lebih kecil?
      10,4 kB minified, 4,2 kB minified + Gzip
      https://bundlephobia.com/package/canvas-confetti@1.9.2

      28,3 kB minified, 7,4 kB minified + Gzip
      https://bundlephobia.com/package/party-js@2.2.0

      Namun, saya tidak terlalu tahu bagaimana bundlephobia bekerja. Bisa jadi itu tidak menunjukkan ukuran akhir paket dengan paling baik. Mungkin tidak mencerminkan code splitting atau hanya mengimpor bagian yang diperlukan. Saya hanya melihatnya sebagai gambaran cepat dan kasar

      Berdasarkan Gzip, confetti tampaknya unggul beberapa KB, jadi kecuali benar-benar perlu memeras beberapa KB itu, keduanya bisa dipilih tergantung fitur yang dibutuhkan

    • Skrip di artikel asli tampak jauh lebih berperforma baik di mobile

    • Pustaka di artikel asli tampak jauh lebih berperforma. Di komputer kerja lama saya, Party.js mulai terasa sedikit lag hanya setelah 3 klik
      canvas-confetti baru mulai lag setelah saya mengklik terus tanpa henti selama beberapa detik, mungkin ketika sudah membuat lebih dari 30 instance confetti dan banyak partikel

  • Saya bermain teka-teki silang di downforacross.com, dan saat puzzle selesai, confetti muncul
    Mungkin bisa memakai sebagian kode yang lebih berperforma di sini agar terasa lebih ringan
    Namun, kecuali untuk situs “fun” atau penggunaan yang jarang, saya tidak ingin melihat animasi seperti ini muncul di mana-mana

  • Menurut saya tidak perlu memasukkan kata useful di judul

    • Bagaimana kalau sebagai alat motivasi sekaligus cara memastikan kode berhasil dikompilasi: https://squint-cljs.github.io/squint/
    • Benar. Tapi justru kata itu membuat saya benar-benar tertarik, dan lucunya ternyata tidak terlalu berguna. Saya rekomendasikan
    • Berguna seperti confetti di dunia nyata, jadi 100% berguna