JSFiddle - React, Tailwind, and code Playground
by Ed Bulikyan
HTML
<div class="columns">
<div><div class="dial" data-width="80" data-lineWidth="2">12.2567567</div></div>
<div><div class="dial blue" data-width="180" data-lineWidth="41">66</div></div>
<div><div class="dial error" data-lineWidth="20" data-lineRound="true">33.6567567</div></div>
</div>
<div class="columns">
<div><div class="dial" data-width="40" data-lineWidth="41">40.2567567</div></div>
<div><div class="dial success" data-width="80">81.1567567</div></div>
</div>
SCSS
body {
background-color: #2f323e;
font-family: Consolas, monaco, monospace;
}
.columns {
display: flex;
align-items: center;
> div {
flex: 1;
text-align: center;
padding: 20px;
}
}
.dial {
border-color: #22262f;
color: #689F38;
display: inline-block;
text-align: left;
p {
text-align:center;
font-weight: bold;
color: #fff;
white-space: nowrap;
position: relative;
overflow: hidden;
z-index: 1;
margin: 0;
}
canvas {
position: absolute;
}
}
/* разные цветовые схемы */
.dial {
&.error {
color: #d46d71;
p {
color: #d46d71;
}
}
&.success {
color: #689F38;
border-color: rgba(#d46d71, 0.4);
p{
color: #689F38;
}
}
&.blue {
color: #1390d4;
}
}
JavaScript
$(function(){
// Ищем все элементы с class="dial"
var dials = $(".dial");
// Перебираем все .dial и пихуем туда canvas с графиком.
for (i=0; i < dials.length; i++){
var width = (typeof $(dials[i]).attr("data-width") != 'undefined') ? Math.round($(dials[i]).attr("data-width")) : 80;
var procent = (Number($(dials[i]).html()) > 0 && Number($(dials[i]).html()) < 100) ? Math.round(Number($(dials[i]).html()) * 10)/10 : 0;
var lineWidth = (typeof $(dials[i]).attr("data-lineWidth") != 'undefined') ? Number($(dials[i]).attr("data-lineWidth")) : width / 10;
var size = width+lineWidth;
var lineRound = (typeof $(dials[i]).attr("data-lineRound") != 'undefined') ? true : false;
var borderColor = $(dials[i]).css("border-color");
var color = $(dials[i]).css("color");
// Меняем размер .dial в зависимости от data-width="80"
// Устанавливаем размер шрифта так что бы он вмещался в круг не задевая border
$(dials[i]).css({"width": size + 'px', "height": size + 'px', "font-size": Math.floor((width-lineWidth) / 4) + 'px'});
// Вставляем canvas такого же размера что и родитель.
$(dials[i]).html('<canvas id="dial' + i + '" width="' + size + '" height="' + size + '"></canvas><p>' + procent + '%</p>');
// Выравниваем текст по вертикали
$("p", dials[i]).css({"line-height": size + 'px'});
var canvas = document.getElementById("dial" + i);
var context = canvas.getContext("2d");
// считаем по формуле радианы
var radian = 2*Math.PI*procent/100;
// рисуем круг для фона
context.arc(width/2+lineWidth/2, width/2+lineWidth/2, width/2, 0, 2*Math.PI, false);
context.lineWidth = lineWidth;
context.strokeStyle = borderColor;
context.stroke();
context.beginPath();
// рисуем круг с процентами
context.arc(width/2+lineWidth/2, width/2+lineWidth/2, width/2, 1.5 * Math.PI, radian+1.5 * Math.PI, false);
context.strokeStyle = color;
// Можно скруглить концы отрезка если передан параметр data-lineRound
if (lineRound == true && lineWidth < width)...