0

I am trying to reset my progress ring, which is drawn with canvas on resize.

Currently, when I resize my window the function is run again as expected, but instead of the canvas being reset another progress ring is being drawn within the same canvas, please see screenshot below:

enter image description here

I have found clearRect() found in an answer here: How to clear the canvas for redrawing and similar solutions but it doesn't seem to resolve my issue.

Please find my codepen with the code: https://codepen.io/MayhemBliz/pen/OJQyLbN

Javascript:

// Progress ring
function progressRing() {
    
    const percentageRings = document.querySelectorAll('.percentage-ring');

    for (const percentageRing of Array.from(percentageRings)) {

        console.log(percentageRing.offsetWidth)

        var percentageRingOptions = {
            percent: percentageRing.dataset.percent,
            size: percentageRing.offsetWidth,
            lineWidth: 30,
            rotate: 0
        }

        var canvas = document.querySelector('.percentage-ring canvas');
        var span = document.querySelector('.percentage-ring span');

        span.textContent = percentageRingOptions.percent + '%';

        if (typeof (G_vmlCanvasManager) !== 'undefined') {
            G_vmlCanvasManager.initElement(canvas);
        }

        var ctx = canvas.getContext('2d');
    
    //clear canvas for resize
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.beginPath();
    // end clear canvas
    
        canvas.width = canvas.height = percentageRingOptions.size;

        percentageRing.appendChild(span);
        percentageRing.appendChild(canvas);

        ctx.translate(percentageRingOptions.size / 2, percentageRingOptions.size / 2); // change center
        ctx.rotate((-1 / 2 + percentageRingOptions.rotate / 180) * Math.PI); // rotate -90 deg

        //imd = ctx.getImageData(0, 0, 240, 240);
        var radius = (percentageRingOptions.size - percentageRingOptions.lineWidth) / 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', percentageRingOptions.lineWidth, 100 / 100);

        var i = 0; var int = setInterval(function () {
            i++;
            drawCircle('#555555', percentageRingOptions.lineWidth, i / 100);
            span.textContent = i + "%";
            if (i >= percentageRingOptions.percent) {
                clearInterval(int);
            }
        }, 50);

    }
}

window.addEventListener('load', progressRing);
window.addEventListener('resize', progressRing);

HTML:

<div class="percentage-ring" data-percent="88">
  <span>88%</span>
  <canvas></canvas>
</div>

Your help would be greatly appreciated.

Thanks in advance

MayhemBliz
  • 227
  • 2
  • 12

1 Answers1

0

1. Clear size problem

var canvas = document.querySelector('.percentage-ring canvas');

var ctx = canvas.getContext('2d');

ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

You have to specify canvas size with (canvas.width, canvas.height) instead of ctx.canvas.width, ctx.canvas.height

ctx.clearRect(0, 0, canvas.width, canvas.height);

2. Interval timer usage problem

If progressRing() is called again after setInterval() without clearInterval(), e.g., due to resizing, it will continue to run with the previous interval execution surviving. This will cause the ring to be drawn twice, thrice and more.

Place var int = 0; outside functions. This initializes the int to 0 first.

And modify var int = setInterval( to int = setInterval(

Then place the following code at the beginning of progressRing()

if (int) {
    clearInterval(int);
    int = 0;
}

And also place int = 0; immediately after the clearInterval() call that was already there.

  • Thanks for your answer, I amended the code in the codepen with your suggestion but the canvas still doesn't reset and is duplicating when I resize the window. – MayhemBliz May 05 '22 at 14:06
  • Okay, so it now clears correctly. And I found another problem and added a solution for it to my answer. Perhaps this issue is what you meant from the beginning. – Itagaki Fumihiko May 05 '22 at 16:48
  • Thanks again for the follow-up response it is greatly appreciated. Unfortunately, I have applied those code changes to my codepen as you suggest and the ring is still being drawn multiple times when the window is resized. – MayhemBliz May 05 '22 at 17:25
  • Move `var int = 0;` to outside all functions including `progressRing()`. The best is the first line. – Itagaki Fumihiko May 06 '22 at 00:16
  • Itagaki; thank you so much for your persisted help with this. – MayhemBliz May 06 '22 at 09:22