英文:
How to make a non-full circle stroke with gradient with a focus point?
问题
我试图制作如下图所示的元素:
![显示部分圆弧半径的渐变](https://i.stack.imgur.com/y7ug8.jpg)
它基于苹果手表的空气质量小部件。
这个圆不是完全圆形,渐变在整个线条上变化。除此之外,还有一个“点”,显示实际数值(我想用JavaScript设置它)。
我尝试使用`dasharray`和`dashoffset`来制作半圆。但我无法让渐变跨越整个线条。我也无法在底部得到圆的间隙,除非在对象上使用`transform: rotate`。
```css
#Layer_1 {
transform: rotate(135deg);
}
.ring {
stroke-dasharray: 314;
stroke-dashoffset: 78;
stroke-linecap: round;
}
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="500px" height="500px" viewBox="0 0 120 120" enable-background="new 0 0 120 120" xml:space="preserve">
<circle class="ring" fill="none" stroke="url(#linear)" stroke-width="10" stroke-miterlimit="10" cx="50%" cy="50%" r="50"/>
<defs>
<linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#05a"></stop>
<stop offset="50%" stop-color="#a55"></stop>
<stop offset="100%" stop-color="#0a5"></stop>
</linearGradient>
</defs>
</svg>
英文:
I'm trying to make the element shown in the image below:
It is based on the Apple Watch widget for Air quality.
The circle is not fully round and the gradient changes across the line. Besides that, there is a 'point' that shows what the actual value is (I would like to set this with JavaScript).
I tried to make the half circle using dasharray
and dashoffset
. But the gradient I cannot get to cross the full line. I also cannot get the gap of the circle on the bottom without using transform: rotate
on the object.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-css -->
#Layer_1 {
transform: rotate(135deg);
}
.ring {
stroke-dasharray:314;
stroke-dashoffset: 78;
stroke-linecap: round;
}
<!-- language: lang-html -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="500px" height="500px" viewBox="0 0 120 120" enable-background="new 0 0 120 120" xml:space="preserve">
<circle class="ring" fill="none" stroke="url(#linear)" stroke-width="10" stroke-miterlimit="10" cx="50%" cy="50%" r="50"/>
<defs>
<linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#05a"></stop>
<stop offset="50%" stop-color="#a55"></stop>
<stop offset="100%" stop-color="#0a5"></stop>
</linearGradient>
</defs>
</svg>
<!-- end snippet -->
答案1
得分: 1
以下是您要翻译的内容:
"While SVG content does not support conical gradients directly, you can combine a HTML element with a background-image: conic-gradient()
and a SVG-defined mask that cuts out the arc and the position marker.
For the arc you can either use your technique with a circle and a stroke-dasharray
. I find it easier to draw a path with an appropriate arc. The pathLength
attribute will help in positioning along its length, but is not strictly needed for my solution.
There are multiple ways to achieve a progress marker, here I am going with a fake <animateMotion>
animating a ring along the path that does not really move. The position is set as the keyPoints="x;x"
attribute, with x
a number between 0 and 1, to be set with Javascript.
const marker = document.querySelector('#progress animateMotion');
function position (x) {
marker.setAttribute('keyPoints', `${x};${x}`);
}
position(0.2);
#progress #arc {
fill: none;
stroke: white;
stroke-width: 10;
stroke-linecap: round;
}
#progress circle {
fill: none;
stroke: black;
stroke-width: 4;
}
#meter {
position: relative;
width: 100px;
height: 100px;
background-image: conic-gradient(yellow, green, blue, red, orange, yellow);
mask: url(#progress);
}
<svg width="0" height="0">
<mask id="progress" width="100" height="100">
<path id="arc" d="M 25,85 A 40 40 0 1 1 75,85" pathLength="100" />
<circle r="7">
<animateMotion path="M 25,85 A 40 40 0 1 1 75,85"
keyTimes="0;1" begin="0s" fill="freeze"
keyPoints="0;0" />
</circle>
</mask>
</svg>
<div id="meter"></div>
希望这有所帮助!
英文:
While SVG content does not support conical gradients directly, you can combine a HTML element with a background-image: conic-gradient()
and a SVG-defined mask that cuts out the arc and the position marker.
For the arc you can either use your technique with a circle and a stroke-dasharray
. I find it easier to draw a path with an appropriate arc. The pathLength
attribute will help in positioning along its length, but is not strictly needed for my solution.
There are multiple ways to achieve a progress marker, here I am going with a fake <animateMotion>
animating a ring along the path that does not really move. The position is set as the keyPoints="x;x"
attribute, with x
a number between 0 and 1, to be set with Javascript.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const marker = document.querySelector('#progress animateMotion');
function position (x) {
marker.setAttribute('keyPoints', `${x};${x}`);
}
position(0.2);
<!-- language: lang-css -->
#progress #arc {
fill: none;
stroke: white;
stroke-width: 10;
stroke-linecap: round;
}
#progress circle {
fill: none;
stroke: black;
stroke-width: 4;
}
#meter {
position: relative;
width: 100px;
height: 100px;
background-image: conic-gradient(yellow, green, blue, red, orange, yellow);
mask: url(#progress);
}
<!-- language: lang-html -->
<svg width="0" height="0">
<mask id="progress" width="100" height="100">
<path id="arc" d="M 25,85 A 40 40 0 1 1 75,85" pathLength="100" />
<circle r="7">
<animateMotion path="M 25,85 A 40 40 0 1 1 75,85"
keyTimes="0;1" begin="0s" fill="freeze"
keyPoints="0;0" />
</circle>
</mask>
</svg>
<div id="meter"></div>
<!-- end snippet -->
答案2
得分: 1
你在涉及虚线数组时走在正确的道路上。在这个例子中,圆圈和焦点点是用蒙版创建的。该蒙版应用于一个包含四条不同线条的组,这四条线条共同构成了圆形渐变。我知道,问题与该渐变的关系不大,但现在SVG只有线性和径向渐变,它变得很重要。
英文:
You are on the right track when it comes to the stroke dash array. In this example the circle and the focus point is made using a mask. The mask is applied to a group containing four different lines that in all makes the circular gradient. I know, the question is not so much about that gradient, but it kind of gets important now that SVG only has linear and radial gradients.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
document.forms.form01.range.addEventListener('change', e => {
document.getElementById('point').setAttribute('transform', `rotate(${e.target.value})`);
});
<!-- language: lang-css -->
body{
background-color: #303030;
}
<!-- language: lang-html -->
<form name="form01">
<input type="range" step="10" name="range" min="0" max="270" value="30">
</form>
<svg xmlns="http://www.w3.org/2000/svg" width="200" viewBox="0 0 100 100">
<defs>
<linearGradient id="lg1" x1="0" x2="0" y1="55" y2="0" gradientUnits="userSpaceOnUse">
<stop offset="20%" stop-color="Gold"/>
<stop offset="90%" stop-color="SpringGreen"/>
</linearGradient>
<linearGradient id="lg2" x1="0" x2="0" y1="55" y2="0" gradientUnits="userSpaceOnUse">
<stop offset="20%" stop-color="DarkOrange"/>
<stop offset="90%" stop-color="Gold"/>
</linearGradient>
<linearGradient id="lg3" x1="0" x2="0" y1="55" y2="0" gradientUnits="userSpaceOnUse">
<stop offset="20%" stop-color="red"/>
<stop offset="90%" stop-color="DarkOrange"/>
</linearGradient>
<linearGradient id="lg4" x1="0" x2="0" y1="55" y2="0" gradientUnits="userSpaceOnUse">
<stop offset="20%" stop-color="DarkOrchid"/>
<stop offset="90%" stop-color="red"/>
</linearGradient>
<mask id="m1">
<circle r="45" stroke="white" stroke-width="10" stroke-linecap="round" stroke-dasharray="270 360" pathLength="360" />
<g id="point" transform="rotate(30)">
<circle transform="translate(45 0)" r="6" stroke="black" fill="white" stroke-width="3"/>
</g>
</mask>
</defs>
<g transform="translate(50 50) rotate(135)" stroke-linecap="round" stroke-width="25" mask="url(#m1)">
<line transform="translate(50 0) rotate(30)" stroke="url(#lg1)" y2="55" />
<line transform="rotate(70) translate(50 0) rotate(30)" stroke="url(#lg2)" y2="55" />
<line transform="rotate(140) translate(50 0) rotate(30)" stroke="url(#lg3)" y2="55" />
<line transform="rotate(210) translate(50 0) rotate(30)" stroke="url(#lg4)" y2="55" />
</g>
</svg>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论