Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Progress circle with spaces between colors

I am trying to achieve this effect (spaces between the color blue and grey), like in the image attached. Those would be like some margins of other color or no color between the 2 colors.

What I would like to achieve: arcs with spaces in between.

But currently managed to this (without spaces).

What I have now: arcs with no space in between.

function loadPieCircle() {
  var el = document.getElementsByClassName('chart'); // get canvas
  for (i = 0; i < el.length; i++) {
    var options = {
      percent: el[i].getAttribute('data-percent') || 25,
      size: el[i].getAttribute('data-size') || 220,
      lineWidth: el[i].getAttribute('data-line') || 15,
      rotate: el[i].getAttribute('data-rotate') || 0
    }
    var canvas = document.getElementById('canvas-' + i);

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

    var ctx = canvas.getContext('2d');
    canvas.width = canvas.height = options.size;

    el[i].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) / 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 = 'square'; // butt, round or square
      ctx.lineWidth = lineWidth;
      ctx.stroke();
    };

    drawCircle('#555555', options.lineWidth, 100 / 100);
    drawCircle('#18aace', options.lineWidth, options.percent / 100);
  }
}
loadPieCircle();
.chart {
  position: relative;
  margin: 0 auto;
  width: 220px;
  height: 220px;
}

canvas {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
}

span.percentage_circle {
  color: #555;
  display: block;
  line-height: 38px;
  text-align: center;
  width: 220px;
  font-family: sans-serif;
  font-size: 30px;
  font-weight: 100;
  margin-left: 0px;
  padding: 72px 0px;
}
<div class="chart" data-line="25" data-percent="70">
  <span class="percentage_circle" id="percentage_circle-0">
    Module<br>
    <strong>13/20</strong>
  </span>
  <canvas id="canvas-0" class="canvas" height="220" width="220"></canvas>
</div>

It can also be found on JSFiddle.

like image 723
Adrian Avatar asked Mar 21 '17 07:03

Adrian


1 Answers

Here is a simple solution :

  • draw both of your arcs, touching each other.
  • set the globalCompositeOperation of your context to 'destination-out'
  • draw a closed arc, with a bigger radius, over these arcs. (green in following pic)

Thanks to the gCO, the closed arc is now transparent.

enter image description here

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

function circleChart(perc) {
  var gap = 6;
  var rad = 85;
  var center = canvas.height / 2;
  var start = -Math.PI / 2;
  var end = start + Math.PI * (perc / 50);
  ctx.lineWidth = 25;
  
  ctx.clearRect(0,0,canvas.width, canvas.height);
  ctx.strokeStyle = '#555555';
  ctx.beginPath();
  ctx.arc(center, center, rad, start, end, true);
  ctx.stroke();

  ctx.strokeStyle = '#18aace';
  ctx.beginPath();
  ctx.arc(center, center, rad, start, end);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(center, center);
  ctx.arc(center, center, rad * 1.5, start, end, true);
  ctx.closePath();
  ctx.lineWidth = gap;
  ctx.globalCompositeOperation = 'destination-out';
  ctx.stroke();

  ctx.globalCompositeOperation = 'source-over';
}
inp.oninput = function(){circleChart(this.value)};
circleChart(75);
body{background: #f3f5f6;}
<input type="range" min="0.1" max="100" step=".5" value="75" id="inp"/>
<canvas id="canvas" width="220" height="220"></canvas>

Ps: I'll let you handle the 0 case as an exercise.

like image 168
Kaiido Avatar answered Oct 11 '22 11:10

Kaiido