进度圈更新百分比

Updating percentage in progress circle

我正在使用此处给出的备选方案之一 (CSS Progress Circle) 构建一个带有进度圈的待办事项列表。在我的 script.js 中,我定义了函数 drawRingProgress(),当我在脚本末尾执行它时,它会呈现 canvas。

当我的脚本的其他功能被执行以添加任务、编辑、删除或将它们标记为完成时,参数 pendingTaskscompletedTasks 得到更新。但是,如果我在其他提到的函数中调用函数 drawRingProgress(),为了更新进度,canvas 会在其他地方多次错误绘制(取决于这些函数的 HTML 元素作用于)。呈现更新进度百分比的正确方法是什么?

Link 到工作示例: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, 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, 0, radius, 0, 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.lineWidth, options.percent / 100)
}

drawRingProgress(pendingTasks, completedTasks);

下面是我绘制图表的方式。我已经从中删除了所有其他函数,因此它仅根据您设置的变量显示图形进度。弄清楚其他功能后,您可以通过该方法更新它们。

首先我会在脚本的开头获取 canvas 并将变量指定为全局变量。

其次,我会把白色甜甜圈画平。除非您打算以某种方式更改它,否则函数 drawGraph() 将被调用一次,仅此而已。

第三个函数 drawRingProgress() 会在您添加、删除或完成任务时从其他函数调用。确保这些函数在调用 drawRingProgress().

之前也会更新 pendingTaskscompletedTasks

drawRingProgress() 中,我添加了文本,因为 canvas 具有内置方法,因此您不需要使用 <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, 0, 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, canvas.height/2, 50, 0, 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, Geneva, Tahoma, 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 */
/* 
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>

我也不确定您使用 bootstraps 图表的目的是什么。我以前没有使用过它,但是从检查文档来看,您似乎并没有真正为它进行适当的编码。另外你有一个 <div> 和 class 的图表而不是 <canvas> 这对我来说似乎是错误的(但就像我说的我以前没有使用过它)。在此处的示例中,我将其更改为 <canvas> 并且还删除了您与跨度一起创建的 canvas。

希望这就是您想要的,如果不是,也许您仍然可以将我这里的内容与您真正想要的拼凑起来。

嘿 Carlos 和所有对解决方案感兴趣的人。

在研究代码后,我注意到问题在于每次调用函数但从未删除时创建元素 spancanvas

解决方案是让这些元素开始,即在 html 代码中 ||或者在调用函数之前创建一次。

至于变量pendingTaskscompletedTasks,我建议将它们更改为pendingTaskstotalAmountOfTasks。 (除非他们可以处于第三种状态。) 那么你要喂入圆圈的比例是pendingTasks/totalAmountOfTasks.

记得在没有任务时检查是否被零除!

干杯,

托马斯