こんにちは、これは Alipay の Zhima Credit スコアを模倣したキャンバスです。実際にはアニメーション化されたダッシュボードです。
まず、上の元の画像:
これはAlipayのスクリーンショットです。スコアが低いと笑えます。次に、キャンバスを使用して実現したレンダリングを見てください。
<canvas id="canvas" width="400" height="700" data-score='724'></canvas> <!-- 设置data-score,分数区间[400, 900] -->
ああ、そのようには感じられません。これは GIF 画像なので、Web ページ上で開いた方が効果が高いかもしれません (もちろんそうかもしれません)。下部をクリックして codepen のデモをプレビューできます。 2 つの欠点があります。1 つは、単純な実装のために同じスケールを使用したことです。もう 1 つは、ダイヤル上の移動ポイントがぼやけていることです。ああ、それは次回に話しましょう。
次に、それを達成する方法について話しましょう。最初のステップ、国際的な練習は、キャンバスを作成することです:
var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), cWidth = canvas.width, cHeight = canvas.height;
次に、乙女座ではありませんが、元の絵とできるだけ一致するように、つまり、この環状の角度を描きます。オープニング? PS にアクセスして測定してください:
さて、136°、この角度は後続の計算を容易にするために、非常に難しい角度です。これは 140° にほぼ等しくなります。次に、分数セグメントの円弧は次のようになります:
var deg1 = Math.PI * 11 / 45
まず、中央に半透明のスケール レイヤーを描画します:
ctx.save(); //中间刻度层 ctx.beginPath(); ctx.strokeStyle = 'rgba(255, 255, 255, .2)'; ctx.lineWidth = 10; ctx.arc(0, 0, 135, 0, 11 * deg0, false); ctx.stroke(); ctx.restore();
次に、6 本のスケール ラインを描画し、for ループを使用して実装します:
ctx.save(); // 刻度线 for (var i = 0; i < 6; i++) { ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(255, 255, 255, .3)'; ctx.moveTo(140, 0); ctx.lineTo(130, 0); ctx.stroke(); ctx.rotate(deg1); } ctx.restore();
同様に、大きなスケール レイヤーを描画します。スケールを細かく 5 つの小さなスケールに分割します:
ctx.save(); // 细分刻度线 for (i = 0; i < 25; i++) { if (i % 5 !== 0){ ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(255, 255, 255, .1)'; ctx.moveTo(140, 0); ctx.lineTo(133, 0); ctx.stroke(); } ctx.rotate(deg1 / 5); } ctx.restore();
ここではスケールをテキストと各分数のクレジット レベルでマークする必要があります。詳細については、コードを参照してください。大規模な実装なので、詳細は説明しません。ここで最も重要なことは、文字盤上の移動点を認識することです (どう呼ぶかわかりませんが、以下ではこれを移動点と呼びましょう)。これは非常に小さな円です。 radius は、最も外側のリング トラックに描かれた単なる円であり、キャンバス上で円を実現する方法は次のとおりです。
ctx.arc(x, y, radius, sAngle, eAngle, false);
円を動かし、必要な効果を実現するには、x と y を制御するだけです。それで、移動点オブジェクトを作成します:
function Dot() { this.x = 0; this.y = 0; this.draw = function (ctx) { ctx.save(); ctx.beginPath(); ctx.fillStyle = 'rgba(255, 255, 255, .7)'; ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false); ctx.fill(); ctx.restore(); }; } var dot = new Dot(), dotSpeed = 0.03, //控制动点的速度 angle = 0, //这个很关键,用来得到动点的坐标x, y credit = 400; //信用最低分数
ドットの座標 x、y を取得するにはどうすればよいですか?次に、伝説的な三角関数を使用する必要があります。
上の図から
x = r * cos(angle), y = r * sin(angle)
を取得できます。JavaScriptでは、ドットの中心座標は次のようになります:
dot.x = radius * Math.cos(angle); //radius为最外层轨道的半径值 dot.y = radius * Math.sin(angle);
次に、この角度を取得する必要があります。これは、ラジアンとスコアの比例関係から取得できます:
var aim = (score - 400) * deg1 / 100; if (angle < aim) { angle += dotSpeed; } dot.draw(ctx);
次に、移動点の回転に応じて中央のクレジット スコアを変化させ、数値の変化を移動点と一致させるために text() を作成します。 「移動点の速度でデジタル変化を計算する」に従ってください:
function text(process) { ctx.save(); ctx.rotate(10 * deg0); ctx.fillStyle = '#000'; ctx.font = '80px Microsoft yahei'; ctx.textAlign = 'center'; ctx.textBaseLine = 'top'; ctx.fillText(process, 0 ,10); ctx.restore(); } var textSpeed = Math.round(dotSpeed * 100 / deg1), if (credit < score - textSpeed) { credit += textSpeed; } else if (credit >= score - textSpeed && credit < score) { credit += 1; // 这里确保信用分数最后停下来是我们输入的分数 } text(credit);
結局、これはすべて、 window.requestAnimationFrame() で描画アニメーションを制御し、 ctx.clearRect(0, 0, cWidth, cHeight) でアニメーションをクリアすることから逃れることはできません。キャンバス。
それがうまく書かれていない場合は、誰もがそれに対処する必要があるだけです。私が何を言いたいのかさえわからない私の言葉を理解するよりも、誰もがコードを理解する能力の方が優れているはずです。