Круговая диаграмма с подписями

возможно ли сделать такую диаграмму посредством css или js. Через абсолют такое себе, более адаптивный вариант к реализации есть какой то?

введите сюда описание изображения


Ответы (1 шт):

Автор решения: ΝNL993

Для начала создадим круг с числами.

let circleDiv = document.querySelector('#circle')

circleDiv.style.position = 'relative'

let indexes = []

for (let i = 0; i < 7; i++) {
  indexes.push(i + 1)
}

let angle = 270
let angleIncrement = 360 / indexes.length
let radius = 100
let centerX = circleDiv.offsetWidth / 2
let centerY = circleDiv.offsetHeight / 2

for (let i = 0; i < indexes.length; i++) {
  let index = document.createElement('div')
  index.textContent = indexes[i]
  index.style.position = 'absolute'  
  
  let r = angle * Math.PI / 180
  
  index.style.left = centerX + radius * Math.cos(r) + 'px'
  index.style.top = centerY + radius * Math.sin(r) + 'px'

  angle += angleIncrement

  circleDiv.appendChild(index)
}
#circle {
  width: 250px;
  height: 250px;
}
<div id="circle"></div>

Объяснение

Сначала получим доступ к нашему элементу где будет храниться круг, далее зададим ему position: relative, чтобы все элементы, которые позиционированы абсолютно, позиционировались относительно нашего элемента. Далее создаём массив с 7'ю элементами (как у вас на картинке). Начальный угол 270, т.к. 1 должно находится в самом вверху. Далее задаём на сколько должен увеличиваться угол и сам радиус круга, дальше находим центр нашего элемента и записываем переменные как центра по X'у, так и по Y'у. Далее проходимся циклом по массиву indexes, создаём элемент с нашим индексом, задаём ему абсолютное позиционирование и задаём top и left, в них, прибавляем centerX (Или centerY в зависимости от пропорции) к радиусу который умножен на радиан нашего угла и это красота обёрнута в cos (Или sin), далее к нашему углу прибавляем angleIncrement и переносим наш созданный элемент в родительский элемент. Ничего сложного.

Зададим стилей

let circleDiv = document.querySelector('#circle')

circleDiv.style.position = 'relative'

let indexes = []

for (let i = 0; i < 7; i++) {
  indexes.push(i + 1)
}

let angle = 270
let angleIncrement = 360 / indexes.length
let radius = 100
let centerX = circleDiv.offsetWidth / 2
let centerY = circleDiv.offsetHeight / 2

for (let i = 0; i < indexes.length; i++) {
  let index = document.createElement('div')
  index.textContent = indexes[i]
  index.style.position = 'absolute'

  let r = angle * Math.PI / 180
  
  index.style.left = centerX + radius * Math.cos(r) + 'px'
  index.style.top = centerY + radius * Math.sin(r) + 'px'
  index.style.zIndex = '2'
  index.className = 'circle-index'

  angle += angleIncrement

  circleDiv.appendChild(index)
}

let backgroundCircle = document.createElement('div')
backgroundCircle.className = 'background-circle'
circleDiv.appendChild(backgroundCircle)
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: Arial, 'Segoe UI';
}

#circle {
  width: 250px;
  height: 250px;
}

.circle-index {
  background-color: rgb(51, 204, 153);
  padding: .125em;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  text-align: center;
  color: rgb(255, 255, 255);
  font-weight: bold;
}

.background-circle {
  width: 80%;
  height: 80%;
  border: 3px solid rgb(70, 45, 113);
  border-radius: 50%;
  position: absolute;
  z-index: 1;
  left: 40px;
  top: 40px;
}
<div id="circle"></div>

Тут надеюсь ничего объяснять не надо. Если всё-таки объяснение требуется, отпишитесь в комментариях.

Создадим текст рядом с числами

let circleDiv = document.querySelector('#circle')

circleDiv.style.position = 'relative'

let texts = {
  '1': {
    header: 'Подача заявки',
    desc: 'Вам достаточно предоставить нам инвойс с весом и объемом продукции, сообщим о необходимом дне загрузки',
  },
  '2': {
    header: 'Просчёт кп по индивидуальным условиям',
    desc: 'В полном соответствии Вашим пожеланиям',
  },
  '3': {
    header: 'Заключение договора или контракта на перевозку',
    desc: '',
  },
  '4': {
    header: 'Загрузка товаров у поставщика и логистика',
    desc: '',
  },
  '5': {
    header: 'Растаможивание и прохождение фитосанитарного контроля в РФ',
    desc: '',
  },
  '6': {
    header: 'Выгрузка товаров у нас на складах ( с возможностью хранения) или доставка до необходимого Вам места или региона.',
    desc: '',
  },
  '7': {
    header: 'Подача отчетности поквартально',
    desc: '',
  },
}

let indexes = []

for (let i = 0; i < 7; i++) {
  indexes.push(i + 1)
}

let angle = 270
let angleIncrement = 360 / indexes.length
let radius = 100
let centerX = circleDiv.offsetWidth / 2
let centerY = circleDiv.offsetHeight / 2

for (let i = 0; i < indexes.length; i++) {
  let index = document.createElement('div')
  let j = indexes[i]
  index.textContent = j
  index.style.position = 'absolute'

  let r = angle * Math.PI / 180
  let left = centerX + radius * Math.cos(r)
  let top = centerY + radius * Math.sin(r)

  index.style.left = left + 'px'
  index.style.top = top + 'px'
  index.style.zIndex = '2'
  index.className = 'circle-index'

  let text = document.createElement('div')
  let currentText = texts[j]
  text.innerHTML = `<div class="circle-header">${currentText.header}</div><div class="circle-desc">${currentText.desc}</div>`

  j < 8 ? circleDiv.appendChild(text) : void 0

  let header = text.querySelector('.circle-header')
  let desc = text.querySelector('.circle-desc')

  text.style.position = 'absolute'
  text.id = 'text-' + j

  angle += angleIncrement
  circleDiv.appendChild(index)
}

let backgroundCircle = document.createElement('div')
backgroundCircle.className = 'background-circle'
circleDiv.appendChild(backgroundCircle)
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: Arial, 'Segoe UI';
}

#circle {
  width: 250px;
  height: 250px;
  margin: 250px auto;
}

.circle-index {
  background-color: rgb(51, 204, 153);
  padding: .125em;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  text-align: center;
  color: rgb(255, 255, 255);
  font-weight: bold;
}

.background-circle {
  width: 80%;
  height: 80%;
  border: 3px solid rgb(70, 45, 113);
  border-radius: 50%;
  position: absolute;
  z-index: 1;
  left: 40px;
  top: 40px;
}

.circle-header {
  color: rgb(70, 45, 113);
  font-weight: bold;
}

.circle-desc {
  color: rgb(0, 0, 0);
}

#text-1 {
  top: -120px;
  left: 65px;
}

#text-2 {
  left: 250px;
  top: -5px;
}

#text-3 {
  top: 140px;
  left: 255px;
}

#text-4 {
  top: 250px;
  left: 200px;
}

#text-5 {
  top: 250px;
  left: -100px;
}

#text-6 {
  top: 120px;
  left: -150px;
  width: 187px;
}

#text-7 {
  left: -200px;
  top: 45px;
}
<div id="circle"></div>

Весь текст я расставлял в ручную т.к. уже не смог придумать способа расставлять его автоматически (сдулся), вот так вот, все пропорции в CSS.

Надеюсь мой ответ хоть чем-то вам поможет.

→ Ссылка