问题描述
我正在使用此处给出的备选方案之一 (CSS Progress Circle) 构建一个带有进度圈的待办事项列表。在我的 script.js 中,我定义了函数 drawRingProgress()
,当我在脚本末尾执行它时呈现画布。
当我的脚本的其他函数被执行以添加任务、编辑、删除或将它们标记为完成时,参数 pendingTasks
和 completedTasks
会更新。但是,如果我在其他提到的函数中调用函数 drawRingProgress()
,为了更新进度,画布会在其他地方多次错误地绘制(取决于这些函数所作用的 HTML 元素)。呈现更新的进度百分比的正确方法是什么?
工作示例链接:https://jsfiddle.net/tailslider13/f4qtmhzj/7/
let pendingTasks = 31;
let completedTasks = 69;
function drawRingProgress(pendingTasks,completedTasks) {
var el = document.getElementById('graph'); // get canvas
let progress_percentage = Math.floor((completedTasks / (completedTasks + pendingTasks)) * 100) || 0;
var options = {
// percent: el.getAttribute('data-percent') || 25,percent: progress_percentage,// size: 110,size: el.getAttribute('data-size') || 220,linewidth: el.getAttribute('data-line') || 15,rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof (G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2,options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getimageData(0,240,240);
var radius = (options.size - options.linewidth) / 3.2;
var drawCircle = function (color,linewidth,percent) {
percent = Math.min(Math.max(0,percent || 1),1);
ctx.beginPath();
ctx.arc(0,radius,Math.PI * 2 * percent,false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt,round or square
ctx.linewidth = linewidth
ctx.stroke();
};
drawCircle('#efefef',options.linewidth,100 / 100);
drawCircle('#046582',options.percent / 100)
}
drawRingProgress(pendingTasks,completedTasks);
解决方法
这是我绘制图形的方式。我已经从中删除了所有其他函数,因此它仅根据您设置的变量显示图形进度。弄清楚其他功能后,您可以通过该方法更新它们。
首先,我会在脚本的开头获取画布,并将变量指定为全局变量。
其次,我会将白色甜甜圈平展。除非您打算以某种方式更改它,否则函数 drawGraph()
将被调用一次,仅此而已。
第三,当您添加、删除或完成任务时,函数 drawRingProgress()
将被其他函数调用。确保这些函数在调用 pendingTasks
之前也更新 completedTasks
和 drawRingProgress()
。
在 drawRingProgress()
中,我添加了文本,因为画布具有内置方法,因此您无需使用 <span>
。至于您的所有选项,我为此删除了它们,但您可以将它们添加回您认为合适的位置。
const inputField = document.getElementById("addTask");
const taskList = document.getElementById("taskList");
var canvas = document.getElementById('graph');
var ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 200;
let pendingTasks = 20;
let completedTasks = 5;
//Progress ring
function drawGraph() {
ctx.beginPath();
ctx.strokeStyle = "white";
ctx.arc(canvas.width/2,canvas.height/2,50,Math.PI*2,false);
ctx.lineCap = 'round'; // butt,round or square
ctx.lineWidth = 15;
ctx.stroke();
ctx.closePath();
}
drawGraph();
function drawRingProgress(pendingTasks,completedTasks) {
let progress_percentage = (completedTasks / pendingTasks) * 100;
ctx.font = "30px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#046582";
ctx.fillText(progress_percentage+'%',canvas.width/2,canvas.height/2);
percent = Math.min(Math.max(0,(progress_percentage/100) || 1),1);
ctx.beginPath();
ctx.save();
ctx.translate(0,canvas.height); // change center
ctx.rotate((-1 / 2 + 0 / 180) * Math.PI); // rotate -90 deg
ctx.arc(canvas.width/2,Math.PI * 2 * percent,false);
ctx.strokeStyle = "#046582";
ctx.lineCap = 'round'; // butt,round or square
ctx.lineWidth = 15;
ctx.stroke();
ctx.restore();
ctx.closePath();
}
drawRingProgress(pendingTasks,completedTasks);
#body {
background-color: #046582;
}
header {
background-color: #f39189;
padding: 50px;
margin: 50px;
position: sticky;
top: 0px;
}
h1 {
text-align: center;
}
.listItem {
margin: 20px 0px;
background-color: white;
}
.container {
background-color: #c4c4c4;
}
.taskList {
list-style-type: none;
background-color: transparent;
overflow: hidden;
margin-top: 150px;
}
.inputContainer {
margin: 50px;
padding: 20px;
max-width: 50%;
width: 100%;
background-color: #f39189;
}
#footer {
text-align: center;
position: sticky;
bottom: 0px;
background-color: #f39189;
padding: 20px;
}
.deleteButton {
background-image: url("/content/delete.png");
background-repeat: no-repeat;
background-size: cover;
cursor: pointer;
width: 30px;
height: 30px;
margin: 15px;
}
#addTask {
font-family: Verdana,Geneva,Tahoma,sans-serif;
font-size: 1.3rem;
}
.taskName {
font-family: Verdana,sans-serif;
font-size: 1.2rem;
}
.listContainer {
height: 1080px;
}
.inputContainer {
position: fixed;
}
.checkedbox {
text-decoration: line-through;
color: #f39189;
}
/* START Styling Progress ring */
.chart {
position: relative;
/* margin:0px; */
width: 220px;
height: 220px;
}
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
}
span {
color: #046582;
display: block;
line-height: 220px;
text-align: center;
width: 220px;
font-family: sans-serif;
font-size: 30px;
font-weight: 100;
margin-left: 5px;
}
/* Links progress ring */
/* https://stackoverflow.com/questions/14222138/css-progress-circle
http://jsfiddle.net/Aapn8/3410/ */
/* END Styling Progress ring */
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Document</title>
<!-- Required meta tags -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous" />
</head>
<div class="container">
<body id="body">
<header class="row justify-content-end">
<h1 class="col-4">Take note</h1>
<!-- Progress ring -->
<div class="col-4">
<canvas class="chart" id="graph"></canvas>
</div>
</header>
<!-- Input field and button -->
<div class="row inputContainer rounded">
<input class="col-auto" type="newTask" placeholder="Enter new Task" id="addTask" />
<button class="col-auto" id="btnAdd">Add</button>
</div>
<!-- List of tasks created -->
<div class="listContainer">
<ul class="taskList rounded" id="taskList"></ul>
</div>
<footer class="row" id="footer">
<h6 class="col w-100">2021</h6>
</footer>
<!-- BOOTSTRAP -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.min.js" integrity="sha384-lpyLfhYuitXl2zRZ5Bn2fqnhNAKOAaM/0Kr9laMspuaMiZfGmfwRNFh8HlMy49eQ" crossorigin="anonymous">
</script>
</body>
</div>
</html>
我也不确定您使用引导程序图表的意图。我以前没有使用过它,但是从检查文档来看,您似乎并没有真正为它进行适当的编码。另外,您有一个 <div>
与图表类,而不是 <canvas>
在我看来是错误的(但就像我说的那样,我以前没有使用过它)。在此处的示例中,我将其更改为 <canvas>
并删除了您正在创建的画布以及跨度。
希望这就是您想要的,如果不是,也许您仍然可以将我在这里的内容与您想要的内容拼凑起来。
,嗨,卡洛斯和所有对解决方案感兴趣的人。
在研究代码后,我注意到问题在于每次函数被调用但从未删除时创建元素 span
和 canvas
。
解决方案是让这些元素一开始就到位,即在 html 代码中 ||或者在调用函数之前创建一次。
对于变量 pendingTasks
和 completedTasks
,我建议将它们更改为 pendingTasks
和 totalAmountOfTasks
。 (除非他们可以处于第三种状态。)
那么你输入圆圈的比例是pendingTasks/totalAmountOfTasks
。
当没有任务时,记得检查除以零!
干杯,
托马斯