进度圆 - 在圆的末端绘制一个小圆弧+更多 [英] Progress circle - draw a small arc at the end tip of the circle + more

查看:183
本文介绍了进度圆 - 在圆的末端绘制一个小圆弧+更多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



示例img



 < div class =radial-progressdata-progress =0> 
< div class =circle>
< div class =img>< / div>
< div class =mask full>
< div class =fill>< / div>
< / div>
< div class =mask half>
< div class =fill>< / div>
< div class =fill fix>< / div>
< / div>
< div class =shadow>< / div>
< / div>
< div class =inset>
< div class =percentage>
< div class =numbers>< span> - < / span>< span> 0%< / span>< span> 1%< / span> <!--- lots of spans --->
< / div>
< / div>
< / div>

感谢Andre的media.com文章,我已经编辑了他的版本 - 一个UPDATED版本说明了我想针对给定的%值动态实现的内容: http://codepen.io/Inlesco/pen / pgKXeG



但是,编译的CSS太多了。对于每100%的100%,将有太多的CSS定位的东西。当前的CSS(@codepen示例)已经加权〜50 KB。不是最好的做法。



我已经在基于JS Canvas的变体上做了一些进展,将vert& horz居中的img定位在画布上。

解决方案

CSS绝对不是一个正确的工具为了这样做,我敦促你放弃这个想法。 Canvas绝对是一个很好的选择,但对于响应式网站,我建议你使用SVG。使用SVG,很容易根据用户输入绘制进度圆,并在其顶端添加圆/点。



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




  • 获取进度圆(0到100)的用户输入,然后根据它计算弧的角度。公式为(输入* 360/100),因为圆有360度。

  • SVG弧通常从时钟中的3的位置开始,因此计算出的弧的角度必须为在负值偏移90度。

  • 使用公式 - (Angle in Degrees * PI / 180)将计算的角度转换为弧度。

  • 计算以弧度为单位的角度后,使用简单的三角函数基于角度在圆上找到一个点:




    • X坐标= Cos(以弧度表示的角度)*半径+中心点的X坐标。

    • Y坐标= Sin中心点。


  • 找到点后,我们需要创建路径,在上一步中找到,进入圆的中心,然后到圆弧的起点,从该点再次将圆弧绘制到原点。路径以这种方式创建,因为我们需要路径在所需的点结束(因为我们将标记添加到终点)。


  • 与弧创建是任何角度> 180度将需要两个弧命令创建。第一个弧将是12的位置在时钟到6的位置,下一个弧将是其余的。因此,我们使用了一个if / else循环。



要在其尖端添加点/圆, done:




  • 将一个标记元素添加到SVG使用 circle 元素创建圆形。 circle 元素需要3个属性 - cx,cy是点的中心点,r是点的半径。

  • 使用标记结束属性,此标记将添加到路径。设置此属性意味着所创建的任何路径都将在其结束点自动附加此点。由于SVG自动处理定位,因此无需进行其他编码。



文本也可以使用 text 元素添加,使用 x y 属性设置。 (

b

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



  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 +'' ,如果进度> 50&&& amp;进度< = 100){d ='M'+ x + 1'+ 1'+ 1'+ 1'+ x +','+ y; setColors(fill,stroke); setOutput() ','+ y +'L'+ cx +','+ cy +'L'+ cx +', 1'+ cx +','+(cy + r)+'A'+ r +','+ r +'0 0,1'+ x +','+ y; setColors(fill,stroke); setOutput ('transparent','transparent');};} {return;};} } 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; }}  

  svg {width:200px; height:200px;}。output {min-height:20px;} h4 {border-bottom:1px solid;}  

 < 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 =输出'> < h4>输出:< / h4> < output id ='path-output'>< / output>< / div>  


$ b

进一步阅读:



您可以在以下链接中了解更多关于SVG及其元素和属性:



SVG路径 | 标记元素 | 文本元素 | 圈子元素


How do I draw a small circle at the end tip of a progress circle, plus adding a small text block below / above it?

Example img:

<div class="radial-progress" data-progress="0">
    <div class="circle">
    <div class="img"></div>
        <div class="mask full">
            <div class="fill"></div>
        </div>
        <div class="mask half">
            <div class="fill"></div>
            <div class="fill fix"></div>
        </div>
        <div class="shadow"></div>
    </div>
    <div class="inset">
        <div class="percentage">
            <div class="numbers"><span>-</span><span>0%</span><span>1%</span> <!--- lots of spans --->
        </div>
    </div>
</div>

Thanks to Andre's medium.com article, I've already edited his version a little - an UPDATED version illustrates what I want to achieve dynamically for a given % value: http://codepen.io/Inlesco/pen/pgKXeG

However, the compiled CSS is way too much. For each % out of 100, there'll be too much CSS for positioning things. The current CSS (@codepen example) already weights ~50 KB. Not the best practice.

I've already done some progress on a JS Canvas-based variant of this, positioning the vert&horz centered img above the canvas. But is it really the only way and best practice for a good-looking responsive website?

解决方案

CSS is definitely not the right tool for doing this and I would urge you to give up on that idea. Canvas is definitely a good option but for a responsive website, I would recommend you to use SVG. With SVG, it is easy to draw the progress circle based on user input and also add the circle/dot at the tip of it.

The following are the steps that would have to be performed to first create the progress circle:

  • Get the user input for the progress circle (0 to 100) and then calculate the arc's angle based on it. The formula would be (input * 360/100) because a circle has 360 degrees.
  • SVG arcs generally start from the 3's position in a clock and so the calculated angle of arc has to be offset by 90 degree in the negative. That is, the arc has to be from -90 degree to 270 degree.
  • Convert the calculated angle into radians using the formula - (Angle in Degrees * PI / 180).
  • Once the angle in radians is calculated, find a point on the circle based on the angle using simple trigonometric functions:

    • X coordinate = Cos(Angle in Radians) * Radius + X coordinate of center point.
    • Y coordinate = Sin(Angle in Radians) * Radius + Y coordinate of center point.
  • Once the point is found, we need to create the path such that it starts at the point that was found in the previous step, goes to the center of circle, then to the starting point of the arc and from that point draw the arc again to the original point. The path is created this way because we need the path to end at the required point (because we will be attaching the marker to the end point).

  • One thing to note with arc creation is that any angle > 180 degree would need two arc commands to create. The first arc would be 12's position in clock to 6's position and the next arc would be for the rest. So, we make use of an if/else loop.

For adding the dot/circle at its tip, the following need to be done:

  • A marker element is added to the SVG and a marker in the form of a circle is created using the circle element. The circle element takes 3 attributes - cx, cy are the center points of the dot and r is the radius of the dot.
  • Using the marker-end attribute, this marker is then added to the path. Setting this attribute will mean that any path that is created would have this dot automatically appended at its ending point. No other coding needs to be done for this because SVG automatically takes care of positioning.

Text can also be added using the text element and then its position can be set using the x and y attributes. (This bit still needs tuning in the below snippet.)

Demo:

Below is a very rough demo of the implementation.

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;
  }
}

svg {
  width: 200px;
  height: 200px;
}
.output {
  min-height: 20px;
}
h4 {
  border-bottom: 1px solid;
}

<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>

Further Reading:

You can read more about SVG, its elements and attributes in the following links:

SVG Paths | Marker element | Text element | Circle element

这篇关于进度圆 - 在圆的末端绘制一个小圆弧+更多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆