Как добавить отступ к обводке круга SVG для простого пончика

Я пытаюсь построить очень простую кольцевую диаграмму.

Вот рабочий код:

const countries = [
{'percent': 2,colour: 'red'},
{'percent': 28,colour: 'blue'},
{'percent': 36,colour: 'yellow'},
{'percent': 34,colour: 'orange'}
];


const donutData = countries.map((country, index) => {
  return {
    stroke: country.colour,
    dashoffset: 25 - countries.slice(0, index).reduce((a, b) => a + b.percent, 0),
    dashArray: [country.percent, 100 - country.percent]
  }
});
const div = document.createElement('div');
div.innerHTML = '<svg id = "donut" width = "100%" height = "100%" viewBox = "3 3 36 36"></svg>';
document.body.appendChild(div);
document.querySelector('#donut').innerHTML= donutData.reduce((a, item) => {
  return a +
    `<circle 
  	cx = "21"
    cy = "21"
    fill = "transparent"
    r = "15.91549430918954"
    stroke-width = "2.3"
    stroke = "${item.stroke}"
    stroke-dasharray = "${item.dashArray[0]} ${item.dashArray[1]}"
    stroke-dashoffset = "${item.dashoffset}"></circle>
`;
}, '')

https://jsfiddle.net/miladhi/1dxnkjht/1/

Выше работает нормально, но попробуйте добавить stroke-linecap = "round" к <circle>, и он станет равномерным, штрихи будут друг над другом.

Как вы можете видеть здесь https://jsfiddle.net/miladhi/x8w4kgdv/.

Я могу понять проблему, но не знаю, как добавить немного поля между штрихами, чтобы избежать уродливого наложения.

Я ценю любое предложение.

Я не совсем уверен, что вы ищете это, но, может быть, вы можете попробовать вычесть небольшой процент для каждого штриха (на dashArray): jsfiddle.net/3L728bmq

Shidersz 28.05.2019 07:59

Одним из решений было бы добавление {'percent': 0,color: 'red'} в конец массива countries. Хотя результат может быть якобы более эстетичным, я бы этого делать не стал. Для диаграмм я бы оставил stroke-linecap = "butt" Диаграммы — это визуальные инструменты, и использование stroke-linecap = "round" может изменить восприятие данных.

enxaneta 28.05.2019 08:29

@Shidersz, это не сработает, когда процент ниже 2,5.

Milad 28.05.2019 09:00

И что должно произойти, если одна или несколько сумм меньше радиуса округления. Что вы хотите, чтобы произошло?

Paul LeBeau 28.05.2019 09:51

@PaulLeBeau, наверное, это вопрос, ха-ха.

Milad 29.05.2019 01:23

Если бы вы сделали это с путями, а не с кругом + штрих-тире, вы могли бы сделать конец маркера, у которого не было бы этой проблемы.

Michael Mullany 30.05.2019 05:22

@MichaelMullany, не могли бы вы показать мне пример, пожалуйста?

Milad 30.05.2019 05:50

Добавлен пример/ответ для вас

Michael Mullany 06.06.2019 18:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
8
689
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это то, что вы хотели?

Просто вычтите радиус круглых заглушек (по одному на каждый конец) из длины тире.

Если радиус окружности не слишком мал, круглые колпачки должны аккуратно касаться друг друга.

const countries = [
{'percent': 10,colour: 'red'},
{'percent': 20,colour: 'blue'},
{'percent': 36,colour: 'yellow'},
{'percent': 34,colour: 'orange'}
];

const STROKE_WIDTH = 2.3;

const donutData = countries.map((country, index) => {
  // Subtract the radius of the round cap, twice.
  const dashLength = country.percent - STROKE_WIDTH;
  return {
    stroke: country.colour,
    dashoffset: 25 - countries.slice(0, index).reduce((a, b) => a + b.percent, 0),
    dashArray: [dashLength, 100 - dashLength]
  }
});
const div = document.createElement('div');
div.innerHTML = '<svg id = "donut" width = "100%" height = "100%" viewBox = "3 3 36 36"></svg>';
document.body.appendChild(div);
document.querySelector('#donut').innerHTML= donutData.reduce((a, item) => {
  return a +
    `<circle 
  	cx = "21"
    cy = "21"
    fill = "transparent"
    r = "15.91549430918954"
    stroke-width = "${STROKE_WIDTH}"
    stroke-linecap = "round"
    stroke = "${item.stroke}"
    stroke-dasharray = "${item.dashArray[0]} ${item.dashArray[1]}"
    stroke-dashoffset = "${item.dashoffset}"></circle>
`;
}, '')

Обновлять

Версия, которая изящно обрабатывает короткие строки.

const countries = [
{'percent': 10, colour: 'red'},
{'percent': 20, colour: 'blue'},
{'percent': 36, colour: 'yellow'},
{'percent': 33, colour: 'orange'},
{'percent': 1,  colour: 'green'},
];

const STROKE_WIDTH = 2.3;

const donutData = countries.map((country, index) => {
  let dashLength, offsetAdjust, caps;
  if (country.percent >= STROKE_WIDTH) {
    // Subtract the radius of the round cap, twice.
    dashLength = country.percent - STROKE_WIDTH;
    offsetAdjust = STROKE_WIDTH / 2;
    caps = "round";
  } else {
    dashLength = country.percent;
    offsetAdjust = 0;
    caps = "butt";
  }
  return {
    stroke: country.colour,
    dashoffset: 25 - countries.slice(0, index).reduce((a, b) => a + b.percent, 0) - offsetAdjust,
    dashArray: [dashLength, 100 - dashLength],
    caps: caps
  }
});
const div = document.createElement('div');
div.innerHTML = '<svg id = "donut" width = "100%" height = "100%" viewBox = "3 3 36 36"></svg>';
document.body.appendChild(div);
document.querySelector('#donut').innerHTML= donutData.reduce((a, item) => {
  return a +
    `<circle 
  	cx = "21"
    cy = "21"
    fill = "transparent"
    r = "15.91549430918954"
    stroke-width = "${STROKE_WIDTH}"
    stroke-linecap = "${item.caps}"
    stroke = "${item.stroke}"
    stroke-dasharray = "${item.dashArray[0]} ${item.dashArray[1]}"
    stroke-dashoffset = "${item.dashoffset}"></circle>
`;
}, '')

LeBaue, спасибо, но нет. Если вы читаете комментарии к моему вопросу, этот ответ очень ограничен, как только я меняю проценты, для любого процента, который меньше 2,3, все идет не так.

Milad 30.05.2019 01:34

Вы так и не ответили на вопрос о том, как должны работать очень маленькие проценты. Одним из решений было бы просто не делать круглые заглавные буквы для небольших значений. Любое решение, которое добавляет заглавные буквы в конце тире, изменит эффективную длину тире и исказит относительные проценты.

Paul LeBeau 30.05.2019 11:40

Вот как вы можете сделать это с путями и маркерами. Хитрость заключается в использовании комбинации начала маркера и конца маркера. Кажущееся перекрытие предыдущей строки на самом деле накладывается на текущую строку в качестве начала маркера.

<svg width = "600px" height = "400px">
  <defs>
    <marker id = "round-cap-blue" viewBox = "0 0 1 1" 
        markerWidth = "1" markerHeight = "1"
        orient = "auto" refX = "0.5" refY = "0.5">
      <circle cx = "0.5" cy = "0.5" r = "0.5" fill = "blue"/>
    </marker>
    
        <marker id = "round-cap-red" viewBox = "0 0 1 1" 
        markerWidth = "1" markerHeight = "1"
        orient = "auto" refX = "0.5" refY = "0.5">
      <circle cx = "0.5" cy = "0.5" r = "0.5" fill = "red"/>
    </marker>
    
            <marker id = "round-cap-green" viewBox = "0 0 1 1" 
        markerWidth = "1" markerHeight = "1"
        orient = "auto" refX = "0.5" refY = "0.5">
      <circle cx = "0.5" cy = "0.5" r = "0.5" fill = "green"/>
    </marker>
    
    
    </defs>
  
  <g transform = "translate(100,0)">
    
  <path fill = "none" stroke = "blue" stroke-width = "30" d = "M 150 150
           A 100 100 0 0 0 50 50" marker-end = "url(#round-cap-blue)"/>
  
   <path fill = "none" stroke = "red" stroke-width = "30" d = "M 50 250
           A 100 100 0 0 0 150 150" marker-end = "url(#round-cap-red)"/>
    
   <path fill = "none" stroke = "green" stroke-width = "30" d = "M 50 50
           A 100 100 0 0 0 50 250" marker-start = "url(#round-cap-blue)" marker-end = "url(#round-cap-green)"/>
    
    
  </g>
  
</svg>

Другие вопросы по теме

Как я могу сделать так, чтобы последовательные промежутки nowrap были обернуты как отдельные элементы?
Меню навигации не открывается под заголовком для средних экранов с использованием начальной загрузки 4
Почему `<input type='date' />` и `<input type='time' />` имеют проблемы с изменением в Firefox? Или я что-то упускаю?
Как я могу получить доступ к публичной переменной в laravel
Как активировать кнопку только тогда, когда файл загружен и проверены условия?
Как установить цвет фона контейнера поиска, помещенного в синюю верхнюю панель?
Bootstrap input-group-prepend / регулировка ширины надстройки
Используйте изображение по умолчанию для 404 при использовании синхронного загрузчика изображений javascript для холста html5
Как я могу добавить пробел между этими логотипами в списке
Как создать функцию javascript, которая объединяет входные значения из пользовательского ввода и выводит их во фразу?