Модернизировать doughnut chart

311
05 ноября 2021, 01:10

Появилась такая необходимость модернизировать стандартный doughnut chart, которые предоставляют библиотеки, но не знаю с чего начать. То есть необходимо изменить высоту и размер разных элементов в dought chart. Подскажите, как возможно изменить библиотеки(3d.js, chart.js, echart) или проще попробовать самому нарисовать svg чарт,

Answer 1

Вот вариант на js+svg, тут надо посчитать углы и точки арок:

let data = Array(5).fill(0).map((e,i)=> ({ 
    r1: 10+i*2,  
    r2: -i*0.5,  
    value: Math.random()+0.1,  
    color: `hsl(${i*45},65%,65%)` 
})); 
 
let total = data.reduce((a, d) => a + d.value, 0); 
let r = 40; 
let a = 0; 
 
chart.innerHTML = data.map(d => { 
     
  let cs1 = Math.cos(a); 
  let sn1 = Math.sin(a); 
  let angle = d.value/total*2*Math.PI; 
  a += angle; 
  let cs2 = Math.cos(a); 
  let sn2 = Math.sin(a); 
  let ir = r + d.r1; 
  let or = r + d.r2; 
  let la = angle > Math.PI ? 1 : 0; 
  return `<path d="${[ 
    "M", [cs1*ir, sn1*ir], 
    "A", [ir, ir, 0, la, 1, cs2*ir, sn2*ir], 
    "L", [cs2*or, sn2*or], 
    "A", [or, or, 0, la, 0, cs1*or, sn1*or] 
  ].join('')}" fill="${d.color}"></path>`; 
 
}).join("");
body { 
  margin: 0; 
  overflow: hidden; 
} 
 
path { 
  opacity: 0.7; 
  transition: 1; 
  transition: 500ms; 
  cursor: pointer; 
} 
 
path:hover { 
  opacity: 1; 
}
<svg id=chart viewbox=-60-60,120,120 width=100vw height=100vh></svg>

Answer 2

Для разбиения окружности на сектора вы можете использовать stroke-dasharray

Для смещения начала сектора используется stroke-dashoffset

Здесь нижний круг имеет серый цвет над ним расположен цветной сектор второго круга. При r="40" Полная длина окружности равна perimetr = 2 * 3.14 * 40 = 251,2

В этом примере строка заполнена на 80% amount = 80 , значит её нужно сдвинуть

stroke-dashoffset = perimeter - perimeter * amount / 100 = 50.3

<svg width="100%" height="100%" viewbox="0 0 100 100"> 
    <circle cx="50" cy="50" r="40" fill="tomato"/> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#00CCFF" stroke-dasharray="251.2" stroke-dashoffset="50.3"/> 
    <text x="40" y="50" fill="black" font-size="10">Text</text> 
</svg>

Ниже пример с 50% заполнением

<svg width="100%" height="100%" viewbox="0 0 100 100"> 
    <circle cx="50" cy="50" r="40" fill="tomato"/> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#00CCFF" stroke-dasharray="251.2" stroke-dashoffset="125.6"/> 
    <text x="40" y="50" fill="black" font-size="10">Text</text> 
</svg>

Несколько цветных секторов

<svg width="300px" height="300px" viewbox="0 0 100 100"> 
    <!-- Центральный круг серый цвет --> 
    <circle cx="50" cy="50" r="40" fill="#eee"/> 
     
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/> 
     
    <!-- Progress --> 
    <!-- Пример заполнения секторов Старт 3 часа (дефолтное положение начала рисования окружности)--> 
    <!-- 100% fill --> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" stroke-dasharray="251.2" stroke-dashoffset="0"/> 
    <!-- 80% fill --> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" stroke-dasharray="251.2" stroke-dashoffset="50.3"/> 
    <!-- 70% fill --> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" stroke-dasharray="251.2" stroke-dashoffset="75.36"/> 
    <!-- 50% fill --> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" stroke-dasharray="251.2" stroke-dashoffset="125.6"/> 
    <!-- 40% fill --> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" stroke-dasharray="251.2" stroke-dashoffset="150.72"/> 
    <!-- 20% fill --> 
    <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" stroke-dasharray="251.2" stroke-dashoffset="200.96"/> 
    <!-- Текст в центре --> 
    <text x="40" y="50" fill="black" font-size="10">Text</text> 
</svg>

Пример анимации

$(".progress").each(function() { 
  var dataProgress = $(this).attr("stroke-dashoffset"); 
  $(this).attr("stroke-dashoffset", "251.2"); 
  $(this).animate({ 
    "stroke-dashoffset": dataProgress 
  },1500) 
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
<svg width="300px" height="300px" viewbox="0 0 100 100"> 
        <!-- Center color --> 
        <circle cx="50" cy="50" r="40" fill="#eee"/> 
        <!-- Default color of ring --> 
        <circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="white"/> 
         
    
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" stroke-dasharray="251.2" stroke-dashoffset="0"/> 
        
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" stroke-dasharray="251.2" stroke-dashoffset="50.3"/> 
        
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" stroke-dasharray="251.2" stroke-dashoffset="75.36"/> 
        
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" stroke-dasharray="251.2" stroke-dashoffset="125.6"/> 
        
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" stroke-dasharray="251.2" stroke-dashoffset="150.72"/> 
        
        <circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" stroke-dasharray="251.2" stroke-dashoffset="200.96"/> 
         
        <text x="40" y="50" fill="black" font-size="10">Text</text> 
    </svg>

Answer 3

Вот решение на d3, все что тут нужно сделать - менять внутренний и внешний радиус у arc-генератора:

.attr('d', d => {
    var ir = radius/3 + Math.random()*radius/5;
    var or = ir + Math.random()*radius/5;
    return arc.innerRadius(ir).outerRadius(or)(d)
  })

var data = [ Math.random(), Math.random(), Math.random(), Math.random()] 
var width = 260; 
var height = 260; 
var radius = Math.min(width, height) / 2; 
var color = d3.scaleOrdinal(d3.schemeCategory10); 
var svg = d3.select("body") 
  .append('svg') 
  .attr('viewBox', `${-width/2} ${-height/2} ${width} ${height}`) 
 
var arc = d3.arc(); 
 
var pie = d3.pie() 
  .value(d => d ) 
  .sort(null); 
 
var path = svg.selectAll('path') 
.data(pie(data)) 
.enter() 
.append("g") 
  .append('path') 
  .attr('d', d => { 
    var ir = radius/3 + Math.random()*radius/5; 
    var or = ir + Math.random()*radius/5; 
    return arc.innerRadius(ir).outerRadius(or)(d) 
  }) 
  .attr('fill', (d,i) => color(i))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

READ ALSO
Индекс в forEach()

Индекс в forEach()

когда индекс будет равен 6, нужно обнулить его до 1 и чтобы он продолжил увеличивать себя до 6 и снова уменьшил себя до 1

85
Как грамотно реализовать стейт в приложении React-Redux

Как грамотно реализовать стейт в приложении React-Redux

Всем доброго времени сутокДелаю простое приложение на React-Redux, опыта с React немного

124
JS: имя свойства объекта из переменной

JS: имя свойства объекта из переменной

Необходимо обратиться к вложенному свойству объекта js, имя которого задано переменнойОбщая картина такова:

205
Uncaught (in promise) DOMException

Uncaught (in promise) DOMException

Скрипт не воспроизводит аудиоПочему?

92