5 puan yazan GN⁺ 2024-04-26 | 1 yorum | WhatsApp'ta paylaş
  • canvas-confetti, web sayfalarında canvas tabanlı confetti animasyonları çalıştıran istemci tarafı bir kütüphanedir; hem NPM kurulumu hem de CDN üzerinden doğrudan ekleme destekler
  • Temel confetti() API’si, tek bir seçenek nesnesiyle parçacık sayısı, açı, yayılım, hız, yerçekimi, renk, şekil, konum, z-index gibi ayarları düzenler; Promise destekleyen ortamlarda animasyonun tamamlanma anı alınabilir
  • Reduced Motion kullanıcıları için disableForReducedMotion seçeneğini sunar; bu değer varsayılan olarak false olsa da ilerideki bir major sürümde değişme ihtimali vardır
  • SVG Path ve metin tabanlı özel şekiller oluşturulabilir; square, circle, star varsayılan şekillerine ek olarak emoji confetti gibi efektler de uygulanabilir
  • confetti.create() belirli bir canvas üzerinde instance oluşturur ve resize, useWorker gibi global seçenekleri destekler; ancak useWorker: true olduğunda canvas kontrolü web worker’a devredilir ve ana thread’den müdahale edilirse hata oluşur

Kurulum ve çalıştırma yöntemi

  • Kütüphanenin nasıl çalıştığını demo sayfasında görebilirsiniz
  • NPM paketi olarak kurulabilir
npm install --save canvas-confetti
  • Proje build’lerinde require('canvas-confetti') ile kullanılabilir
  • Bu kütüphane bir istemci bileşenidir ve Node üzerinde çalışmaz
    • README, projenin webpack gibi araçlarla build edilmesi gerektiğini belirtir
  • HTML sayfasına CDN script’i olarak doğrudan eklenebilir
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.4/…;
  • CDN kullanırken projeye eklediğiniz andaki en güncel sürümü kullanmanız önerilir; tüm sürümler releases page üzerinden görülebilir

Reduced Motion desteği

  • Bazı kullanıcılar web sitelerindeki hareketi istemeyebilir veya azaltmayı tercih edebilir; tarayıcılar bunu prefers-reduced-motion ile iletebilir
  • disableForReducedMotion seçeneği kullanıldığında, rahatsız edici animasyonlar konusunda zorlanan kullanıcılara confetti gösterilmeyebilir
  • Bu seçeneğin mevcut varsayılan değeri falsetur
  • İlerideki bir major sürümde varsayılan değerin değiştirilmesi değerlendiriliyor; güçlü bir görüşünüz varsa issue olarak iletebilirsiniz
  • disableForReducedMotion uygulanıp confetti devre dışı bırakılırsa confetti() Promise’i hemen resolve olur

Temel API ve Promise davranışı

  • NPM ile kurulduğunda proje build’inde istemci bileşeni olarak require edilebilir; CDN sürümünde ise window üzerindeki confetti fonksiyonu olarak sunulur
  • confetti([options]) isteğe bağlı tek bir seçenek nesnesi alır
  • window.Promise varsa animasyonun tamamlandığını bildiren bir Promise döndürür
    • Promise olmayan IE gibi ortamlarda null döndürür
    • Promise polyfill’i kullanılabilir
    • confetti.Promise = MyPromise biçiminde Promise implementasyonunu doğrudan sağlayabilirsiniz
  • Tamamlanmadan önce confetti birden çok kez çağrılırsa her seferinde aynı Promise döndürülür
  • Dahili olarak aynı canvas öğesini yeniden kullanır ve mevcut animasyona devam ederken yeni confetti ekler
  • Her çağrının döndürdüğü Promise, tüm animasyonlar bittikten sonra resolve olur

Başlıca seçenekler

  • particleCount: fırlatılacak confetti sayısı, varsayılan 50
  • angle: fırlatma açısı, varsayılan 90; 90 yukarıyı ifade eder
  • spread: merkezden yayılma aralığı, varsayılan 45
  • startVelocity: başlangıç hızı, varsayılan 45
  • decay: hızın azalma oranı, varsayılan 0.9
    • 0 ile 1 arasında tutulmalıdır; aralığın dışına çıkarsa hız artabilir
  • gravity: parçacıkların aşağı çekilme derecesi, varsayılan 1
    • 0.5 yarım yerçekimi anlamına gelir; sınır olmadığından yukarı çıkacak şekilde de ayarlanabilir
  • drift: sağa-sola sürüklenme derecesi, varsayılan 0
    • Negatif değer sol, pozitif değer sağ anlamına gelir
  • flat: gerçek 3D confetti gibi eğilme ve sallanma efektini kapatabilir; varsayılan false
  • ticks: confetti’nin hareket ettiği adım sayısı, varsayılan 200
  • origin: fırlatmanın başlangıç konumu
    • origin.x: sayfadaki x konumu; 0 sol, 1 sağ, varsayılan 0.5
    • origin.y: sayfadaki y konumu; 0 üst, 1 alt, varsayılan 0.5
  • colors: HEX biçiminde renk string’leri dizisi
  • shapes: confetti şekilleri dizisi
    • Varsayılan yerleşik değerler square, circle, star
    • Varsayılan olarak square ve circle eşit oranda karıştırılır
    • ['circle', 'circle', 'square'] gibi dizi oranlarıyla karışım oranı ayarlanabilir
  • scalar: her parçacığın ölçeği, varsayılan 1
  • zIndex: confetti gösterim katmanı, varsayılan 100
  • disableForReducedMotion: Reduced Motion tercih eden kullanıcılar için confetti’yi devre dışı bırakır

Özel şekil oluşturma

  • confetti.shapeFromPath({ path, matrix? }), SVG Path string ile özel confetti şekli oluşturur
  • Path tabanlı şekillerde bazı kısıtlamalar vardır
    • Tüm path’ler dolu şekil olarak işlenir; stroke path uygulanmamıştır
    • Path tek renkle sınırlıdır
    • Tüm path’ler geçerli bir transform matrix gerektirir
    • Matrix hesaplaması maliyetli olduğundan geliştirme sırasında her path için bir kez hesaplayıp cache’lemek önerilir
    • Matrix aynı path değeri için her zaman aynıdır
    • Kütüphaneyi güncellediğinizde forward compatibility için matrix’i yeniden oluşturup cache’lemek önerilir
    • Path tabanlı confetti, Path2D destekleyen tarayıcılarla sınırlıdır
  • Dönüş değeri bir Shape nesnesidir ve doğrudan shapes dizisine eklenerek kullanılabilir
var triangle = confetti.shapeFromPath({ path: 'M0 10 L5 0 L10 10z' });

confetti({
  shapes: [triangle]
});
  • confetti.shapeFromText({ text, scalar?, color?, fontFamily? }) metin tabanlı confetti şekli oluşturur; standart Unicode emoji kullanılabilir
  • Metin tabanlı şekiller emoji confetti için uygundur
    • Sallanan confetti için genellikle kareye yakın tek karakterler, özellikle emoji’ler iyi uyar
    • Metni her seferinde çizmek yerine rasterize ettiği için, oluşturduktan sonra ölçek çok büyütülürse bulanıklaşabilir
    • Confetti seçeneklerinde scalar kullanmayı planlıyorsanız shape oluştururken aynı scalar değerini kullanmanız önerilir
  • Metin seçenekleri text, scalar, color, fontFamily alır
    • fontFamily varsayılanı, yerel OS emoji render etme pratiklerini izler ve sans-serife fallback yapar
    • Web fontu kullanırken font, confetti render edilmeden önce yüklenmiş olmalıdır
var scalar = 2;
var pineapple = confetti.shapeFromText({ text: '🍍', scalar });

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

Özel canvas ve worker render etme

  • confetti.create(canvas, [globalOptions]), belirli bir canvas’ı kullanan bir confetti fonksiyonu instance’ı oluşturur
  • Confetti’yi sayfa içindeki belirli bir alanla sınırlamak istediğinizde kullanışlıdır
  • Varsayılan olarak bu metot, canvas’a çizim yapmak dışında canvas’ı değiştirmez
  • Canvas’ın görüntü boyutu CSS ile değiştirildiğinde gerçek canvas görüntü boyutu değişmez; bu da görüntünün esneyip bulanıklaşmasına yol açabilir
    • resize seçeneği açıldığında kütüphane canvas görüntü boyutunu eşleştirir, pencere boyutu değişimlerine ve mobil döndürmeye de yanıt verir
  • Aynı canvas öğesiyle confetti instance’ını birden fazla kez başlatmayın; oluşturduğunuz özel instance’ı saklamalısınız
  • Global seçenekler

    • resize: canvas görüntü boyutunu ayarlayıp pencere değişikliklerine göre koruyup korumayacağını belirler, varsayılan false
    • useWorker: mümkün olduğunda confetti animasyonunu asenkron bir web worker’da render eder, varsayılan false
    • Varsayılan durumda animasyon her zaman ana thread’de çalışır
    • Tarayıcı destekliyorsa ana thread’i engellememek için animasyon ana thread dışında çalıştırılır
    • Desteklemeyen tarayıcılarda bu değer yok sayılır
    • disableForReducedMotion: ilgili confetti instance’ının kullanıcının Reduced Motion isteğine her zaman saygı göstermesini sağlar
  • useWorker: true için dikkat edilmesi gerekenler

    • useWorker: true kullanıldığında canvas kontrolü web worker’a devredilir
    • Bu durumda canvas’ı DOM’dan kaldırmak dışında ana thread’den müdahale etmek hata oluşturur
    • Canvas’ı doğrudan manipüle etmeniz gerekiyorsa useWorker seçeneğini kullanmamalısınız
    var myCanvas = document.createElement('canvas');
    document.body.appendChild(myCanvas);
    
    var myConfetti = confetti.create(myCanvas, {
      resize: true,
      useWorker: true
    });
    myConfetti({
      particleCount: 100,
      spread: 160
    });
    

Animasyonu durdurma ve örnek desenler

  • confetti.reset() animasyonu durdurur, tüm confetti’leri temizler ve bekleyen Promise’leri hemen resolve eder
  • confetti.create() ile oluşturulan ayrı instance’ın kendi reset metodu vardır
confetti();

setTimeout(() => {
  confetti.reset();
}, 100);
  • Temel çalıştırma, argümansız confetti() çağırmaktır
  • particleCount: 150 ile çok sayıda confetti fırlatılabilir
  • spread: 180 ile geniş alana yayılan confetti oluşturulabilir
  • origin içinde Math.random() kullanıldığında sayfanın rastgele konumlarında küçük patlama efektleri oluşturulabilir
  • README örneği, requestAnimationFrame kullanarak 30 saniye boyunca sol ve sağ kenarlardan sürekli confetti fırlatan bir deseni gösterir

1 yorum

 
GN⁺ 2024-04-26
Hacker News yorumları
  • Burada performanslı animasyon yapmanın püf noktası, canvas’a çizip sonra o canvas’ı diğer tüm öğelerin önüne koymak, ama sayfayla etkileşime devam edilebilmesi için pointer events’i kapatmak

    • Doğru. Pointer events’i devre dışı bırakmak şaşırtıcı derecede çok işe yarıyor
    • Buna performanslı animasyon için bir püf noktası denmiş ama bunu uygulamanın başka bir yolu aklıma pek gelmiyor. Naif bir uygulama nasıl görünürdü?
  • 2015’te lisede web geliştirdiğim güzel günleri hatırlattı. Homecoming’e birlikte gitmeyi teklif etmek için bir kıza konfetili küçük bir web sitesi yapmıştım; şimdi dönüp bakınca aşırı nerd’ceymiş
    O zamanlar bir çocuk için web sitesi yapmak süper güç gibi geliyordu. Zamanlama açısından bu paket değildi sanırım ama animasyon epey iyiydi
    Böyle safça keyif veren küçük projeleri seviyorum. Programlamaya başlama nedenim de buydu, hâlâ da büyük bir motivasyon kaynağı

    • Başarılı oldu mu? Kız evet dedi mi?
  • Demo sayfasındaki şu kısmı sevdim:

    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.

    Bu tür detay takıntısı nadir; ister istatistik görselleştirmesi olsun, ister film aksesuarı, ister web sitesi konfeti efekti, karşıma çıktığında çok değerli geliyor
    Çözüm olarak rastgele dağılımın kendisini değiştirmeyi denerdim. Gerçekten test ederdim ama gerçek hayattaki dağılımın Gauss dağılımına daha yakın olacağını tahmin ediyorum

  • Satış temsilcisi satışı kapattığında çıkan yönetici paneli konfeti efekti ekledik; beklenmedik şekilde eğlenceli ve motive edici oluyor

  • reset fonksiyonuna confetti.resetti() deseler iyi olurdu

    • JavaScript olduğu için en azından yerelde "confetti.resetti = confetti.reset" ile basitçe düzeltebilirsin
      Bu yaklaşımın biraz yazılım mühendisliği maliyeti olur elbette, ama dikkatli her gözlemcinin açıkça görebileceği gibi getirisi ezici biçimde büyük, o yüzden bence yapılmalı
    • Bu kişiye iş vermek lazım. Zaten işi varsa en azından bir kurabiye vermek lazım
    • Bir PR açmayı da deneyebilirsin
  • Güzel ve kullanışlı bir kütüphane olmasının yanında, John Ousterhout’un Philosophy of Software Design’da bahsettiği derin modül için iyi bir örnek
    En temel sürüm, yani konfeti çağırma işlevi çok kolay kullanılıyor; ama seçeneklere bakınca kar, belirli renkler, çeşitli konfeti efektleri gibi epey şey elde edilebiliyor

  • Güzel ve etkileyici
    Aynı zamanda kullandığım hiçbir web sitesinde çalıştığını görmek istemem. Özellikle bülten popup’larında ya da sepete ürün eklerken peşinden konfeti gelmesini istemem

    • Garip şekilde bu efekt epey etkili kullanılabiliyor. Bu tam ekran yaklaşımından emin değilim ama yakın zamanda gittiğim bir müşterinin kullandığı proje yönetim yazılımında bir öğeyi kapatınca buton yeşile dönüyor ve böyle bir efekt ekleniyordu
      İnceydi ama fark edilecek kadardı; toplantıdan sonra başka bir geliştiriciyle ikimiz de “epey iyi bir efektmiş” dedik. “Güzel, ilerleme var!” hissini veriyordu
      Yeter ki isteğe bağlı yapılsın

    • Meşru kullanım yeri olarak YouTube’un beğen düğmesi gibi şeyler olabilir. Güzel bir animasyonu var, mobil uygulamada cihaz da titreşiyor. Çok hoş bir kullanıcı deneyimi

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

      Tarayıcıda hareketi azaltma tercih edilebilir. Site sahipleri ve kütüphane bakımcıları konfeti gibi şeyler uygularken buna saygı duymalı. Bu kütüphanede özellikle disableForReducedMotion seçeneği var

    • Böyle efektlerin yakıştığı yerler var. Örneğin bir oyunu bitirmek gibi

    • Biz bu kütüphaneyi biri belirli bir yeterliliği karşıladığında kullanıyoruz. Onboarding akışına epey hoş bir etki katıyor

  • Party.js kütüphanesi de var: https://party.js.org/

    • O zaman hangisi daha küçük?
      10.4 kB minify edilmiş, 4.2 kB minify + Gzip
      https://bundlephobia.com/package/canvas-confetti@1.9.2

      28.3 kB minify edilmiş, 7.4 kB minify + Gzip
      https://bundlephobia.com/package/party-js@2.2.0

      Ancak bundlephobia’nın nasıl çalıştığını pek bilmiyorum. Paketin nihai boyutunu en iyi şekilde göstermiyor olabilir. Muhtemelen code splitting ya da sadece gerekenleri import etme gibi yöntemleri hesaba katmıyordur. Bunu sadece hızlı ve kabaca bir genel bakış olarak görüyorum

      Gzip’e göre confetti birkaç KB önde gibi; yani o birkaç KB’ı sıkıştırıp çıkarmak zorunda değilseniz, ihtiyacınız olan özelliklerin hangisinde olduğuna bağlı olarak ikisi de olur

    • Orijinal yazıdaki script mobilde çok daha performanslı görünüyor

    • Orijinal yazıdaki kütüphane çok daha performanslı görünüyor. Eski iş bilgisayarımda Party.js’e sadece 3 kez tıklayınca bile hafif gecikme hissediliyor
      canvas-confetti’de ise birkaç saniye boyunca durmadan tıklayıp muhtemelen 30’dan fazla konfeti instance’ı ve çok sayıda parçacık oluşturduğumda gecikme başlamaya başlıyor

  • downforacross.com’da bulmaca çözüyorum; bulmacayı bitirince konfeti çıkıyor
    Daha hafif hissettirmek için buradaki daha performanslı kodun bir kısmını kullanabilirler belki
    Ama “eğlence” sitesi ya da nadir kullanım değilse, bu tür animasyonların her yerde çıkmasını görmek istemem

  • Başlığa useful kelimesini özellikle koymaya gerek olduğunu sanmıyorum

    • Motivasyon aracı ve kodun derlenip derlenmediğini kontrol etme yöntemi olarak nasıl: https://squint-cljs.github.io/squint/
    • Doğru. Yine de o kelime yüzünden gerçekten ilgimi çekti ve aslında pek kullanışlı olmaması komikti. Tavsiye ederim
    • Gerçek konfeti kadar kullanışlı; yani %100 kullanışlı