如何使用渐变制作一个带有焦点点的非完整圆形描边?

huangapple go评论65阅读模式
英文:

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 -->

&lt;svg version=&quot;1.1&quot; id=&quot;Layer_1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; x=&quot;0px&quot; y=&quot;0px&quot; width=&quot;500px&quot; height=&quot;500px&quot; viewBox=&quot;0 0 120 120&quot; enable-background=&quot;new 0 0 120 120&quot; xml:space=&quot;preserve&quot;&gt;

   &lt;circle class=&quot;ring&quot; fill=&quot;none&quot; stroke=&quot;url(#linear)&quot; stroke-width=&quot;10&quot; stroke-miterlimit=&quot;10&quot; cx=&quot;50%&quot; cy=&quot;50%&quot; r=&quot;50&quot;/&gt;

   &lt;defs&gt;
       &lt;linearGradient id=&quot;linear&quot; x1=&quot;0%&quot; y1=&quot;0%&quot; x2=&quot;100%&quot; y2=&quot;0%&quot;&gt;
           &lt;stop offset=&quot;0%&quot; stop-color=&quot;#05a&quot;&gt;&lt;/stop&gt;
           &lt;stop offset=&quot;50%&quot; stop-color=&quot;#a55&quot;&gt;&lt;/stop&gt;
           &lt;stop offset=&quot;100%&quot; stop-color=&quot;#0a5&quot;&gt;&lt;/stop&gt;
       &lt;/linearGradient&gt;
   &lt;/defs&gt;
&lt;/svg&gt;

<!-- 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 &lt;animateMotion&gt; animating a ring along the path that does not really move. The position is set as the keyPoints=&quot;x;x&quot; 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(&#39;#progress animateMotion&#39;);

function position (x) {
  marker.setAttribute(&#39;keyPoints&#39;, `${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 -->

&lt;svg width=&quot;0&quot; height=&quot;0&quot;&gt;
  &lt;mask id=&quot;progress&quot; width=&quot;100&quot; height=&quot;100&quot;&gt;
    &lt;path id=&quot;arc&quot; d=&quot;M 25,85 A 40 40 0 1 1 75,85&quot; pathLength=&quot;100&quot; /&gt;
    &lt;circle r=&quot;7&quot;&gt;
      &lt;animateMotion path=&quot;M 25,85 A 40 40 0 1 1 75,85&quot;
                     keyTimes=&quot;0;1&quot; begin=&quot;0s&quot; fill=&quot;freeze&quot;
                     keyPoints=&quot;0;0&quot; /&gt;
    &lt;/circle&gt;
  &lt;/mask&gt;
&lt;/svg&gt;
&lt;div id=&quot;meter&quot;&gt;&lt;/div&gt;

<!-- 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(&#39;change&#39;, e =&gt; {
  document.getElementById(&#39;point&#39;).setAttribute(&#39;transform&#39;, `rotate(${e.target.value})`);
});

<!-- language: lang-css -->

body{
  background-color: #303030;
}

<!-- language: lang-html -->

&lt;form name=&quot;form01&quot;&gt;
  &lt;input type=&quot;range&quot; step=&quot;10&quot; name=&quot;range&quot; min=&quot;0&quot; max=&quot;270&quot; value=&quot;30&quot;&gt;
&lt;/form&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;200&quot; viewBox=&quot;0 0 100 100&quot;&gt;
  &lt;defs&gt;
    &lt;linearGradient id=&quot;lg1&quot; x1=&quot;0&quot; x2=&quot;0&quot; y1=&quot;55&quot; y2=&quot;0&quot; gradientUnits=&quot;userSpaceOnUse&quot;&gt;
      &lt;stop offset=&quot;20%&quot; stop-color=&quot;Gold&quot;/&gt;
      &lt;stop offset=&quot;90%&quot; stop-color=&quot;SpringGreen&quot;/&gt;
    &lt;/linearGradient&gt;
    &lt;linearGradient id=&quot;lg2&quot; x1=&quot;0&quot; x2=&quot;0&quot; y1=&quot;55&quot; y2=&quot;0&quot; gradientUnits=&quot;userSpaceOnUse&quot;&gt;
      &lt;stop offset=&quot;20%&quot; stop-color=&quot;DarkOrange&quot;/&gt;
      &lt;stop offset=&quot;90%&quot; stop-color=&quot;Gold&quot;/&gt;
    &lt;/linearGradient&gt;
    &lt;linearGradient id=&quot;lg3&quot; x1=&quot;0&quot; x2=&quot;0&quot; y1=&quot;55&quot; y2=&quot;0&quot; gradientUnits=&quot;userSpaceOnUse&quot;&gt;
      &lt;stop offset=&quot;20%&quot; stop-color=&quot;red&quot;/&gt;
      &lt;stop offset=&quot;90%&quot; stop-color=&quot;DarkOrange&quot;/&gt;
    &lt;/linearGradient&gt;
    &lt;linearGradient id=&quot;lg4&quot; x1=&quot;0&quot; x2=&quot;0&quot; y1=&quot;55&quot; y2=&quot;0&quot; gradientUnits=&quot;userSpaceOnUse&quot;&gt;
      &lt;stop offset=&quot;20%&quot; stop-color=&quot;DarkOrchid&quot;/&gt;
      &lt;stop offset=&quot;90%&quot; stop-color=&quot;red&quot;/&gt;
    &lt;/linearGradient&gt;
    &lt;mask id=&quot;m1&quot;&gt;
      &lt;circle r=&quot;45&quot; stroke=&quot;white&quot; stroke-width=&quot;10&quot; stroke-linecap=&quot;round&quot; stroke-dasharray=&quot;270 360&quot; pathLength=&quot;360&quot; /&gt;
      &lt;g id=&quot;point&quot; transform=&quot;rotate(30)&quot;&gt;
        &lt;circle transform=&quot;translate(45 0)&quot; r=&quot;6&quot; stroke=&quot;black&quot; fill=&quot;white&quot; stroke-width=&quot;3&quot;/&gt;
      &lt;/g&gt;
    &lt;/mask&gt;
  &lt;/defs&gt;
  &lt;g transform=&quot;translate(50 50) rotate(135)&quot; stroke-linecap=&quot;round&quot; stroke-width=&quot;25&quot; mask=&quot;url(#m1)&quot;&gt;
    &lt;line transform=&quot;translate(50 0) rotate(30)&quot; stroke=&quot;url(#lg1)&quot; y2=&quot;55&quot; /&gt;
    &lt;line transform=&quot;rotate(70) translate(50 0) rotate(30)&quot; stroke=&quot;url(#lg2)&quot; y2=&quot;55&quot; /&gt;
    &lt;line transform=&quot;rotate(140) translate(50 0) rotate(30)&quot; stroke=&quot;url(#lg3)&quot; y2=&quot;55&quot; /&gt;
    &lt;line transform=&quot;rotate(210) translate(50 0) rotate(30)&quot; stroke=&quot;url(#lg4)&quot; y2=&quot;55&quot; /&gt;
  &lt;/g&gt;
&lt;/svg&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月17日 21:36:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76272725.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定