Я пытаюсь построить очень простую диаграмму пончиков.
Вот рабочий код:
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/.
Я могу понять проблему, но не знаю, как добавить немного поля между штрихами, чтобы избежать уродливой укладки.
Я ценю любое предложение.
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>
`;
}, '')
Вот как вы можете сделать это с путями и маркерами. Хитрость заключается в использовании комбинированного маркера начала / конца маркера. Кажущееся перекрытие предыдущей строки фактически привязано к текущей строке как начало маркера.
<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>
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript / JS) и его различных диалектах / реализациях (кроме ActionScript). Включите все соответствующие теги в свой вопрос; например, [node.js], [jquery], [json] и т. д.