如何在径向进度条上显示部分?

时间:2016-05-18 12:29:18

标签: javascript html css canvas

我目前有一个像“实心”边框的径向进度条,我想要一个带有截面的径向进度条(比如“虚线”边框,但对它有更多控制)。

我在寻找:

enter image description here

这是我到目前为止所做的:

var el = document.getElementById('graph'); // get canvas

var options = {
  percent: el.getAttribute('data-percent'),
  size: el.getAttribute('data-size'),
  lineWidth: el.getAttribute('data-line'),
  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

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

drawCircle('#57d39d', options.lineWidth, 100 / 100);
drawCircle('#14928e', options.lineWidth, options.percent / 100);
div {
  position: relative;
  margin: 30px;
  width: 110px;
  height: 110px;
}
canvas {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
}
span {
  color: black;
  display: block;
  line-height: 110px;
  text-align: center;
  width: 110px;
  font-family: sans-serif;
  font-weight: bold;
  font-size: 30px;
  margin-left: 5px;
}
<div class="chart" id="graph" data-percent="30" data-size="110" data-line="6"></div>

2 个答案:

答案 0 :(得分:3)

受到sass & haml笔的启发:

代码段

下面的

Demo和纯HTML / CSS

&#13;
&#13;
.boo {
  text-align: left;
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -35px;
  width: 70px;
  height: 70px;
  background: lime;
  z-index: -1;
  border-radius: 100%;
}
.boo:nth-child(1) {
  transform: rotate(-71deg) translate(70px);
}
.boo:nth-child(2) {
  transform: rotate(1deg) translate(70px);
}
.boo:nth-child(3) {
  transform: rotate(73deg) translate(70px);
}
.boo:nth-child(4) {
  transform: rotate(145deg) translate(70px);
}
.boo:nth-child(5) {
  transform: rotate(217deg) translate(70px);
}

.a1 .boo + .boo {
  background: gray;
}

.a2 .boo:nth-child(2) ~ .boo {
  background: gray;
}

.a3 .boo:nth-child(3) ~ .boo {
  background: gray;
}

.a4 .boo:nth-child(4) ~ .boo {
  background: gray;
}

.a1:after {
  content: '1/5';
}

.a2:after {
  content: '2/5';
}

.a3:after {
  content: '3/5';
}

.a4:after {
  content: '4/5';
}

.a5:after {
  content: '5/5';
}

.gge {
  float: left;
  font-size: 50px;
  position: relative;
  width: 150px;
  border-radius: 100%;
  text-align: center;
  margin: 20px 10px ;
  padding: 15px;
  overflow: hidden;
}

.gge:before {
  content: '';
  display: inline-block;
  padding: 50% 0;
  margin-left: -0.25em;
  vertical-align: middle;
  z-index: 2;
}

.gge:after {
  line-height: 150px;
  position: absolute;
  z-index: 1;
  background: white;
  border-radius: 100%;
  left: 15px;
  top: 15px;
  right: 15px;
  bottom: 15px;
}

.boo:before,
.boo:after {
  left: auto;
  content: '';
  position: absolute;
  height: 20px;
  width: 16px;
  background: inherit;
  border-radius: 8px;
  transform: rotate(-35deg);
}

.boo:before {
  top: -7px;
  right: 21px;
}

.boo:after {
  transform: rotate(30deg);
  bottom: -7px;
  right: 21px;
  left: auto;
}
&#13;
<div class='gge a1'>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
</div>
<div class='gge a2'>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
</div>
<div class='gge a3'>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
</div>
<div class='gge a4'>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
</div>
<div class='gge a5'>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
  <div class='boo'></div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

你可以完全使用破折号模式。只需根据圆周长度计算短划线模式:

假设变量已声明:

radius = 140;
circum = 2 * Math.PI * radius;
gap = 7;
sections = 5;
dashOn = circum / sections - gap;

然后以这种方式设置破折号模式:

ctx.setLineDash([dashOn, gap]);    // set dash pattern
ctx.lineDashOffset = -gap * 0.5;   // center dash gap

我想让第一个间隙/部分朝上,你只需要首先旋转上下文-90°。

更新:如果您想为每个细分受众群提供圆顶上限,只需执行以下操作:

ctx.lineCap = "round";

然而,“上限”将消耗部分差距,因此我们需要通过将线宽添加到间隙值来补偿间隙的大小。

实施例

演示如何设置和删除短划线图案,并演示如何旋转上下文以便从顶部位置绘制剖面,以及如何制作圆角。

var ctx = c.getContext("2d"),
    radius = 140,
    circum = 2 * Math.PI * radius,
    lineWidth = 12,
    gap = 9 + lineWidth;                         // compensate for rounded caps

function render() {
  var sections = s.max = +seg.value;
  var dashOn = circum / sections - gap;
  var t = +s.value / sections;                   // normalize value on sections

  ctx.clearRect(0, 0, 300, 300);                 // clear previous drawn content
  ctx.setTransform(1,0,0,1, 150, 150);           // translate to center
  ctx.rotate(-Math.PI*0.5);                      // rotate -90° so 0° is up

  ctx.beginPath();
  ctx.arc(0,0,radius, Math.PI*2*t, Math.PI*2);   // circle from angle x t
  ctx.setLineDash([dashOn, gap]);                // set dash pattern
  ctx.lineDashOffset = -gap * 0.5;               // center dash gap
  ctx.lineWidth = lineWidth;                     // line width
  ctx.lineCap = "round";                         // line width
  ctx.strokeStyle = "#9ac";                      // base color
  ctx.stroke();                                  // render it
  
  ctx.beginPath();
  ctx.arc(0, 0, radius, 0, Math.PI*2 * t);       // render arc based on angle x t
  ctx.strokeStyle = "#06c";                      // top color
  ctx.stroke();

  ctx.setLineDash([]);                           // reset dash
  ctx.setTransform(1,0,0,1,0,0);                 // reset transforms
  // render text here
}

(s.oninput = seg.oninput = render)();            // demo slider and first run
<label>Segments: <input id=seg type=range min=3 max=40 value=5></label><br>
<label>Progress: <input id=s type=range min=0 max=5 value=0></label><br>
<canvas id=c height=300></canvas>