JavaScriptからCanvasへの知識ポイントを復習して、Canvasを使って描画された静的な時計の例を見て、これをシステム時間を動的に表示する時計アニメーションにしたいと思いました。さらにデジタル表示時計と合わせて小型時計モジュールが誕生!現在のインターフェイスはまだ比較的粗く、シンプルなインターフェイスとアニメーション効果のみが含まれています。
この時計には、アニメーションディスク時計とデジタル時計の 2 つの部分が含まれています。 1 つ目は、タイムアウトを使用して setTimeout() メソッドを呼び出し、時間を表示するループ アニメーション効果を作成する方法です。まずデジタル時計のコードを見てみましょう。ディスク時計もデジタル時計を模倣して作られています。
var ntimeoutId = setTimeout(ntimeOut,0);function ntimeOut() { clearTimeout(ntimeoutId); var now = new Date(); var hours = now.getHours().toString(), minutes = now.getMinutes().toString(), seconds = now.getSeconds().toString(); var time = hours+" : "+minutes+" : "+seconds; var timep = document.getElementById("time"); timep.innerHTML = time; ntimeoutId = setTimeout(ntimeOut, 1000); }
1. まず、システムの現在時刻を表示するメソッドを初めて呼び出すタイムアウト呼び出しを設定します。時間を0に設定しているのは、遅延なく時刻を表示するためです。 。
2. 各ループの前に前のタイムアウト呼び出しをクリアします (なぜこれを行うのか、まだわかりません??? メモリのパフォーマンスに関連している可能性があります。コメント後、プログラムは正常に実行できます。)
3. 現在のシステム時刻を取得し、特定の文字列形式で保存します。
4. ページ上に動的に表示するために、HTML ページに時間文字列を格納する空の p 要素を定義します。 DOM 操作を使用して p 要素に追加し、動的に表示します。
5. タイムアウト呼び出しを継続的にループすることで、デジタル時計を動的に表示することができます。また、開発者ツールを通じて p 要素の動的な変化を確認することもできます。
次のステップは、ディスク時計アニメーションを作成することです。ディスクと数値の描写は比較的単純で、context.arc() メソッドと context.fillText() メソッドを使用するだけです。以下はそのソースコードです:
context.beginPath(); context.restore(); context.translate(0,0); context.clearRect(0,0,300,300); //绘制时钟内外边框 context.arc(150,150,149,0,2 * Math.PI,false); context.moveTo(295,150); context.arc(150,150,145,0,2 * Math.PI,false); context.font = "bold 18px Arial"; context.textAlign = "center"; //绘制时钟表盘数值 context.fillText("12",150,25); context.fillText("3",285,150); context.fillText("6",150,290); context.fillText("9",15,150); context.fillText("1",215,45); context.fillText("2",265,95); context.fillText("4",265,225); context.fillText("7",95,275); context.fillText("5",215,275); context.fillText("8",35,225); context.fillText("10",35,95); context.fillText("11",75,45); context.stroke(); context.closePath();
次のステップはポインタを描画することです。ポインタを描画する際には、立面図のメソッドを参照して、変換操作 context.translate() メソッドを使用します。原点を選択してから、ポインタとなるパスを描画する方が便利です。ポインタを描画する際のもう 1 つの困難は、ラジアンの計算です。もちろん、これは数学的な問題です。まずソース コードを見てみましょう:
//绘制指针 context.save(); context.translate(150,150); //时针 context.moveTo(0,0); hour(hours); function hour(thour) { context.save(); var newhour = 0; if(thour>12) { newhour = thour-12; } else { newhour = thour; } context.rotate((2*Math.PI/12)*newhour); context.lineTo(0,-80); context.restore(); } //分针 context.moveTo(0,0); minute(minutes); function minute(tminute) { context.save(); context.rotate((2*Math.PI/12)*tminute/5); context.lineTo(0,-110); context.restore(); } //秒针 context.moveTo(0,0); second(seconds); function second(tsecond) { context.save(); context.fillStyle = "#fff"; context.rotate((2*Math.PI/12)*tsecond/5); context.lineTo(0,-120); context.restore(); } context.stroke();
ポインターを描画する場合、各タイプのポインターは関数を使用して各ポインター描画の円弧を変更し、ポインター回転のアニメーション効果を実現します。短針は、24 時間時計を 12 時間時計に変換し、毎回 30 度回転させます。長針と秒針は 0 から 11 まで回転します。簡単な数学の問題は、私よりも皆さんのほうが得意だと思います。私はまだしばらく苦労していました。 context.save() メソッドと context.restore() メソッドは、初期化中にパスを保存および復元するために各関数で使用されます。そうしないと、ポインターが軌道から外れてしまいます。
次に、タイムアウト呼び出しに時計のダイヤルとポインターを配置するだけで、すべての作業が完了します。ただし、原点の設定など、注意する必要がある問題がまだいくつかあります。時計の文字盤と針は異なります。保存と復元を使用して初期化パスを復元しないと、時計の文字盤と針が軌道から外れてしまいます。もう 1 つ注意すべき点は、Canvas を使用してアニメーションを作成する場合、各アニメーション サイクルで Canvas をクリアして再描画する必要があることです。そうしないと、ポインタが回転し続けて花になってしまいます。
完全なディスク クロック コードは次のとおりです:
//显示指针时间var drawing = document.getElementById("drawing");if(drawing.getContext) { var context = drawing.getContext("2d"); var rtimeoutId = setTimeout(roudClock,0); function roudClock() { clearTimeout(rtimeoutId); context.beginPath(); context.restore(); context.translate(0,0); context.clearRect(0,0,300,300); //绘制时钟内外边框 context.arc(150,150,149,0,2 * Math.PI,false); context.moveTo(295,150); context.arc(150,150,145,0,2 * Math.PI,false); context.font = "bold 18px Arial"; context.textAlign = "center"; //绘制时钟表盘数值 context.fillText("12",150,25); context.fillText("3",285,150); context.fillText("6",150,290); context.fillText("9",15,150); context.fillText("1",215,45); context.fillText("2",265,95); context.fillText("4",265,225); context.fillText("7",95,275); context.fillText("5",215,275); context.fillText("8",35,225); context.fillText("10",35,95); context.fillText("11",75,45); context.stroke(); context.closePath(); var now = new Date(); var hours = now.getHours(), minutes = now.getMinutes(), seconds = now.getSeconds(); //绘制指针 context.save(); context.translate(150,150); //时针 context.moveTo(0,0); hour(hours); function hour(thour) { context.save(); var newhour = 0; if(thour>12) { newhour = thour-12; } else { newhour = thour; } context.rotate((2*Math.PI/12)*newhour); context.lineTo(0,-80); context.restore(); } //分针 context.moveTo(0,0); minute(minutes); function minute(tminute) { context.save(); context.rotate((2*Math.PI/12)*tminute/5); context.lineTo(0,-110); context.restore(); } //秒针 context.moveTo(0,0); second(seconds); function second(tsecond) { context.save(); context.fillStyle = "#fff"; context.rotate((2*Math.PI/12)*tsecond/5); context.lineTo(0,-120); context.restore(); } context.stroke(); context.restore(); context.translate(0,0); context.save(); rtimeoutId = setTimeout(roudClock,1000); } }
最後に、このデモ演習中に遭遇した問題をまとめます:
1. キャンバスの再描画の問題
ポインター アニメーションがループすると、前のパスをクリアする方法がなくなり、各ループに跡が残ります。狭い範囲でclearRect()メソッドを使用してみましたが、範囲内のダイヤルと数字の内容しかクリアできず、ポインタの痕跡が残ることがわかりました。その後、検索して得た答えは、Canvas を使用してアニメーションを作成する場合は、新しいコンテンツを描画する前にキャンバスのコンテンツをクリアする必要があり、アニメーションの変更はすべてクリアする必要があるということでした。再描画方法についてはリンクを参照してください。clearRect()メソッドを使用してキャンバス全体をクリアします。
2. save()メソッドとrestore()メソッドの使用
時計の文字盤とポインターの原点設定が異なるため、再描画後は時計の文字盤の原点がポインターなので、save() メソッドとrestore() メソッドを使用して変更します。この場所以外にも使用する必要がある場所があり、操作後に設定を変更したが、その後の操作では元の設定を使用する必要がある場合に適しています。これら 2 つの方法では、設定の保存と復元のみが行われ、コンテンツは保存されないことに注意してください。
3.translate()メソッドの使用
translate()メソッドは変形操作に属し、キャンバスの原点を変更できます。キャンバスのデフォルトの原点はキャンバスの左上隅にあります。 。このメソッドを使用すると、ポインタのパスを描画しやすくなります。もちろん、まだ触れていない他の用途もあります。
4. setTimeout()メソッドの使用
タイムアウト呼び出しを使用することは、断続的な呼び出しをシミュレートすることができるより良い方法です。タイムアウト呼び出しが渡される関数内にタイムアウト呼び出しを追加すると、ループを適切にシミュレートできます。関数内のいくつかの条件に基づいてループの数と時間を制限することもできます。
5. 現在の時刻に対応する、ラジアンの使い方
これは数学の問題で、ずっと角を曲がらずに悩んでいましたが、原理がわかれば問題ありません。技術的な問題。
6. timeメソッドの繰り返し取得と再利用の問題について
コード内に重複コードが存在する状況に関しては、冗長性を減らすためのこれより良い方法は思いつきませんでした。たとえば、取得時間に関しては、2 つのタイムアウト呼び出しに繰り返し定義がありますが、それらがグローバルに配置されている場合、アニメーション効果はなく、読み込みが完了した後の静的な時間のみが表示されます。もう一つは、ポインタの関数設定に繰り返し部分があるのですが、それを一つの関数メソッドにまとめて呼び出すことはできるのでしょうか?
誰もがアイデアを出したり、欠点を補ったり、一緒にコミュニケーションしたりすることを歓迎します。
以上がCanvasを使った時計アニメーションの作り方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。