1

Thanks to another SO who has kindly assisted me with this task, I have a canvas element successfully animating a circle in the way of which I desire. However, whilst the animation is occurring, the background of the canvas is visible and therefore overlays anything behind the canvas. I am aware that canvas' have transparent backgrounds by default, but this I believe is actually unrelated...

Please see the following example of what has been achieved and the error that is occurring throughout the initial animation.

https://jsfiddle.net/sm8ozqLg/1/

I believe the code in question is the following:

function convertToRadians(degree) {
    return degree*(Math.PI);
}

var canvas = document.getElementById('progress');
var context = canvas.getContext('2d');

function showProgress(percent){
    console.log(percent);
    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;
    var sections = 6;
    var radius = 106;

    context.beginPath();
    context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
    var grd = context.createLinearGradient(canvas.width, 0, 0, canvas.height);
    grd.addColorStop(0, '#d586f4');   
    grd.addColorStop(1, '#5c00d2');
    context.fillStyle = grd;
    context.fill();

    context.beginPath();
    if (percent){
        var amt = ((2 / 100) * percent) + 1.5;
        if (amt > 2) amt = amt - 2;
        context.arc(centerX, centerY, radius, amt * Math.PI, 1.5 * Math.PI, false); //25%
    } else context.arc(centerX, centerY, radius, 0 * Math.PI, 2 * Math.PI, false); //0%

    context.lineWidth = (radius - .3) * 2;
    context.strokeStyle = '#ffffff';
    context.stroke();
}

var timer = setInterval(function(){ runTimer() }, 20);
var t = 0;

function runTimer(){
    if (t == 101) stopTimer();
    context.clearRect(0, 0, canvas.width, canvas.height);
    showProgress(t);
    t++;
}

function stopTimer() {
    clearInterval(myVar);
}

Can anyone work out why the white is overlaying the other elements?

Ben Carey
  • 16,540
  • 19
  • 87
  • 169

2 Answers2

2

Try this:

function toRad(degrees) { return degrees * (Math.PI / 180); }
function map(value, minIn, maxIn, minOut, maxOut) {
  return (value - minIn) * (maxOut - minOut) / (maxIn - minIn) + minOut;
}
var canvas = document.getElementById('progress');
var context = canvas.getContext('2d');
function showProgress(percent) {
  var centerX = canvas.width / 2;
  var centerY = canvas.height / 2;
  var sections = 6;
  var radius = 94;

  context.beginPath();
  context.arc(centerX, centerY, radius, toRad(-90), toRad(map(percent, 0, 100, -90, 270)), false);
  var grd = context.createLinearGradient(canvas.width, 0, 0, canvas.height);
  grd.addColorStop(0, '#d586f4');
  grd.addColorStop(1, '#5c00d2');
  context.lineWidth = 22;
  context.strokeStyle = grd;
  context.stroke();
}

function runTimer() {
  if (t == 101) stopTimer();
  context.clearRect(0, 0, canvas.width, canvas.height);
  showProgress(t);
  t++;
}

function stopTimer() { clearInterval(timer); }

var timer = setInterval(function () { runTimer(); }, 20);
var t = 0;
html, body {
    background: #f5f5f5;
}
#progress_container {
    position: absolute;
    border-radius: 50%;
    width: 240px;
    height: 240px;
    top: 50%;
    left: 50%;
    margin-top: -120px;
    margin-left: -120px;
    background: #D0D2D5;
    background: -moz-linear-gradient(top, #d0d2d5 0%, #ffffff 100%);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #d0d2d5), color-stop(100%, #ffffff));
    background: -webkit-linear-gradient(top, #d0d2d5 0%, #ffffff 100%);
    background: -o-linear-gradient(top, #d0d2d5 0%, #ffffff 100%);
    background: -ms-linear-gradient(top, #d0d2d5 0%, #ffffff 100%);
    background: linear-gradient(to bottom, #d0d2d5 0%, #ffffff 100%);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0d2d5', endColorstr='#ffffff', GradientType=0);
    -webkit-box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 0.15);
    -moz-box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 0.15);
    box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 0.15);
    z-index: 5;
}
#progress_dial {
    position: absolute;
    border-radius: 50%;
    width: 212px;
    height: 212px;
    margin: 14px;
    -webkit-box-shadow: inset 0px 3px 5px 0px rgba(5, 71, 110, 0.51), inset 0px 0px 19px 0px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: inset 0px 3px 5px 0px rgba(5, 71, 110, 0.51), inset 0px 0px 19px 0px rgba(0, 0, 0, 0.2);
    box-shadow: inset 0px 3px 5px 0px rgba(5, 71, 110, 0.51), inset 0px 0px 19px 0px rgba(0, 0, 0, 0.2);
    z-index: 6;
}
#progress_shadow {
    position: absolute;
    border-radius: 50%;
    width: 212px;
    height: 212px;
    margin: 14px;
    -webkit-box-shadow: inset 0px 3px 5px 0px rgba(5, 71, 110, 0.51), inset 0px 0px 19px 0px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: inset 0px 3px 5px 0px rgba(5, 71, 110, 0.51), inset 0px 0px 19px 0px rgba(0, 0, 0, 0.2);
    box-shadow: inset 0px 3px 5px 0px rgba(5, 71, 110, 0.51), inset 0px 0px 19px 0px rgba(0, 0, 0, 0.2);
    z-index: 8;
}
#progress {
    position: absolute;
    margin: 9px;
    z-index: 7;
}
#progress_content {
    position: absolute;
    border-radius: 50%;
    width: 170px;
    height: 170px;
    margin: 21px;
    background: #fafafb;
    background-image: url("//images.domain.com/_index/bg-noise.png");
    background-image: url("//images.domain.com/_index/bg-noise.png"), -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fafafb), color-stop(100%, #e1e2e5));
    background-image: url("//images.domain.com/_index/bg-noise.png"), -webkit-linear-gradient(top, #fafafb 0%, #e1e2e5 100%);
    background-image: url("//images.domain.com/_index/bg-noise.png"), -moz-linear-gradient(top, #fafafb 0%, #e1e2e5 100%);
    background-image: url("//images.domain.com/_index/bg-noise.png"), -o-linear-gradient(top, #fafafb 0%, #e1e2e5 100%);
    background-image: url("//images.domain.com/_index/bg-noise.png"), -ms-linear-gradient(top, #fafafb 0%, #e1e2e5 100%);
    background-image: url("//images.domain.com/_index/bg-noise.png"), linear-gradient(to bottom, #fafafb 0%, #e1e2e5 100%);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafb', endColorstr='#e1e2e5', GradientType=0);
    -webkit-box-shadow: 0px 0px 19px 0px rgba(0, 0, 0, 0.2), 0px 0px 3px 1px rgba(0, 0, 0, 0.3), inset 0px -1px 2px 1px rgba(32, 46, 61, 0.9);
    -moz-box-shadow: 0px 0px 19px 0px rgba(0, 0, 0, 0.2), 0px 0px 3px 1px rgba(0, 0, 0, 0.3), inset 0px -1px 2px 1px rgba(32, 46, 61, 0.9);
    box-shadow: 0px 0px 19px 0px rgba(0, 0, 0, 0.2), 0px 0px 3px 1px rgba(0, 0, 0, 0.3), inset 0px -1px 2px 1px rgba(32, 46, 61, 0.9);
    z-index: 9;
}
h1#progress_percentage {
    position: relative;
    margin: 35px 0 0 0;
    z-index:10;
    text-shadow: 0px 1px 1px #fff;
    display: block;
    color: #777;
    font-family:'Open Sans', sans-serif;
    font-weight: 800;
    font-size: 60px;
    padding: 0;
    text-align: center;
    width: 170px;
}
h1#progress_percentage:before {
    content: attr(title);
    position: absolute;
    display: block;
    color: rgba(255, 255, 255, .4);
    text-align: center;
    width: 170px;
    text-shadow: none;
    top: 1px;
    left: 1px;
}
h2#progress_value {
    position: absolute;
    display: block;
    margin: -8px 0 0 0;
    color: #777;
    font-family:'Open Sans', sans-serif;
    font-weight: 800;
    font-size: 18px;
    padding: 0;
    text-align: center;
    width: 170px;
    z-index:10;
    text-shadow: 0px 1px 1px #fff;
}
h2#progress_value:before {
    content: attr(title);
    position: absolute;
    display: block;
    color: rgba(255, 255, 255, .4);
    text-align: center;
    width: 170px;
    top: 1px;
    left: 1px;
    text-shadow: none;
}
<div id="progress_container">
    <svg id="progress_dial" width="212px" height="212px">
        <path d="M 0 106 C 0 47.4571 47.4571 0 106 0 C 164.5429 0 212 47.4571 212 106 C 212 164.5429 164.5429 212 106 212 C 47.4571 212 0 164.5429 0 106 Z" fill="#e0e1e5" />
        <path opacity="0.3882" d="M 106.5 0.5 L 106.5 212.5 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 133.9519 3.9825 L 79.0822 208.7587 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 159.517 14.5719 L 53.517 198.1693 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 181.4704 31.4173 L 31.5637 181.3239 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 198.3157 53.3706 L 14.7183 159.3706 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 208.9052 78.9358 L 4.1289 133.8054 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 212.517 106.3706 L 0.517 106.3706 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 209.0346 133.8224 L 4.2583 78.9528 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 198.4451 159.3876 L 14.8478 53.3876 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 181.5998 181.341 L 31.6931 31.4343 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 159.6464 198.1863 L 53.6465 14.5889 " stroke="#ffffff" stroke-width="1" />
        <path opacity="0.3882" d="M 134.0813 208.7758 L 79.2116 3.9995 " stroke="#ffffff" stroke-width="1" />
    </svg>
    <div id="progress_shadow">
        <div id="progress_content">
             <h1 id="progress_percentage" title="0%">0%</h1>
        </div>
    </div>
    <canvas id="progress" width="224" height="224"></canvas>
</div>

Details:

  • The idea here is that you do not need to create two separate shapes using the arc method but instead, you could achieve the desired result by using only one call to the arc method on a timely basis.
  • Secondly, we needed a way to convert degrees to radians for our arc method which is done here by toRad() method.
  • We also needed to map a value falling between one range, to map / convert / transfer to another range. Here, percent is the value falling between the range of 0 and 100. And it is mapped to a range of -90 and 270. We could have mapped them to 0 and 360 but we needed the circle start from the top and center point location i.e. a 90 degree subtraction.
  • Lastly, some small adjustments needed to be applied on CSS margin rule for #progress element as well as the canvas object in HTML needed a bigger width and height. Plus, the radius variable in JavaScript needed tweaking as well and the lineWidth needed to be an exact number.

Hope this helps.

Tahir Ahmed
  • 5,687
  • 2
  • 17
  • 28
0

Please check following fiddle. I have updated it there.

JS Fiddle

function convertToRadians(degree) {
        return degree*(Math.PI);
    }

    var canvas = document.getElementById('progress');
    var context = canvas.getContext('2d');

    function showProgress(percent){
        console.log(percent);
        var centerX = canvas.width / 2;
        var centerY = canvas.height / 2;
        var sections = 6;
        var radius = 106;

        context.beginPath();
        context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
        var grd = context.createLinearGradient(canvas.width, 0, 0, canvas.height);
        grd.addColorStop(0, '#d586f4');   
        grd.addColorStop(1, '#5c00d2');
        context.fillStyle = grd;
        context.fill();

        context.beginPath();
        if (percent){
            var amt = ((2 / 100) * percent) + 1.5;
            if (amt > 2) amt = amt - 2;
            context.arc(centerX, centerY, radius, amt * Math.PI, 1.5 * Math.PI, false); //25%
        } else context.arc(centerX, centerY, radius, 0 * Math.PI, 2 * Math.PI, false); //0%

        context.lineWidth = (radius - .3) * 2;
        context.strokeStyle = '#ffffff';
        context.stroke();
    }

    var timer = setInterval(function(){ runTimer() }, 20);
    var t = 0;

    function runTimer(){
        if (t == 101) stopTimer();
        context.clearRect(0, 0, canvas.width, canvas.height);
        showProgress(t);
        t++;
    }

    function stopTimer() {
        clearInterval(myVar);
    }