跃然一笑
当你处于 时,你实现它的方式总是有一些“问题” 0%。如果您希望什么都没有,0%并且在百分比增长时保持一致,那么您不想使用ctx.lineJoin = "round"作为解决方法,您可以使用arc()方法来绘制圆角。关于arc(x, y, radius, startAngle, endAngle),我们知道x = r,y = r并且radius = rz我们只需要一些几何计算就可以得到所需的值startAngle(α)和endAngle(α+Δ)。利用三角函数余弦,我们有Math.cos(θ) = (r - p) / r⇒ θ = Math.acos((r - p) / r)。我们有并且 α = Math.PI - θ 我们知道 Δ = 2 * θ⇒(α+Δ) = Math.PI + θ所以最后:startAngle α = Math.PI - Math.acos((r - p) / r)endAngle (α+Δ) = Math.PI + Math.acos((r - p) / r)在我们的例子中,r = h /2当p < r⇔时p < h / 2,我们得到:ctx.arc(h / 2, h / 2, h / 2, Math.PI - Math.acos((h - 2 * p) / h), Math.PI + Math.acos((h - 2 * p) / h))
ctx.fillStyle = '#FF1700';
ctx.fill();const canvas = $("#progressBar");const ctx = canvas.get(0).getContext("2d");const h = 100;const p = 30;/* To visalize ------------------------------------------------------*/ctx.beginPath();ctx.arc(h / 2, h / 2, h / 2, Math.PI / 2, 3 / 2 *Math.PI);ctx.lineTo(500, 0);ctx.arc((h / 2) + 500, h / 2, h / 2, 3 / 2 *Math.PI,Math.PI / 2);ctx.lineTo(h / 2, h);ctx.strokeStyle = '#000000';ctx.stroke();ctx.closePath();/* ------------------------------------------------------------------*/ctx.beginPath();ctx.arc(h / 2, h / 2, h / 2, Math.PI - Math.acos((h - 2 * p) / h), Math.PI + Math.acos((h - 2 * p) / h));ctx.fillStyle = '#FF1700';ctx.fill();<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><canvas id="progressBar" width="750" height="120"></canvas>现在,如果我们想要这种外观(红色部分,我们想要骑上灰色部分)。该方法包括执行相同的操作,但只进行一半的进度,然后对称地重复相同的图形(阴影区域)。为了绘制对称形状,我们将使用ctx.scale(-1, 1)和 方法save() restore()。第二个圆弧中心的 x 位置将是- (r - p)⇔ -((h / 2) - p),就像我们将在水平对称中工作一样,它最终将是(h / 2) - pctx.beginPath();ctx.arc(h / 2, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h));ctx.save();ctx.scale(-1, 1);ctx.arc((h / 2) - p, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h));ctx.restore();ctx.fillStyle = '#FF1700';ctx.fill();const canvas = $("#progressBar");const ctx = canvas.get(0).getContext("2d");const h = 100;const p = 25;/* To visalize ------------------------------------------------------*/ctx.beginPath();ctx.arc(h / 2, h / 2, h / 2, Math.PI / 2, 3 / 2 *Math.PI);ctx.lineTo(500, 0);ctx.arc((h / 2) + 500, h / 2, h / 2, 3 / 2 *Math.PI,Math.PI / 2);ctx.lineTo(h / 2, h);ctx.strokeStyle = '#000000';ctx.stroke();ctx.closePath();/* ------------------------------------------------------------------*/ctx.beginPath();ctx.arc(h / 2, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h));ctx.save();ctx.scale(-1, 1);ctx.arc((h / 2) - p, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h));ctx.restore();ctx.fillStyle = '#FF1700';ctx.fill();<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><canvas id="progressBar" width="750" height="120"></canvas>p <= h在我们需要更改代码以考虑矩形部分之前,情况都是如此。我们将使用 if...else 来做到这一点。if(p <= h){ ctx.beginPath(); ctx.arc(h / 2, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h)); ctx.save(); ctx.scale(-1, 1); ctx.arc((h / 2) - p, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h)); ctx.restore(); ctx.fillStyle = '#FF1700'; ctx.fill();} else { ctx.beginPath(); ctx.arc(h / 2, h / 2, h / 2, Math.PI / 2, 3 / 2 *Math.PI); ctx.lineTo(p - 2 * h, 0); ctx.arc(p - (h / 2), h / 2, h / 2, 3 / 2 *Math.PI,Math.PI / 2); ctx.lineTo(h / 2, h); ctx.fillStyle = '#FF1700'; ctx.fill();}const canvas = $("#progressBar");const ctx = canvas.get(0).getContext("2d");const h = 100;const p = 350;/* To visalize ------------------------------------------------------*/ctx.beginPath();ctx.arc(h / 2, h / 2, h / 2, Math.PI / 2, 3 / 2 *Math.PI);ctx.lineTo(500, 0);ctx.arc((h / 2) + 500, h / 2, h / 2, 3 / 2 *Math.PI,Math.PI / 2);ctx.lineTo(h / 2, h);ctx.strokeStyle = '#000000';ctx.stroke();ctx.closePath();/* ------------------------------------------------------------------*/if(p <= h){ ctx.beginPath(); ctx.arc(h / 2, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h)); ctx.save(); ctx.scale(-1, 1); ctx.arc((h / 2) - p, h / 2, h / 2, Math.PI - Math.acos((h - p) / h), Math.PI + Math.acos((h - p) / h)); ctx.restore(); ctx.fillStyle = '#FF1700'; ctx.fill();} else { ctx.beginPath(); ctx.arc(h / 2, h / 2, h / 2, Math.PI / 2, 3 / 2 *Math.PI); ctx.lineTo(p - 2 * h, 0); ctx.arc(p - (h / 2), h / 2, h / 2, 3 / 2 *Math.PI,Math.PI / 2); ctx.lineTo(h / 2, h); ctx.fillStyle = '#FF1700'; ctx.fill();}<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><canvas id="progressBar" width="750" height="120"></canvas>现在,我们可以总结一下了:const canvas = $("#progressBar");const ctx = canvas.get(0).getContext("2d");const canvasWidth = ctx.canvas.width;const canvasHeight = ctx.canvas.height;class progressBar { constructor(dimension, color, percentage){ ({x: this.x, y: this.y, width: this.w, height: this.h} = dimension); this.color = color; this.percentage = percentage / 100; this.p; } static clear(){ ctx.clearRect(0, 0, canvasWidth, canvasHeight); } draw(){ // Visualize ------- this.visualize(); // ----------------- this.p = this.percentage * this.w; if(this.p <= this.h){ ctx.beginPath(); ctx.arc(this.h / 2 + this.x, this.h / 2 + this.y, this.h / 2, Math.PI - Math.acos((this.h - this.p) / this.h), Math.PI + Math.acos((this.h - this.p) / this.h)); ctx.save(); ctx.scale(-1, 1); ctx.arc((this.h / 2) - this.p - this.x, this.h / 2 + this.y, this.h / 2, Math.PI - Math.acos((this.h - this.p) / this.h), Math.PI + Math.acos((this.h - this.p) / this.h)); ctx.restore(); ctx.closePath(); } else { ctx.beginPath(); ctx.arc(this.h / 2 + this.x, this.h / 2 + this.y, this.h / 2, Math.PI / 2, 3 / 2 *Math.PI); ctx.lineTo(this.p - this.h + this.x, 0 + this.y); ctx.arc(this.p - (this.h / 2) + this.x, this.h / 2 + this.y, this.h / 2, 3 / 2 * Math.PI, Math.PI / 2); ctx.lineTo(this.h / 2 + this.x, this.h + this.y); ctx.closePath(); } ctx.fillStyle = this.color; ctx.fill(); } visualize(){ if (wholeprogressbar.checked === true){ this.showWholeProgressBar(); } } showWholeProgressBar(){ ctx.beginPath(); ctx.arc(this.h / 2 + this.x, this.h / 2 + this.y, this.h / 2, Math.PI / 2, 3 / 2 * Math.PI); ctx.lineTo(this.w - this.h + this.x, 0 + this.y); ctx.arc(this.w - this.h / 2 + this.x, this.h / 2 + this.y, this.h / 2, 3 / 2 *Math.PI, Math.PI / 2); ctx.lineTo(this.h / 2 + this.x, this.h + this.y); ctx.strokeStyle = '#000000'; ctx.stroke(); ctx.closePath(); } get PPercentage(){ return this.percentage * 100; } set PPercentage(x){ this.percentage = x / 100; } }// We create new progress barsprogressbar2 = new progressBar({x: 10, y: 10, width: 400, height: 35}, "#FF1700", 50);// progressbar2.draw(); ---> No need coz we draw them laterprogressbar = new progressBar({x: 10, y: 60, width: 400, height: 35}, "#FF1700", 0);// progressbar.draw(); ---> No need coz we draw them later// For showing the current percentage (just for example)setInterval(function() { let currentPercentage = progressbar.PPercentage; document.getElementById("percentage").innerHTML = `${Math.round(currentPercentage)} %`;}, 20);// We draw the progress-bars (just for example, one fix at 50% and one moving on a range from 0 to 100 %)let i=0;setInterval(function() { const start = 0; const end = 100; const step = 0.3; progressbar.PPercentage = i * step; progressBar.clear(); progressbar.draw(); progressbar2.draw(); i++; if(progressbar.PPercentage > end){ i = start; }}, 20);<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><canvas id="progressBar" width="420" height="100"></canvas><div> <p> Progression at <span id="percentage"></span></p> <input type="checkbox" id="wholeprogressbar" name="wholeprogressbar" onclick="progressbar.draw()"> <label for="wholeprogressbar">Visualize all the progress bar (100%)</label></div>编辑 :要创建进度条,您只需创建一个新实例progressbar = new progressBar({x: PositionXinTheCanvas, y: PositionYinTheCanvas, width: WidthOfTheProgressBar, height: HeightOfTheProgressBar}, "ColorOfTheProgressBar", CurrentProgression);..然后画它progressbar.draw();如果需要清除画布,请调用该clear()方法。如果您想要为进度条设置动画,您将需要它。由于它是静态方法,因此您需要在类上调用它progressBar:progressBar.clear();