修复 SVG 圆的线性渐变
Fix linear gradient of SVG circle
我有如下圆形进度条。除了渐变,一切都很好。圆实际上是2个弧。当脚本绘制第一条弧时,渐变为红色->蓝色。所以圆圈的起点是红色的。尾巴是蓝色的。但是当绘制第二个弧时,渐变的开始切换为蓝色,我不知道如何修复它。我不希望它改变颜色。我希望渐变始终相同
function update(percentage) {
var width = 160,
height = 160,
cx = width / 2,
cy = height / 2,
start_angle = 0,
barsize = 10;
var r = Math.min(cx, cy) - barsize / 2;
if (percentage === 100) {
percentage -= 0.0001;
}
var end_angle = start_angle + percentage * Math.PI * 2 / 100;
var x1 = cx + r * Math.sin(start_angle),
y1 = cy - r * Math.cos(start_angle),
x2 = cx + r * Math.sin(end_angle),
y2 = cy - r * Math.cos(end_angle);
// This is a flag for angles larger than than a half circle
// It is required by the SVG arc drawing component
var big = 0;
if (end_angle - start_angle > Math.PI) big = 1;
// This string holds the path details
var d = "M" + x1 + "," + y1 + // Start at (x1,y1)
" A" + r + "," + r + // Draw an arc of radius r
" 0 " + big + " 1 " + // Arc details...
x2 + "," + y2;
document.getElementById('path').setAttribute('d', d);
}
function animate(start, finish) {
setTimeout(function() {
update(start);
console.log(document.getElementsByClassName('progress__content'))
let element = document.getElementsByClassName('progress__content')[0];
element.textContent = start + '%';
start += 1;
if (start <= finish) {
animate(start, finish);
} else {
return;
}
}, 10);
}
function go() {
animate(0, 100);
}
.progress {
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: 100px;
width: 200px;
height: 200px;
}
.progress__content {
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px;
margin-top: -23px;
font-family: Helvetica;
font-size: 40px;
width: 103px;
height: 47px;
text-align: center;
}
body {
background: #f1f1f1;
}
<button onclick="go()">Click me</button>
<div class="progress clip-svg">
<div class="progress__content">0%</div>
<svg width="160" height="160">
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop stop-color="#EE3028" offset="0" />
<stop stop-color="#067BC2" offset="1" />
</linearGradient>
</defs>
<ellipse rx="75" ry="75" cx="80" cy="80" stroke="#f2f2f2" fill="none" stroke-width="10"></ellipse>
<g>
<path id="path" stroke-width="10" stroke="url(#gradient)" fill="none" d="">
</path>
</g>
</svg>
</div>
渐变的变化是因为你在整个路径上定义了渐变,随着路径对象的向下和向左生长,渐变的停止位置也不断被重新定义。解决方案是将 gradientUnits 更改为 userSpaceOnUse - 因此渐变是相对于绘图 surface/viewBox 相对于对象定义的。下面可能的实现(我不完全确定你的目标是什么配色方案 - 但调整停止位置和颜色直到你得到你想要的)。
function update(percentage) {
var width = 160,
height = 160,
cx = width / 2,
cy = height / 2,
start_angle = 0,
barsize = 10;
var r = Math.min(cx, cy) - barsize / 2;
if (percentage === 100) {
percentage -= 0.0001;
}
var end_angle = start_angle + percentage * Math.PI * 2 / 100;
var x1 = cx + r * Math.sin(start_angle),
y1 = cy - r * Math.cos(start_angle),
x2 = cx + r * Math.sin(end_angle),
y2 = cy - r * Math.cos(end_angle);
// This is a flag for angles larger than than a half circle
// It is required by the SVG arc drawing component
var big = 0;
if (end_angle - start_angle > Math.PI) big = 1;
// This string holds the path details
var d = "M" + x1 + "," + y1 + // Start at (x1,y1)
" A" + r + "," + r + // Draw an arc of radius r
" 0 " + big + " 1 " + // Arc details...
x2 + "," + y2;
document.getElementById('path').setAttribute('d', d);
}
function animate(start, finish) {
setTimeout(function() {
update(start);
console.log(document.getElementsByClassName('progress__content'))
let element = document.getElementsByClassName('progress__content')[0];
element.textContent = start + '%';
start += 1;
if (start <= finish) {
animate(start, finish);
} else {
return;
}
}, 10);
}
function go() {
animate(0, 100);
}
.progress {
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: 100px;
width: 200px;
height: 200px;
}
.progress__content {
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px;
margin-top: -23px;
font-family: Helvetica;
font-size: 40px;
width: 103px;
height: 47px;
text-align: center;
}
body {
background: #f1f1f1;
}
<button onclick="go()">Click me</button>
<div class="progress clip-svg">
<div class="progress__content">0%</div>
<svg width="160" height="160">
<defs>
<linearGradient id="gradient" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="160" y2="0">
<stop stop-color="#EE3028" offset="0" />
<stop stop-color="#067BC2" offset="160" />
</linearGradient>
</defs>
<ellipse rx="75" ry="75" cx="80" cy="80" stroke="#f2f2f2" fill="none" stroke-width="10"></ellipse>
<g>
<path id="path" stroke-width="10" stroke="url(#gradient)" fill="none" d="">
</path>
</g>
</svg>
</div>
我有如下圆形进度条。除了渐变,一切都很好。圆实际上是2个弧。当脚本绘制第一条弧时,渐变为红色->蓝色。所以圆圈的起点是红色的。尾巴是蓝色的。但是当绘制第二个弧时,渐变的开始切换为蓝色,我不知道如何修复它。我不希望它改变颜色。我希望渐变始终相同
function update(percentage) {
var width = 160,
height = 160,
cx = width / 2,
cy = height / 2,
start_angle = 0,
barsize = 10;
var r = Math.min(cx, cy) - barsize / 2;
if (percentage === 100) {
percentage -= 0.0001;
}
var end_angle = start_angle + percentage * Math.PI * 2 / 100;
var x1 = cx + r * Math.sin(start_angle),
y1 = cy - r * Math.cos(start_angle),
x2 = cx + r * Math.sin(end_angle),
y2 = cy - r * Math.cos(end_angle);
// This is a flag for angles larger than than a half circle
// It is required by the SVG arc drawing component
var big = 0;
if (end_angle - start_angle > Math.PI) big = 1;
// This string holds the path details
var d = "M" + x1 + "," + y1 + // Start at (x1,y1)
" A" + r + "," + r + // Draw an arc of radius r
" 0 " + big + " 1 " + // Arc details...
x2 + "," + y2;
document.getElementById('path').setAttribute('d', d);
}
function animate(start, finish) {
setTimeout(function() {
update(start);
console.log(document.getElementsByClassName('progress__content'))
let element = document.getElementsByClassName('progress__content')[0];
element.textContent = start + '%';
start += 1;
if (start <= finish) {
animate(start, finish);
} else {
return;
}
}, 10);
}
function go() {
animate(0, 100);
}
.progress {
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: 100px;
width: 200px;
height: 200px;
}
.progress__content {
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px;
margin-top: -23px;
font-family: Helvetica;
font-size: 40px;
width: 103px;
height: 47px;
text-align: center;
}
body {
background: #f1f1f1;
}
<button onclick="go()">Click me</button>
<div class="progress clip-svg">
<div class="progress__content">0%</div>
<svg width="160" height="160">
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop stop-color="#EE3028" offset="0" />
<stop stop-color="#067BC2" offset="1" />
</linearGradient>
</defs>
<ellipse rx="75" ry="75" cx="80" cy="80" stroke="#f2f2f2" fill="none" stroke-width="10"></ellipse>
<g>
<path id="path" stroke-width="10" stroke="url(#gradient)" fill="none" d="">
</path>
</g>
</svg>
</div>
渐变的变化是因为你在整个路径上定义了渐变,随着路径对象的向下和向左生长,渐变的停止位置也不断被重新定义。解决方案是将 gradientUnits 更改为 userSpaceOnUse - 因此渐变是相对于绘图 surface/viewBox 相对于对象定义的。下面可能的实现(我不完全确定你的目标是什么配色方案 - 但调整停止位置和颜色直到你得到你想要的)。
function update(percentage) {
var width = 160,
height = 160,
cx = width / 2,
cy = height / 2,
start_angle = 0,
barsize = 10;
var r = Math.min(cx, cy) - barsize / 2;
if (percentage === 100) {
percentage -= 0.0001;
}
var end_angle = start_angle + percentage * Math.PI * 2 / 100;
var x1 = cx + r * Math.sin(start_angle),
y1 = cy - r * Math.cos(start_angle),
x2 = cx + r * Math.sin(end_angle),
y2 = cy - r * Math.cos(end_angle);
// This is a flag for angles larger than than a half circle
// It is required by the SVG arc drawing component
var big = 0;
if (end_angle - start_angle > Math.PI) big = 1;
// This string holds the path details
var d = "M" + x1 + "," + y1 + // Start at (x1,y1)
" A" + r + "," + r + // Draw an arc of radius r
" 0 " + big + " 1 " + // Arc details...
x2 + "," + y2;
document.getElementById('path').setAttribute('d', d);
}
function animate(start, finish) {
setTimeout(function() {
update(start);
console.log(document.getElementsByClassName('progress__content'))
let element = document.getElementsByClassName('progress__content')[0];
element.textContent = start + '%';
start += 1;
if (start <= finish) {
animate(start, finish);
} else {
return;
}
}, 10);
}
function go() {
animate(0, 100);
}
.progress {
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: 100px;
width: 200px;
height: 200px;
}
.progress__content {
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px;
margin-top: -23px;
font-family: Helvetica;
font-size: 40px;
width: 103px;
height: 47px;
text-align: center;
}
body {
background: #f1f1f1;
}
<button onclick="go()">Click me</button>
<div class="progress clip-svg">
<div class="progress__content">0%</div>
<svg width="160" height="160">
<defs>
<linearGradient id="gradient" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="160" y2="0">
<stop stop-color="#EE3028" offset="0" />
<stop stop-color="#067BC2" offset="160" />
</linearGradient>
</defs>
<ellipse rx="75" ry="75" cx="80" cy="80" stroke="#f2f2f2" fill="none" stroke-width="10"></ellipse>
<g>
<path id="path" stroke-width="10" stroke="url(#gradient)" fill="none" d="">
</path>
</g>
</svg>
</div>