部分的なすごい効果:簡単な言葉の魔法について

通常wowサイトと呼ばれるサイトのカテゴリがあります。 コンテンツを直接消費することを目的としたものではなく、訪問者を感心させるものです。 これらのサイトは通常、デザインが独特であり、ユーザーとやり取りするための実験的なソリューションを含み、ステレオタイプを破り、さまざまなアニメーションであふれています。 特に興味深いのは、SVGのさまざまなトリックと、多数のパーティクルに基づくアニメーションです。これについては、この記事で説明します。







一般に、一連の粒子の形でさまざまなオブジェクトを再構築するという考え方は、長い間存在していました。 しかし、このアイデアの実際の適用は非常に限られており、特定の実装はそれぞれ特定のコンテンツに結び付けられているため、すべてのトリックをすばやく学習できる単一の構造化された知識ベースはありません。 その結果、多くの開発者は、すべてが非常に単純なアイデアに基づいていることを理解していません。 JSに多少なりとも精通している人なら誰でも実装できます。



キャンバスを操作するための特定のライブラリの低レベルの最適化と機能を掘り下げることなく、2Dでパーティクルアニメーションを作成する基本的なアプローチを理解し、いくつかの実用的な例を見てみます。 これ以降の説明はすべて、読者がcanvasの操作の基本に精通しているという前提に基づいています。 そうでない場合は、この時点で中断して、慣れることをお勧めします。 コード例は、コピーペーストの具体的なレシピではなく、アイデアを伝えるために少し簡略化されているため、コンテキスト内にあると便利です。



小さな余談:これはすべてプロセッサリソースを使い果たし、新しいMacBookのラグが発生し、一般的にはサイトでこれを実行できないと言う人がいるでしょう。 一方で、この発言は真実です。 ブラウザーの最新のJSは、特に平均的なサイトに関しては、複雑な計算の良い基盤ではありません。 しかし、私たちは普通のサイトについて話しているのではありませんか?



ナンバーワンを考えました。 サイズが重要







ほとんどの場合、粒子を非常に小さくすることはできません。 これはパフォーマンスの問題です。 平均的なラップトップでは、画面全体を1ピクセルで計算することはできず、60は言うまでもなく少なくとも30 fpsがあります。パーティクルの数を減らす必要があります。 実際には、アニメーションは通常、小さな画像で作業している場合は2〜3ピクセルの小さな粒子か、画面の大きな領域を埋めるように設計された数十ピクセルの大きな粒子を使用します。



一方、粒子は大きすぎることはできません。 これは適応性の問題です。 電話では画面が小さくなり、粒子が大きくなるだけで判読不能な混乱が生じることを覚えておくのは理にかなっています。 適切な選択は、作業中のキャンバスサイズに粒子サイズをバインドすることです。



考え番号2。 既製のパーティクルレイアウトが必要です。







基盤が必要です。 基盤がなければ、妥当な時間で複雑なアニメーションを作成することはできません。 2つのオプションがあります。 画像またはテキストを基準として使用します。 テキストは、見出し、時計、エラー番号、またはフェンス上の単語のみです。



基盤は、それが何であれ、キャンバスに転送する必要があります。 テキストはすべてシンプルです。標準のfillTextを使用して作成すると、パーティクルの配置の白黒のアウトラインが表示されます。 これがまさに必要なものです。



ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, width, height); ctx.fillStyle = '#000'; ctx.font = `${fontSize}px Arial`; ctx.textAlign = 'center'; ctx.fillText('Hello', width/2, height/2 + fontSize/4);
      
      









背景に白を事前に入力する必要はないことに注意してください。 はい、最新のブラウザでは、背景は正式には白になりますが、Safariではそうではありません。 誰かが聞いたことがない場合、これは新しいロバであり、CSSグラデーションとキャンバスの両方で、独自の方法で透明度と連携します。 このため、予想される色がまったく表示されない場合があります。 さらに、さまざまなブラウザの信念でさまざまな方法で故障が発生します。



粒子の配列の配色を受け取ったら、簡単な検索を使用して、それぞれが独自の座標を持つこれらの粒子のセットを作成できます。 将来的には、追加のパラメーターを追加します。 以下、高さと幅はキャンバスのサイズ、パーティクルはパーティクルの配列、ステップはパーティクル間の初期距離です。



 const data = ctx.getImageData(0, 0, width, height).data; const data32 = new Uint32Array(data.buffer); for (let x = 0; x < width; x += step) { for (let y = 0; y < height; y += step) { const color = data32[y * width + x]; if (color != 0xFFFFFFFF) { particles.push({ x, y }); } } }
      
      





パーティクル間の距離を決定する特定のステップを使用して、キャンバス全体をピクセル単位で単純にトラバースし、文字に当たるパーティクルを保存します。 スキームは2色で構成されているため、どちらを比較するかは問題ではありません。 しかし、画像を基礎として使用する場合、特にそれが白い背景の製品またはストック人である場合、背景と比較すると便利です。 場合によっては、そのようなサンプリングはまったく実行されず、粒子はサイクルの各ステップで保存されます。



たとえば、元の画像のピクセルの色に対応する色を粒子に追加したり、隣接するピクセルの平均色を計算したりできますが、これはほとんど不要です。



これで、たとえば、その位置に正方形を描くことで、キャンバスをクリアして粒子で埋めることができます。



 particles.forEach((particle) => { ctx.fillStyle = particle.color; ctx.fillRect( particle.x, particle.y, step, step ); });
      
      





これは特に興味深い効果を与えるものではなく、画像またはテキストが少しピクセル化されているだけです。 または、正方形ではなく他の幾何学的図形のセットになります。 しかし、動きを追加すると、面白い結果が出始めます:





わかった そして、どのような動きを追加するのですか?



一般に、パーティクルには次の主要なパラメーターがあります。





ほとんどの場合、パーティクルのパラメーターを決定するために使用するタイムカウンターがあります。 言い換えれば、変化するすべてのものは、時間にバインドしようとします。 これには興味深い機能があります-カウンターを増減して、時間の経過を変更し、アニメーションをそのルートに戻すことができます。



最も単純ですが、多くの人に愛されているアニメーションの1つは、パーティクルが元の座標を中心にランダムに移動することです。 これはテキストでうまく機能します。 動きがランダムであればあるほど、結果はよりシャープになります。 動きが多少均一なもの、たとえば小さな円(サインとコサインを覚えている)に結び付けられている場合、特に粒子サイズをわずかに変更した場合、効果はより滑らかになり、流れるようになります。





この例では、小さな画面で大きな粒子サイズを保存するとどうなるかを示しています(前の例と比較してください)。 これは適応性の問題です。



ここでの主なことは、パーティクルがパラメータを完全に同期しないように変更するように多様性を追加することです。 これはさまざまな方法で行うことができますが、通常、各粒子に対して、粒子配列のシリアル番号に応じて、何らかのパラメータを変更してパラメータを変更します。 多くの場合、同じ正弦の引数にパーティクルのシリアル番号を掛けるのに十分です。 このアプローチにより、精神的な労力をあまりかけずに許容可能なレベルのランダム性を実現できます。 数学者-暗号作成者の観点からは、これはランダムなシーケンスのようには見えませんが、アニメーションでは十分です-粒子の動きの顕著な同期が発生する前に、視聴者は感動し、さらに先に進みます。



初心者向けの便利なカラーアドバイス:時間が経つにつれてスムーズにパーティクルのカラーを変更する必要がある場合は、RGBを忘れてHSLに切り替えてください。 これにより、トーンを変更するためのパラメータの1つだけを気にせず、スムーズに変更できなくなります。 彩度は同じです。 そして、黒や白のままにしたとしても、配色が古いテレビのように少し浮いているという事実を考える必要はありません。



時の砂...







もう一つの壮大なことは、滝のような外観、または言うまでもなく、地滑りを作り出すことです。 粒子はランダムな加速度で一方向に動き始め、高さが増します。 彼らは跡を残すようです。 同様の手法は、写真でもうまく機能します。



キャンバスに画像を配置するために、標準のdrawImageメソッドを使用します。 必要に応じて、object-fit:coverまたはcontainsプロパティと同様の動作を使用して画像を配置できます。 この場合、ネットワークには既製のソリューションがあります。



しかし、効果そのものに戻りましょう。 前の例から簡単に作成できます。 粒子に新しいパラメーターを追加する必要があります-サイズと速度。



 particles.forEach((particle) => { ctx.fillStyle = particle.color; ctx.fillRect( particle.x, particle.y, particle.width, particle.height ); particle.speed += timeCounter * Math.abs(Math.sin(5 * particle.x + 7)); particle.y += particle.speed; particle.height += particle.speed; }); timeCounter++;
      
      





乱数ジェネレーターを作成したことがある場合、おそらく2つの素数(5と7)の組み合わせは非常によく知られているものに似ていると考えているでしょう。 理論を思い出すことはできますが、実際には、そのような効果を作成する場合、数値係数は通常試行錯誤によって選択されます。結果として視覚効果がどうなるかを事前に言うのは困難です。 そして、重要なのは彼です。





同様のアニメーションを使用して、一方が下に流れ、もう一方が反対側から流れ込む場合に、ある画像を別の画像に効果的に置き換えることができます。 このような画像の変更を実行するには、2番目の画像の粒子の位置を事前に計算し、反対方向にその時間カウンタを開始する必要があります。 これは、パーティクルのすべてのパラメーターを明示的な時間カウンターで表現した後に行うのが最も便利です。



次はどこに行きますか?



アニメーションでパーティクルを使用する最も簡単な方法を検討しました。 これは氷山の一角にすぎません。 これらのことを行う方法を学ぶ最良の方法は、それらを始めることです。 興味深いデモがCodePenに定期的に表示されます。これは、知り合いになると便利です。 初心者の開発者は、特定の実装よりも、学習している例に具体化されているアイデアに注意を払い、実験することを恐れないでください。



All Articles