それはこのデジタル時計でした。当時は良いアイデアだと思いましたが、気にしませんでした。昨日まで同僚がこの事例をネットで見てとても素敵だと思ったので、実装方法を考えて少し興味を持ち、真似してみました。それを作りました。違いは、Cen An が div を使用して作成していることです。そしてキャンバスを使って作りました。各ポイントの動きを制御するだけの場合、js を使用して dom の style 属性を制御するのは、js を使用してキャンバスの描画を制御する場合に比べてパフォーマンスが明らかに不足するため、パフォーマンスの面では Canvas を使用した方が良いでしょう。
XML/HTML コードコンテンツをクリップボードにコピー
- var numData = [
- "1111/1001/1001/1001/1001/1001/1111", //0
- "0001/0001/0001/0001/0001/0001/0001", //1
- "1111/0001/0001/1111/1000/1000/1111", //2
- "1111/0001/0001/1111/0001/0001/1111", //3
- "1010/1010/1010/1111/0010/0010/0010", //4
- "1111/1000/1000/1111/0001/0001/1111", //5
- "1111/1000/1000/1111/1001/1001/1111", //6
- "1111/0001/0001/0001/0001/0001/0001", //7
- "1111/1001/1001/1111/1001/1001/1111", //8
- "1111/1001/1001/1111/0001/0001/1111", //9
- "0000/0000/0010/0000/0010/0000/0000", //:
- ]
XML/HTML コードコンテンツをクリップボードにコピー
- 1 1 1 1
-
- 1 0 0 1
-
- 1 0 0 1
-
- 1 0 0 1
-
- 1 0 0 1
-
- 1 0 0 1
-
- 1 1 1 1
XML/HTML コードコンテンツをクリップボードにコピー
- var P_radius = 8,重力 = 9.8;
-
var 粒子 = 関数(){
-
this.x = 0;
-
this.y = 0;
-
this.vx = 0;
-
this.vy = 0;
-
this.color = "";
-
this.visible = false;
-
this.drop = false;
- }
-
Particle.prototype = {
- コンストラクター:パーティクル、
- paint:function(){ //绘自己制
-
ctx.fillStyle = this.color;
- ctx.beginPath();
- ctx.arc(this.x,this.y,P_radius,0,2*Math.PI);
- ctx.fill();
- },
- reset:function(x,y,color){ // 重置
-
this.x = x;
-
this.y = y;
-
this.vx = 0;
-
this.vy = 0;
-
this.color = 色;
-
this.visible = true;
-
this.drop = false;
- }、
- isDrop:function(){ //勾配
-
this.drop = true;
-
var vx = Math.random()*20 15
-
this.vx = Math.random()> =0.5?-vx : vx;
- },
- update:function(time){ //每一帧的アニメーション
- if(this.drop){
- this.x = this.vx*time;
- this.y = this.vy*time;
-
-
var vy = this.vy Gravity*time;
-
-
if(this.y>=canvas.height-P_radius){
-
this.y = canvas.height-P_radius
-
vy = -vy*0.7;
- }
-
-
this.vy = vy;
-
-
if(this.x<-P_radius||this.x>canvas.width P_radius||this.y<-P_radius||this.y>canvas.height P_radius){
-
this.visible = false;
- }
- }
- }
- }
-
粒子オブジェクトのプロパティは、位置、速度、および可視かどうかというより単純なものです。つまり、各フレームがパーティクルの動作を更新し、更新中にパーティクルがキャンバスの制限領域を超えて移動する場合、その可用性は false に設定され、パーティクル コンテナ内に保持され、次の使用を待ちます。
XML/HTML コード
复制コンテンツ到剪贴板
- function drawBg(){
-
var tx = (canvas.width-((P_radius*2 X_J)*4*8 7*xjg))/2;
-
for(var i=0;i<8;i ){
- var ty = (canvas.height-((P_radius yjg)*6))/2;
- for(var j=0;j<numData[0].length;j ){
- var tt = numData[0].charAt(j);
- if(tt==="/"){
- ty =yjg;
- }else {
- var x = tx j%5*(P_radius*2 X_J),
- y = ty;
- bgctx.fillStyle = "#FFF";
- bgctx.beginPath();
- bgctx.arc(x,y,P_radius,0,2*Math.PI);
- bgctx.fill();
- }
- }
- tx =xjg 4*(P_radius*2 X_J);
- }
- }
まず、背景をオフスクリーン キャンバスに描画し、それをキャッシュします。その後、各フレームを再描画するときに論理計算は必要ありません。オフスクリーン キャンバスを直接描画します。上記のロジックは、2 つのループで 8 つの数値をループし、各数値をポイントごとに描画するというもので、「/」が出現すると新しい行が必要であることを意味し、描画される ty は難しくありません。改行間隔を追加し、txをリセットしてから描画します。このようにして、すべての点を描くことができます。レンダリングは次のとおりです:
背景を描画した後、各秒の時間に従ってデジタル ピクセルの描画を開始します。主なメソッドは次のとおりです:
XML/HTML コードコンテンツをクリップボードにコピー
- 関数 setTime(時間){
- var h = time.getHours() "",
- m = 時間.getMinutes() "",
- s = 時間.getSeconds() "";
- hh = h.length===1?"0"時:時;
- mm = m.length===1?"0"分:分;
- ss = s.length===1?"0" s:s;
-
- var nowdate = h ":" m ":" s;
- var tx = (canvas.width-((P_radius*2 X_J)*4*8 7*xjg))/2,色 = "";
- for(var i=0;i<nowdate.length;i ){
- var n = nowdate.charAt(i)===":"?10:parseInt( nowdate.charAt(i))、
- テキスト = numData[n];
-
- var ty = (canvas.height-((P_radius yjg)*6))/2;
-
- スイッチ(i){
- case 0:color = "#4DCB74";break;
- case 2:color = "#4062E0";break;
- case 3:color = "#D65050";break;
- case 5:color = "#4062E0";break;
- case 6:color = "#797C17";break;
- }
-
- for(var j=0;j<text.length;j ){
- var tt = text.charAt(j);
- if(tt==="/"){
- ty =yjg;
- }else{
- var x = tx j%5*(P_radius*2 X_J),
- y = ty、
- pp = null、
- usefullp = null;
- particles.forEach(function(p){
- if(p.visible&p.x===x&p.y===y){
- ppp = p;
- }else if(!p.visible&usefullp===null){
- usefullp = p;
- }
- });
- if(pp!==null&tt==="0"){
- pp.isDrop();
- else if(pp===null&tt==="1"){
- usefullp.reset(x , y , color);
- }
- }
- }
- tx =xjg 4*(P_radius*2 X_J);
- }
- }
原理も不难、また跟上面画背景差不多、遍在すべての点、その後当時点の数字変換成る文字列に基づいて判断、当時点がこの点であるか否かを判断する、如果有像素が当時点であるかどうかを判断する粒子オブジェクトが存在する場合には、処理は直ちにスキップされ、粒子オブジェクトが存在しない場合には、再び粒子コンテナ内の使用されていない粒子がその位置にリセットされる。現在、この点には画素はありませんが、粒子が存在するので、この粒子を取得し、この粒子が自由落下するとみなします。
時間設定も写好、就可舞台更新的代了:
XML/HTML コード
复制コンテンツ到剪贴板
- var timeCount_0 = 0,timeCount_1 = 0 、粒子 = [];
- 関数 initAnimate(){
- for(var i=0;i<200;i ){
- var p = new Particle();
- particles.push(p);
- }
-
- timeCount_0 = new Date();
- timeCount_1 = new Date();
- drawBg();
- setTime(timeCount_0)
- animate();
- }
-
- 関数 animate(){
- ctx.clearRect(0,0,canvas.width,canvas.height);
- ctx.drawImage(bgcanvas,0,0);
-
- var timeCount_2 = new Date();
-
- if(timeCount_1-timeCount_0>=1000){
- setTime(timeCount_1);
-
timeCount_0 = timeCount_1;
- }
-
- particles.forEach(function(p){
- if(p.visible){
- p.update((timeCount_2-timeCount_1)/70);
- p.paint();
- }
- });
-
-
timeCount_1 = timeCount_2;
-
RAF(アニメーション) -
-
initAnimate でアニメーションの初期化を実行します。初期化とは、まず 200 個のパーティクル オブジェクトをインスタンス化し、それらをパーティクル コンテナに入れて保存し、次にタイムスタンプを更新し、背景をキャッシュし、現在の時間を設定して、アニメーション ループ本体を呼び出します。アニメーションを開始します。
animate のロジックも非常に単純です。2 つのタイムスタンプ間の時間差が 1 秒以上の場合、setTime が実行されます。次のステップでは、パーティクル コンテナ内の可視化されたパーティクルをすべてトラバースして再描画します。
これで完了です:
この効果に関して最適化できる領域はまだ多くあります。時計と分は比較的めったに移動しないため、これら 2 つはキャッシュでき、アクションがない場合はキャッシュされたデータを直接描画するだけで済みます。これにより、時間を削減できます。ステージの各フレームの描画 API 呼び出しの数が増加し、パフォーマンスが確実に向上します。ただし、現時点ではパーティクルの数はそれほど多くなく、最適化が行われていない場合でも、200 ~ 300 個のパーティクル オブジェクトで十分です。つまり、オリジナルのポスターはちょっと怠けていたんです。
ソースコードのアドレス:
https://github.com/whxaxes/canvas-test/blob/gh-pages/src/Funny-demo/coolClock/index.html