进度圆 - 在圆的末端绘制一个小弧+更多

时间:2016-02-01 14:20:30

标签: css canvas responsive-design geometry css-shapes

如何在进度圆的末端绘制一个小圆圈,并在其上方/上方添加一个小文本块?

示例img:

src/widgets/styles/qstylesheetstyle.cpp

{{1}}

感谢Andre的medium.com文章,我已经编辑了他的版本 - 一个UPDATED版本说明了我想要为给定的%值动态实现的内容:enter image description here

然而,编译的CSS太多了。对于每百分之一的百分比来说,用于定位事物的CSS太多了。当前的CSS(@codepen示例)已经加权~50 KB。不是最好的做法。

我已经在基于JS Canvas的变体上取得了一些进展,将vert& horz居中img定位在画布上方。但对于一个好看的响应式网站来说,它真的是唯一的方法和最佳实践吗?

1 个答案:

答案 0 :(得分:6)

CSS绝对不是正确的工具,我会敦促你放弃这个想法。 Canvas绝对是一个不错的选择,但对于响应式网站,我建议你使用SVG。使用SVG,可以根据用户输入轻松绘制进度圆,并在其顶部添加圆/点。

以下是首次创建进度循环时必须执行的步骤:

  • 获取进度圆的用户输入(0到100),然后根据它计算弧的角度。公式为(输入* 360/100),因为圆圈有360度。
  • SVG弧通常从时钟中的3个位置开始,因此计算出的弧角必须在负值处偏移90度。也就是说,电弧必须在-90度到270度之间。
  • 使用公式将计算的角度转换为弧度 - (角度度数* PI​​ / 180)。
  • 计算弧度角后,使用简单的三角函数根据角度在圆上找到一个点:

    • X坐标= Cos(以弧度表示的角度)*半径+中心点的X坐标。
    • Y坐标= Sin(弧度的角度)*半径+中心点的Y坐标。
  • 一旦找到该点,我们需要创建路径,使其从上一步中找到的点开始,到达圆心,然后到弧的起点,从该点再次将弧线绘制到原点。路径是以这种方式创建的,因为我们需要路径在所需的点结束(因为我们将标记附加到终点)。

  • 电弧创建需要注意的一点是任何角度> 180度需要两个弧命令来创建。第一个弧将是时钟到6位置的12位置,下一个弧将用于其余位置。所以,我们使用if / else循环。

要在其尖端添加点/圆,需要执行以下操作:

  • marker元素添加到SVG,并使用circle元素创建圆形标记。 circle元素有3个属性 - cx,cy是点的中心点,r是点的半径。
  • 使用marker-end属性,此标记会添加到path。设置此属性意味着创建的任何路径都会在其结束点自动附加此点。不需要为此进行其他编码,因为SVG会自动处理定位。

也可以使用text元素添加文字,然后可以使用xy属性设置其位置。 (此位仍需要在下面的代码段中调整。

<强>演示:

下面是一个非常粗略的实施演示。

&#13;
&#13;
window.onload = function() {
  var btn = document.querySelector('button'),
    inp = document.querySelector('#progress'),
    path = document.querySelector('#p'),
    text = document.querySelector('#val'),
    rect = document.querySelector('rect'),
    output = document.querySelector('#path-output');
  var x = 0,
    y = 0,
    r = 30,
    cx = 50,
    cy = 50,
    d = '',
    fill = 'yellowgreen',
    stroke = 'transparent';
  btn.addEventListener('click', function() {
    progress = (inp.value == '') ? 0 : inp.value;
    arcRad = ((progress * 360 / 100) - 90) * Math.PI / 180;

    x = Math.cos(arcRad) * r + cx;
    y = Math.sin(arcRad) * r + cy;

    if (progress > 0 && progress <= 50) {
      d = 'M' + x + ',' + y + ' L' + cx + ',' + cy + ' L' + cx + ',' + (cy - r) + ' A' + r + ',' + r + ' 0 0,1' + x + ',' + y;
      setColors(fill, stroke);
      setOutput();
    } else if (progress > 50 && progress <= 100) {
      d = 'M' + x + ',' + y + ' L' + cx + ',' + cy + ' L' + cx + ',' + (cy - r) + ' A' + r + ',' + r + ' 0 0,1' + cx + ',' + (cy + r) + ' A' + r + ',' + r + ' 0 0,1' + x + ',' + y;
      setColors(fill, stroke);
      setOutput();
    } else {
      text.innerHTML = '';
      path.setAttribute('d', '');
      output.innerHTML = 'Enter a value between 0 and 100';
      setColors('transparent', 'transparent');
    }

    if (progress > 0 && progress <= 10) {
      rect.setAttribute('x', x);
      rect.setAttribute('y', y + 7.5);
      text.setAttribute('x', x + 2);
      text.setAttribute('y', y + 15);
    } else if (progress > 10 && progress <= 62) {
      rect.setAttribute('x', x - 5);
      rect.setAttribute('y', y + 7.5);
      text.setAttribute('x', x - 3.5);
      text.setAttribute('y', y + 15);
    } else if (progress > 62 && progress <= 100) {
      rect.setAttribute('x', x - 5);
      rect.setAttribute('y', y - 15);
      text.setAttribute('x', x - 3.5);
      text.setAttribute('y', y - 7.5);
    }

  });

  function setColors(fill, stroke) {
    rect.setAttribute('fill', fill);
    rect.setAttribute('stroke', stroke);
    path.setAttribute('fill', fill);
    path.setAttribute('stroke', stroke);
  }

  function setOutput() {
    path.setAttribute('d', d);
    text.innerHTML = progress;
    output.innerHTML = 'Angle in Radians: ' + arcRad + '<br/>';
    output.innerHTML += 'Point in Circle: ' + x + ',' + y + '<br/>';
    output.innerHTML += 'Path d attribute: ' + d;
  }
}
&#13;
svg {
  width: 200px;
  height: 200px;
}
.output {
  min-height: 20px;
}
h4 {
  border-bottom: 1px solid;
}
&#13;
<input id='progress' type='number' />
<button>Generate</button>
<br/>
<svg viewBox='0 0 100 100'>
  <defs>
    <marker id='dot' viewBox='0 0 10 10' markerHeight='10' markerWidth='10' refX='5' refY='5'>
      <circle cx='5' cy='5' r='2' />
    </marker>
  </defs>
  <path d='' marker-end='url(#dot)' id='p' stroke='transparent' fill='transparent' />
  <rect height='10' width='10' x='10' y='10' stroke='transparent' fill='transparent' />
  <text x='10' y='10' id='val' font-family='Arial' font-size='6'></text>
</svg>
<div class='output'>
  <h4>Output:</h4>
  <output id='path-output'></output>
</div>
&#13;
&#13;
&#13;

进一步阅读:

您可以在以下链接中阅读有关SVG及其元素和属性的更多信息:

SVG Paths | Marker element | Text element | Circle element