タイトルが示すように、この記事では、Canvas を使用して実現されるパーティクルの動きのエフェクトのみを共有したいと考えています。ちょっと見出しのような気がしますが、見方を変えると、まぶしいとは言えません。色はまぶしいとは関係ありませんが、動きの効果はまだ少しまぶしいです。とにかく、このいわゆる幻惑効果を始めましょう!
理解できない場合は、コードに直接アクセスして、コードのコメントを読んでください。おそらく大まかな考え方は理解できるでしょう。
htmlコード
<!DOCTYPE html><html lang=ja><head><meta charset=UTF-8><title>Canvas で見事なパーティクル モーション エフェクトを実現 - クラウド ライブラリ フロント エンド</title><style>* { margin: 0; : 0;}html,body { 幅: 100%; 高さ: 100%;}キャンバス { 表示: ブロック; 背景: #000;}body::-webkit-scrollbar{表示: なし;}.operator-box{ 位置: 固定; 左: 1px 背景: rgba(255,255,255,0.5); (-50%); 変換:translateX(-50%);}.back-type,.back-animate{ margin-right: 20px;}.flex-box{ 表示: flex; 整列アイテム: センター;}#input-text{ 行の高さ: 260 ピクセル; 高さ: 35 ピクセル; 0, 0,0.7); カラー: #fff; ボーダー: なし; テキストインデント: 12px; ボックスシャドウ: インセット 0 0 12px rgba(0,0,0,0.7);}#input-text::placeholder{ color: #ccc; line-height: 55px;}select{ - webkit の外観: なし; -moz の外観: なし; ボーダー: なし; 0px 6px; 高さ: 35px; テキスト整列: 左; 背景: rgba(0, 0, 0,0.7) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAICAYAAAAx8TU7AAAAOUlEQ…R4gPgWEIMAiOYBCS4C8ZDAIrBq4gigNkztQEFMi6AuQHESAPMeXiEMiWfpAAAAAElFTkSuQmCC) 繰り返しなし 190px 12px; 背景サイズ: 5px 8px; ボックスシャドウ: インセット 0 0 12px 1px rgba(0,0,0,0.7);}</style></head><body><div class=operator-box>< div class=flex-box> <div class=back-type>スプレッドタイプ: <select name= id=selectType> <option value=back>Return</option> <option value=auto>ランダム</option> </select> </div> <div class=back-animate>分散効果 (ホーミングに有効): <select class=back-dynamics id=selectDynamics> <option value= spring>dynamics.spring</option> <option value=bounce>dynamics.bounce</option> <option value=forceWithGravity>dynamics.forceWithGravity</option> <option value=gravity>dynamics.gravity</option> <option value=easeInOut>dynamics.easeInOut</option> <option value=easeIn>dynamics.easeIn</option> <option value=easeOut>dynamics.easeOut</ option> <option value=linear>dynamics.linear</option> </select> </div> <div class=input-box><input type=text placeholder=中国語の文字を入力して Enter を押してください。 id=input-text></div></div></div><script src=dynamics.min.js></script><script src=index.js></ script ><script>var iCircle = new Circle();</script></body></html>
HTML コードはそれほど多くなく、操作要素がいくつかあるだけです。ここなら一目で分かりやすいですね。余計な言葉を無駄にする必要はありません。この記事の主役となる JavaScript コードを見てみましょう。ただし、コードを見る前に、この効果を実現するためのアイデアを聞いておくとよいでしょう。
JavaScript コードでは、this.iCanvas (ホームページ)、this.iCanvasCalculate (テキストの幅の計算に使用)、this.iCanvasPixel (テキストの描画とテキストに対応するピクセルの位置座標の取得に使用) の 3 つの Canvas キャンバスが使用されます。 )。
this.iCanvasCalculate と this.iCanvasPixel はページに表示する必要はなく、単なる補助機能です。
これが素晴らしいJS実装コードです
function Circle() { var This = this; this.generalRandomParam(); this.ballAnimate(); // ウィンドウのサイズが変更された後、画面を取得します window.onresize = function(){ This.stateW = document.body.offsetWidth; This.stateH = document.body.offsetHeight; This.iCanvas.width = This.stateW; This.iCanvasH = This.iCanvas.height = This.stateH; This.ctx = This.iCanvas.getContext(2d); }}//Circle.prototype.init を初期化します。 ){ //親要素の幅と高さ this.stateW = document.body.offsetWidth; this.stateH = document.body.offsetHeight; document.createElement(canvas); // Canvas を親要素と同じ幅と高さに設定します this.iCanvasW = this.iCanvas.width = this.stateW; this.iCanvasH = this.iCanvas.height = this.stateH; // 2D ペイント環境を取得 this.ctx = this.iCanvas.getContext(2d); // body 要素に挿入 document.body.appendChild(this.iCanvas); this.iCanvasCalculate = document.createElement(canvas); // 計算されたテキスト幅を保存するために使用されるキャンバス this.mCtx = this.iCanvasCalculate.getContext(2d); this.mCtx.font = 128px Microsoft Yahei = document .createElement; (キャンバス); this.iCanvasPixel.setAttribute(style,position:absolute;top:0;left:0;); this.pCtx = null; // テキストの描画に使用されるキャンバス // ランダムに生成された円の数 this.ballNumber = ramdomNumber(1000) , 2000); // すべてのボールの配列を保存します this.balls = [] // アニメーションで動きを停止した最後のボールを保存します this.animte = null; this.imageData = null; this.textWidth = 0; // 生成されたテキストの幅を保存します this.textHeight = 150; // 生成されたテキストの高さを保存します this.inputText = ; this.actionCount = 0; this.ballActor = []; // テキストを生成するパーティクルを保存する this.actorNumber = 0 // テキストを生成するパーティクルの数を保存する this.backType = back; ; // アニメーション効果 this.isPlay = false; // ロゴ (テキスト生成中に生成できません)}// すべての円をレンダリングします Circle.prototype.drawCircles = function () { for(var i=0;i <this.ballNumber ;i++){ this.renderBall(this.balls[0]) }}// ユーザー入力テキストを取得します Circle.prototype.getUserText = function(){ This = this; // これを ipu = document.getElementById(input-text) を指すように保存します。 ipu.addEventListener(keydown,function(event){ if(event.that === 13){ // Enter キーの場合ipu.value = ipu.value.trim(); // 先頭と末尾のスペースを削除します var pat = /[/u4e00-/u9fa5]// 中国語の判定 var is Chinese = pat.test(ipu.value); if(ipu.value.length !=0 && is中国語){ This.inputText = ipu.value; }else(中国語の文字を入力してください); ) { return } This.getAnimateType(); This.isPlay = true; }//テキストの幅を計算します Circle.prototype.calculateTextWidth = function () { this.textWidth = this.mCtx.measureText(this.inputText).width;}// テキストのピクセルを取得します Circle.prototype.getTextPixel = function () { if(this.pCtx){ this.pCtx.clearRect(0,0,this.textWidth,this.textHeight); this.calculateTextWidth(this.inputText); this.iCanvasPixel.width = this.textWidth; this.iCanvasPixel.height = this.textHeight; .pCtx = this.iCanvasPixel.getContext(2d); this.pCtx.font = 128px Microsoft Yahei; this.pCtx.fillStyle = #FF0000; this.pCtx.fillText(this.inputText,0,110); 0,0,this.textWidth,this.textHeight).data; this.getTextPixelPosition(this.textWidth,this.textHeight);} //テキスト パーティクルのピクセル位置を取得します Circle.prototype.getTextPixelPosition = function (width,height) { var left = (this.iCanvasW - width)/2; = (this.iCanvasH - 高さ)/2; var space = 4; for(var) i=0;i<this.textHeight;i+=space){ for(var j=0;j<this.textWidth;j+=space){ varindex = j*space+i*this.textWidth*4; this.imageData[インデックス] == 255){ if(this.actionCount<this.ballNumber){ this.balls[this.actionCount].status = 1; this.balls[this.actionCount].targetX = left+j; this.balls[this.actionCount].targetY = top+i; this.balls[this.actionCount].backX = this.balls[this.actionCount]。 x; this.balls[this.actionCount].backY = this.balls[this.actionCount].y; this.ballActor.push(this.balls[this.actionCount]); } } } this.actorNumber = this.ballActor.length; } this.animateToText();}//パーティクルは指定された位置に移動します Circle.prototype.animateToText = function(){ for(var i=0;i<This .actorNumber ;i++){ Dynamics.animate(This.ballActor[i], { x: this.ballActor[i].targetX, y: this.ballActor[i].targetY },{ type:dynamics.easeIn,duration:1024, }); } setTimeout(function(){ This.ballbackType(); },3000);}//パーティクルは元のパスに沿って円を描く .prototype.ballBackPosition = function(){ for(var i=0;i<This.actorNumber;i++){ var ball = This.ballActor[i]; Dynamics.animate(ball, { x: ball.backX, y: ball.backY },{ type:dynamics[this.backDynamics], period: 991, complete:this.changeStatus(ball) } ); }}// タイプ|アニメーション効果を取得 Circle.prototype.getAnimateType = function() { var selectType = document.getElementById(selectType); var selectDynamics = document.getElementById(selectDynamics); this.backType = selectType.options[selectType.options.selectedIndex].value; this.backDynamics = selectDynamics.options[selectDynamics.options.selectedIndex].value;}//スプレッド円をリセット.prototype.ballbackType = function(){ if(this.backType == back){ this.ballBackPosition(); }else{ this.ballAutoPosition(); } this.ballActor = [];}// ランダムに散布する Circle.prototype.ballAutoPosition = function(ball){ for(var i= 0 ;i<this.actorNumber;i++){ this.changeStatus(this.ballActor[i]) }}//ボールのステータスを変更します Circle.prototype.changeStatus = function(ball){ ball.status = 0; if(this.isPlay == true){ this.isPlay = false }}// 各サークルの関連パラメーターをランダムに生成します。 .prototype.generalRandomParam = function(){ for(var i=0;i<this.ballNumber;i++){ var ball = {}; //円の半径をランダムに生成 // 円の中心 x 座標をランダムに生成 ball.x = ramdomNumber(0+ball.size, this.iCanvasW-ball.size); ball.y = ramdomNumber(0+ball.size, this.iCanvasH-ball) .サイズ); ボール.スピードX = ラムダム番号(-1, 1); ball.status = 0; ball.targetX = 0; ball.backX = 0; ball.backY = 0; for( var i=0;i<this.ballNumber;i++){ if( this.balls[i].status == 0){ this.balls[i].x += this.balls[i].speedX; this.balls[i].y += this.balls[i].speedY; } }}// 円を描く Circle.prototype.renderBall = function(ball){ this.ctx . fillStyle = #fff; this.ctx.beginPath(); // this.ctx.arc(ball.x, ball.y, ball.size, 0, 2 *) を追加する必要があります。 Math.PI); this.ctx.closePath(); // this.ctx.fill() で追加する必要があります;}// ボール衝突判定 Circle.prototype.collision = function(ball){ for(var i= 0;i<this.ballNumber;i++){ if(ball.x>this.iCanvasW-ball.size || ball.x<ball.size){ if(ball.x>this.iCanvasW-ball.size){ ball.x = this.iCanvasW-ball.size; }else{ ball.x = ball.size } ball.speedX = - ball.speedX; (ball.y>this.iCanvasH-ball.size || ball.y<ball.size){ if(ball.y>this.iCanvasH-ball.size){ ball.y = this.iCanvasH-ball.size; }else{ ball.y = ball.size; } ball.speedY = - ball.speedY; } }}// アニメーションの開始 Circle.prototype.ballAnimate = function(){ var This = this ; var animateFrame = window.mozRequestAnimationFrame || ウィンドウ.webkitRequestAnimationFrame window.msRequestAnimationFrame; (関数 move(){ animte = animateFrame(move); This.ctx.clearRect(0, 0, This.iCanvasW, This.iCanvasH); This.changeposition(); for(var i=0;i <This.ballNumber;i++){ This.collision(This.balls[i]); This.renderBall(This.balls[i]); })();}//乱数関数を生成する ramdomNumber(min, max) { return Math.random() * (max - min) + min;}
コードを読んだ後は、ちょっとした見せびらかしで、これを作りたいという意欲が湧かなかったのだと思います。これについては、目と口で納得する必要があることはわかっています。オンライン デモ: 動的粒子の例。
完璧な人はいませんし、コードも完璧ではありません。スムーズに実行されているように見えるコードには、多かれ少なかれ欠陥があります。現在、このエフェクトは中国語のみをサポートしています。英語に関しては、何としても頑張らなければなりません。英語は後から必ず加わります。それは時間の問題です。コードには、生成されたテキストを再度実行できるかどうかをマークするために使用される属性 this.isPlay もありますが、これにはまだ少し欠陥がありますが、this.isPlay の状態変化はパーティクルが戻った瞬間に正確に変化しません。ただし、事前に状態を変更します。ただし、この状態は、この例の効果の完全な実装には影響しません。
この例では、dynamis.js ライブラリが使用されています。主に、パーティクルの動きをより印象的にするためにライブラリ内のいくつかのモーション関数を使用するだけです。
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。