この記事では、キャンバステキストをパーティクルエフェクトに実装するコードを紹介し、皆さんに共有します。詳細は次のとおりです。
パーティクルを通してテキストを描画するのは面白く感じられ、パーティクルの動きを一致させると、効果がさらにクールになります。この記事では、キャンバス内のパーティクルを通してテキストを描画する方法を紹介します。
実施原則一般に、テキストをパーティクル表示に変換するエフェクトを作成するのは非常に簡単です。1 つはユーザーには見えないキャンバスで、もう 1 つはテキストを描画するために使用されます。取得した B キャンバスは、A のテキスト データに基づいてパーティクルを生成するために使用されます。視覚的に表現すると次の図のようになります。
オフスクリーンキャンバスを作成するHTML はメイン キャンバスに配置するだけで済みます。
<!-- HTML 構造 --><html><head> ...</head><body> <canvas id=stage></canvas></body></html>
次に、オフスクリーン キャンバスを作成し、テキストを描画します。
const WIDTH = window.innerWidth; const HEIGHT = window.innerHeight; const offscreenCtx = offscreenCanvas.getContext('2d'); offscreenCtx.font = '100px ピンファンSC';offscreenCtx.textAlign = 'center';offscreenCtx.baseline = 'middle';offscreenCtx.fillText('Hello', WIDTH / 2, HEIGHT / 2);現時点ではページ上では何も起こりませんが、実際にオフスクリーン キャンバス上では次の図のようになっていることが想像できます。
コアメソッド getImageDataキャンバスの getImageData メソッドを使用すると、キャンバスの指定された領域のピクセル データを記述するために使用されるImageDataオブジェクトを取得できます。つまり、Hello テキストの各ピクセルの位置と色を取得し、指定した位置にパーティクルを生成することができ、最終的にはパーティクルがテキストに結合されます。
ピクセル情報を取得するには、すべてのピクセルの rgba 値を配列に展開するImageDataオブジェクトのdata属性を使用する必要があります。この配列の数は像素点数量* 4です。 。
3 * 4領域を選択すると、合計 12 ピクセルがあり、各ピクセルには 4 つの rgba 値があるため、データ配列には12 * 4 = 48要素が含まれます。
データを印刷すると、これらのピクセルの rgba が左から右、上から下に配置されていることがわかります。
もちろん、取得したい領域にはテキストが含まれている必要があるため、オフスクリーンのキャンバス領域全体を取得する必要があります。
const imgData = offscreenCtx.getImageData(0, 0, WIDTH, HEIGHT).data;パーティクルを生成する
ImageData を取得した後、データ配列を走査することで、オフスクリーン キャンバス内のどの点が色付き (テキストの中央) でどの点が無色 (テキスト上ではない) であるかを判断し、それらの色付きピクセルを配置できます。位置を下げてから、メイン キャンバスでパーティクルを生成すれば準備完了です。
まずパーティクル クラスを作成します。
class Particle {constructor (options = {}) { const { x = 0, y = 0, color = '#fff', radius = 5} = オプション; = y; this.color = color; } 描画 (ctx) { ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI、false); ctx.fillStyle = this.color();データを走査すると、透明度に基づいてピクセルがテキスト内にあるかどうか、つまり rgba の 4 番目の要素が 0 でないかどうかを判断できます。
const 粒子 = [];const スキップ = 4;for (var y = 0; y < HEIGHT; y += スキップ) { for (var x = 0; x < WIDTH; x += スキップ) { var opacityIndex = (x + y * 幅) * 4 + 3; if (imgData[opacityIndex] > 0) {articles.push(new Particle({ x, y, 半径: 1,色: '#2EA9DF' }));すべてのパーティクルを保存するためにparticles配列を使用します。ここでのskipの機能は、ピクセルごとにスキャンする場合、最終的にテキストを結合するパーティクルの密度が非常に高くなります。粒子がまばらになります。
最後に、メイン キャンバスを作成して描画します。
const Canvas = document.querySelector('#stage');canvas.width = WIDTH;canvas.height = HEIGHT;const ctx = Canvas.getContext('2d');for (粒子の const 粒子) {article.draw(ctx) );}効果は次のとおりです。
完全なコードについては、01-basic-text-to-particles を参照してください。
エフェクトを追加する実装原理を理解したら、残りは実際にパーティクルにアニメーション効果を追加します。まず、見た目がきれいになりすぎないように、パーティクルにランダムなディスプレイスメントを与えることができます。
const 粒子 = [];const スキップ = 4;for (var y = 0; y < HEIGHT; y += スキップ) { for (var x = 0; x < WIDTH; x += スキップ) { var opacityIndex = (x + y * WIDTH) * 4 + 3; if (imgData[opacityIndex] > 0) { // パーティクルの作成時にランダムなディスプレイスメントを追加しますarticle.push(new Particle({ x: x + Math.random() * 6 - 3, y: y + Math.random() * 6 - 3, 半径: 1, カラー: '#2EA9DF' }));効果は次のとおりです。
より大きな効果を実現したい場合は、次のような場合があります。
これを実装するにはどうすればよいでしょうか? まず、パーティクルのサイズをランダムに生成する必要があります。これには、パーティクルの作成時に半径をランダム化するだけです。さらに、パーティクルの半径を動的に変更したい場合は、パーティクルのレンダリング半径と初期半径を区別し、アニメーションのレンダリングにrequestAnimationFrameを使用する必要があります。
class Particle {constructor (options = {}) { const { x = 0, y = 0, color = '#fff', radius = 5} = オプション; // ... this.dynamicRadius = radius; //dynamicRadius プロパティを追加}draw (ctx) { // ... ctx.arc(this.x, this.y, this.dynamicRadius, 0, 2 * Math.PI, false); DynamicRadius に置き換えます // ... } update () { // TODO }}requestAnimationFrame(functionloop() { requestAnimationFrame(loop); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, WIDTH, HEIGHT ); for (粒子の const 粒子) {particle.draw(ctx);次に、パーティクルのupdateメソッドをどのように実装するかが鍵となります。パーティクルの半径を 1 から 5 まで滑らかに周期的に変化させたいとします。次のような三角関数を考えるのは簡単です。
横軸は時間に関連している必要があります。変数を維持し、update を呼び出すたびに追加することもできます。また、タイムスタンプを使用して単純に計算することもできます。 update方法の例は次のとおりです。
update () { this.dynamicRadius = 3 + 2 * Math.sin(new Date() / 1000 % 1000 * this.radius);}完全なコードについては、「02-text-to-particles-with-size-changing」を参照してください。
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。