Я пытаюсь построить очень простую кольцевую диаграмму.
Вот рабочий код:
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/.
Я могу понять проблему, но не знаю, как добавить немного поля между штрихами, чтобы избежать уродливого наложения.
Я ценю любое предложение.
Одним из решений было бы добавление {'percent': 0,color: 'red'} в конец массива countries. Хотя результат может быть якобы более эстетичным, я бы этого делать не стал. Для диаграмм я бы оставил stroke-linecap = "butt" Диаграммы — это визуальные инструменты, и использование stroke-linecap = "round" может изменить восприятие данных.
@Shidersz, это не сработает, когда процент ниже 2,5.
И что должно произойти, если одна или несколько сумм меньше радиуса округления. Что вы хотите, чтобы произошло?
@PaulLeBeau, наверное, это вопрос, ха-ха.
Если бы вы сделали это с путями, а не с кругом + штрих-тире, вы могли бы сделать конец маркера, у которого не было бы этой проблемы.
@MichaelMullany, не могли бы вы показать мне пример, пожалуйста?
Добавлен пример/ответ для вас



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это то, что вы хотели?
Просто вычтите радиус круглых заглушек (по одному на каждый конец) из длины тире.
Если радиус окружности не слишком мал, круглые колпачки должны аккуратно касаться друг друга.
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, все идет не так.
Вы так и не ответили на вопрос о том, как должны работать очень маленькие проценты. Одним из решений было бы просто не делать круглые заглавные буквы для небольших значений. Любое решение, которое добавляет заглавные буквы в конце тире, изменит эффективную длину тире и исказит относительные проценты.
Вот как вы можете сделать это с путями и маркерами. Хитрость заключается в использовании комбинации начала маркера и конца маркера. Кажущееся перекрытие предыдущей строки на самом деле накладывается на текущую строку в качестве начала маркера.
<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>
Я не совсем уверен, что вы ищете это, но, может быть, вы можете попробовать вычесть небольшой процент для каждого штриха (на
dashArray): jsfiddle.net/3L728bmq