Как в svg circle сделать нулевую заполненность круга
У меня есть вот такая вёрстка svg круга
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
}
.progressbar {
max-width: 150px;
font-size: 10px;
--color: rgb(0, 186, 16);
--percent: 0;
/* процент, насколько заполнен круг */
--PI: 3.141592;
--r: 30;
--strokeWidth: 2;
--lengthCircle: calc( 2 * var(--PI) * var(--r));
}
.progressbar circle {
r: var(--r);
}
.progressbar text {
fill: var(--color);
}
.progressbar__track {
fill: transparent;
stroke: #ededed;
stroke-width: var(--strokeWidth);
}
.progressbar__thumb {
fill: transparent;
stroke-dasharray: calc( var(--lengthCircle) * var(--percent) / 100) var(--lengthCircle);
stroke: var(--color);
stroke-width: var(--strokeWidth);
stroke-linecap: round;
transform-origin: center;
transform-box: fill-box;
transform: rotate(-90deg);
}
.progressbar__percent {
font-size: 16px;
}
<svg class="progressbar" viewBox="0 0 62 80">
<circle class="progressbar__track" cx="31" cy="31"></circle>
<circle class="progressbar__thumb" cx="31" cy="31"></circle>
<text x="32" y="33" class="progressbar__percent" text-anchor="middle" dominant-baseline="middle">
<tspan>0</tspan>
%
</text>
<text x="32" y="73" class="progressbar__info" text-anchor="middle" dominant-baseline="middle">
<tspan>Загрузочка ...</tspan>
</text>
</svg>
Я бы хотел придумать, как можно сделать так, когда CSS переменная --percent для .progressbar равняется 0, не было видной зелёной точке на старте, сверху круга.
Я приложу свой вариант в ответах, но может кто-то предложит что-то получше.
UPD: я приложил свой вариант, но хотелось бы, чтобы кто-то додумался, как можно было бы это правило описать в CSS.
Вот это правило:
opacity = 0, если
--percent=== 0
opacity = 1, если--percent!== 1
Ответы (1 шт):
В общем я всё равно управляю изменение CSS переменной --percent из JS, поэтому вот такое я придумал, просто по умолчанию в CSS opacity: 0 для .progressbar__thumb, а при анимации.
.to(progressbarThumb, {
opacity: 1,
duration: 0.1
})
const progressbarThumb = document.querySelector('.progressbar__thumb');
const progressbarPercent = document.querySelector('.progressbar__percent > tspan');
const progressbarText = document.querySelector('.progressbar__info > tspan');
const btn = document.querySelector('.btn');
function onUpdateGsap() {
const percent = gsap.getProperty(progressbarThumb, '--percent');
if (percent > 99) {
progressbarText.textContent = 'Закончили?';
} else if (percent > 60 && percent < 99) {
progressbarText.textContent = 'Разгоняемся!';
} else if (percent > 40 && percent < 60) {
progressbarText.textContent = 'Погнали!';
} else if (percent > 0 && percent < 40) {
progressbarText.textContent = 'Загрузочка ...'
}
progressbarPercent.textContent = Math.round(percent);
}
const tl = gsap.timeline({
defaults: {
duration: 5,
ease: 'linear'
}
})
.to(progressbarThumb, {
opacity: 1,
duration: 0.1
})
.to(progressbarThumb, {
'--percent': 100,
onUpdate: onUpdateGsap
});
tl.paused(true);
btn.addEventListener('click', (e) => {
if (btn.classList.contains('active')) {
btn.classList.remove('active');
tl.reverse();
} else {
btn.classList.add('active');
tl.play();
}
});
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: sans-serif;
}
.progressbar {
max-width: 100px;
font-size: 10px;
display: block;
--color: rgb(0, 186, 16);
--percent: 0;
/* процент, насколько заполнен круг */
--PI: 3.141592;
--r: 30;
--strokeWidth: 2;
--total: calc( var(--PI) * var(--r));
}
.progressbar circle {
r: var(--r);
}
.progressbar text {
fill: var(--color);
}
.progressbar__percent {
font-size: 16px;
}
.progressbar__track {
fill: transparent;
stroke: #ededed;
stroke-width: var(--strokeWidth);
}
.progressbar__thumb {
fill: transparent;
--strokeDasharray: calc(2 * var(--total) * var(--percent) / 100) calc(2 * var(--total));
stroke-linecap: round;
stroke-dasharray: var(--strokeDasharray);
stroke: var(--color);
stroke-width: var(--strokeWidth);
transform-origin: center;
transform-box: fill-box;
transform: rotate(-90deg);
opacity: 0;
}
.btn {
--color1: black;
--color2: white;
display: inline-block;
background-color: var(--color2);
color: var(--color1);
padding: 5px 8px;
margin: 20px 0 0 20px;
font-size: 18px;
user-select: none;
cursor: pointer;
border: 2px solid var(--color1);
transition-duration: 0.2s;
transition-timing-function: ease;
transition-property: border-color, background-color, color;
}
.btn.active {
--color1: white;
--color2: black;
border-color: var(--color2);
}
<svg class="progressbar" viewBox="0 0 62 80">
<circle class="progressbar__track" cx="31" cy="31"></circle>
<circle class="progressbar__thumb" cx="31" cy="31"></circle>
<text x="32" y="33" class="progressbar__percent" text-anchor="middle" dominant-baseline="middle"><tspan>0</tspan>%</text>
<text x="32" y="73" class="progressbar__info" text-anchor="middle" dominant-baseline="middle"><tspan>Загрузочка ...</tspan></text>
</svg>
<div class="btn">Туда-сюда</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/gsap.min.js"></script>
UPD: Получилось то, что я хотел изначально, вариант с установкой прозрачности чисто в CSS:
const progressbarThumb = document.querySelector('.progressbar__thumb');
const progressbarPercent = document.querySelector('.progressbar__percent > tspan');
const progressbarText = document.querySelector('.progressbar__info > tspan');
const btn = document.querySelector('.btn');
function onUpdateGsap() {
const percent = gsap.getProperty(progressbarThumb, '--percent');
if (percent > 99) {
progressbarText.textContent = 'Закончили?';
} else if (percent > 60 && percent < 99) {
progressbarText.textContent = 'Разгоняемся!';
} else if (percent > 40 && percent < 60) {
progressbarText.textContent = 'Погнали!';
} else if (percent > 0 && percent < 40) {
progressbarText.textContent = 'Загрузочка ...'
}
progressbarPercent.textContent = Math.round(percent);
}
const tl = gsap.timeline({
defaults: {
duration: 5,
ease: 'linear'
}
})
.to(progressbarThumb, {
'--percent': 100,
onUpdate: onUpdateGsap
});
tl.paused(true);
btn.addEventListener('click', (e) => {
if (btn.classList.contains('active')) {
btn.classList.remove('active');
tl.reverse();
} else {
btn.classList.add('active');
tl.play();
}
});
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0;
font-family: sans-serif;
}
.progressbar {
max-width: 100px;
font-size: 10px;
display: block;
--color: rgb(0, 186, 16);
--percent: 0;
/* процент, насколько заполнен круг */
--PI: 3.141592;
--r: 30;
--strokeWidth: 2;
--total: calc( var(--PI) * var(--r));
}
.progressbar circle {
r: var(--r);
}
.progressbar text {
fill: var(--color);
}
.progressbar__percent {
font-size: 16px;
}
.progressbar__track {
fill: transparent;
stroke: #ededed;
stroke-width: var(--strokeWidth);
}
@property --ceil {
syntax: '<integer>';
initial-value: 0;
inherits: false;
}
.progressbar__thumb {
fill: transparent;
--strokeDasharray: calc(2 * var(--total) * var(--percent) / 100) calc(2 * var(--total));
stroke-linecap: round;
stroke-dasharray: var(--strokeDasharray);
stroke: var(--color);
stroke-width: var(--strokeWidth);
transform-origin: center;
transform-box: fill-box;
transform: rotate(-90deg);
--percent01: calc(var(--percent) / 100);
--ceil: calc(var(--percent01) + 0.499);
--opacity: var(--ceil);
opacity: var(--opacity);
}
.btn {
--color1: black;
--color2: white;
display: inline-block;
background-color: var(--color2);
color: var(--color1);
padding: 5px 8px;
margin: 20px 0 0 20px;
font-size: 18px;
user-select: none;
cursor: pointer;
border: 2px solid var(--color1);
transition-duration: 0.2s;
transition-timing-function: ease;
transition-property: border-color, background-color, color;
}
.btn.active {
--color1: white;
--color2: black;
border-color: var(--color2);
}
<svg class="progressbar" viewBox="0 0 62 80">
<circle class="progressbar__track" cx="31" cy="31"></circle>
<circle class="progressbar__thumb" cx="31" cy="31"></circle>
<text x="32" y="33" class="progressbar__percent" text-anchor="middle" dominant-baseline="middle"><tspan>0</tspan>%</text>
<text x="32" y="73" class="progressbar__info" text-anchor="middle" dominant-baseline="middle"><tspan>Загрузочка ...</tspan></text>
</svg>
<div class="btn">Туда-сюда</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/gsap.min.js"></script>