Как сверстать круговую диаграмму с фоновым изображением?

91
28 мая 2021, 04:30

Внимание! Это дубль вопроса с тостера! Автор не я, просто вопрос показался интересным:

Добрый день. Возникла необходимость сверстать круговую диаграмму с фоновым изображением, что бы можно было редактировать процент заполнения. Пытался сделать с помощью SVG, но скудные знания в этой области не позволили это реализовать. Причем нужно решение без использования jQuery библиотек, можно на ванильном JS, либо с использованием VUE.

UPD: Полупрозрачная подложка под диаграммой просто отдельное изображение, которого потенциально может и не быть. Интересует только создание диаграммы.

UPD 2: Я в курсе что нарушил Правила сообщества, не предоставив хоть попыток решения, но я считаю, здесь вопрос не кода, а подхода к решению данного вопроса.

Answer 1

На картинку наложена маска из серого круга и белого сектора.

Для того чтобы нарисовать сектор нужно посчитать вторую точку дуги по формуле.

addEventListener('mousemove', e => { 
 
  // процент заполнения 
  let percent = Math.min(99.99, Math.max(0, (e.y-20)/(innerHeight-40)*100)); 
   
  // радиус сектора 
  let r = 120; 
   
  // угол второй точки сектора 
  let angle = percent/50*Math.PI - Math.PI/2; 
   
  // признак большой дуги 
  let largeArc = percent > 50 ? 1 : 0; 
   
  // аргументы команды ARC  
  let arc = [r, r, 0, largeArc, 1, Math.cos(angle)*r, Math.sin(angle)*r]; 
 
  // устанавливаем сектору 
  path.setAttribute('d', `M0,${-r}A${arc}L0,0z`); 
   
  text.innerHTML = percent.toFixed() + "%"; 
   
});
<body style="margin:0;overflow:hidden"> 
<svg viewbox="-150 -150 300 300" style="height:100vh" id=svg> 
<defs> 
  <mask id=mask> 
    <circle r=100 fill=gray></circle> 
    <path id=path fill=white></path> 
  </mask> 
</defs> 
<text id=text text-anchor=middle font-size=28px font-family=arial y=-122></text> 
<image mask="url(#mask)" width=300 height=300 x=-150 y=-150  
       xlink:href="https://picsum.photos/id/63/300/300"></image> 
</svg> 
</body>

Answer 2

По просьбам трудящихся добавляю вариант с канвой, тут уже почти ничего считать не надо, т.к. на входе у команды рисующей дугу уже углы.

let ctx = canvas.getContext('2d'); 
let image = new Image(); 
image.src = "https://picsum.photos/id/63/300/300"; 
image.onload = e => draw(ctx.fillStyle = ctx.createPattern(image, 'repeat')); 
addEventListener('mousemove', draw); 
 
function draw(e){ 
  let percent = Math.min(99.99, Math.max(0, (e.y||0-20)/(innerHeight-40)*100)); 
  let angle = percent/50*Math.PI - Math.PI/2; 
  ctx.clearRect(0, 0, canvas.width, canvas.height); 
  arc(0.5, 100, 0, Math.PI*2); 
  arc(1.0, 120, -Math.PI/2, angle); 
} 
 
function arc(alpha, radius, startAngle, endAngle){ 
  ctx.globalAlpha = alpha 
  ctx.beginPath(); 
  ctx.arc(canvas.width/2,canvas.height/2,radius,startAngle,endAngle); 
  ctx.lineTo(canvas.width/2,canvas.height/2); 
  ctx.fill(); 
}
<canvas id=canvas width=300 height=300/>

READ ALSO
Вставка даты по умолчанию на HTML странице

Вставка даты по умолчанию на HTML странице

Для выгрузки операций из БД на html-странице есть 2 окна для ввода периода времени "с" и "по"Если написать в коде страницы: body onload = "ShowMonthDate();", то при...

145
Сетка товаров на Grid

Сетка товаров на Grid

У меня есть сетка товаров сделанная на гридахКоличество товаров в ряду - 4, рядов может неопределенное количество

106
Программно вставить символ в PasswordBox в позицию каретки

Программно вставить символ в PasswordBox в позицию каретки

Дорого времени суток! Я пишу WPF контрол экранной клавиатурыУ нее должен быть режим пароля

104
Проблема с Bitmap Palette 8bpp indexed (Window xp)

Проблема с Bitmap Palette 8bpp indexed (Window xp)

Всем доброго времени сутокРаботаю с 8-битными индексированными изображениями в формате png

104