【问题标题】:svg multiple color on circle strokesvg 圆形笔划上的多种颜色
【发布时间】:2013-08-14 21:47:29
【问题描述】:

我想画一个彩虹圈,如下图:

如何绘制弯曲和多色停止渐变?

这是我当前的代码:

<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
    <linearGradient id="test">
    <stop offset="0%" stop-color="#f00"/>
    <stop offset="100%" stop-color="#0ff"/>
    </linearGradient>    
    </defs>    
    <circle cx="50" cy="50" r="40" fill="none" stroke="url(#test)" stroke-width="6"/>    
</svg>

【问题讨论】:

    标签: svg colors gradient curve


    【解决方案1】:

    这种方法行不通。 SVG 没有锥形渐变。为了模拟这种效果,你必须用大量的小线段来伪造它。或者一些类似的技术。

    更新:

    这是一个例子。我用六条路径来近似 360 度的色调。每条路径都包含一个覆盖圆 60 度的弧。我使用线性渐变来插入从每条路径的开始到结束的颜色。它并不完美(你可以看到一些不连续的颜色相遇),但它可能会欺骗大多数人。您可以通过使用六个以上的段来提高准确性。

        <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="-10 -10 220 220">
          <defs>
            <linearGradient id="redyel" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
                <stop offset="0%" stop-color="#ff0000"/>   
                <stop offset="100%" stop-color="#ffff00"/>   
            </linearGradient>
            <linearGradient id="yelgre" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stop-color="#ffff00"/>   
                <stop offset="100%" stop-color="#00ff00"/>   
            </linearGradient>
            <linearGradient id="grecya" gradientUnits="objectBoundingBox" x1="1" y1="0" x2="0" y2="1">
                <stop offset="0%" stop-color="#00ff00"/>   
                <stop offset="100%" stop-color="#00ffff"/>   
            </linearGradient>
            <linearGradient id="cyablu" gradientUnits="objectBoundingBox" x1="1" y1="1" x2="0" y2="0">
                <stop offset="0%" stop-color="#00ffff"/>   
                <stop offset="100%" stop-color="#0000ff"/>   
            </linearGradient>
            <linearGradient id="blumag" gradientUnits="objectBoundingBox" x1="0" y1="1" x2="0" y2="0">
                <stop offset="0%" stop-color="#0000ff"/>   
                <stop offset="100%" stop-color="#ff00ff"/>   
            </linearGradient>
            <linearGradient id="magred" gradientUnits="objectBoundingBox" x1="0" y1="1" x2="1" y2="0">
                <stop offset="0%" stop-color="#ff00ff"/>   
                <stop offset="100%" stop-color="#ff0000"/>   
            </linearGradient>
          </defs>
        
          <g fill="none" stroke-width="15" transform="translate(100,100)">
            <path d="M 0,-100 A 100,100 0 0,1 86.6,-50" stroke="url(#redyel)"/>
            <path d="M 86.6,-50 A 100,100 0 0,1 86.6,50" stroke="url(#yelgre)"/>
            <path d="M 86.6,50 A 100,100 0 0,1 0,100" stroke="url(#grecya)"/>
            <path d="M 0,100 A 100,100 0 0,1 -86.6,50" stroke="url(#cyablu)"/>
            <path d="M -86.6,50 A 100,100 0 0,1 -86.6,-50" stroke="url(#blumag)"/>
            <path d="M -86.6,-50 A 100,100 0 0,1 0,-100" stroke="url(#magred)"/>
          </g>
        </svg>

    在这里提琴:http://jsfiddle.net/Weytu/

    更新 2:

    对于那些想要超过六个段的人,这里有一些 javascript 可以生成一个带有任意数量段的轮子。

    function makeColourWheel(numSegments)
    {
        if (numSegments <= 0)
            numSegments = 6;
        if (numSegments > 360)
            numSegments = 360;
    
        var  svgns = xmlns="http://www.w3.org/2000/svg";
        var  svg = document.getElementById("colourwheel");
        var  defs = svg.getElementById("defs");
        var  paths = svg.getElementById("paths");
    
        var  radius = 100;
        var  stepAngle = 2 * Math.PI / numSegments;
    
        var  lastX = 0;
        var  lastY = -radius;
        var  lastAngle = 0;
        
        for (var i=1; i<=numSegments; i++)
        {
            var  angle = i * stepAngle;
    
            // Calculate this arc end point
            var x = radius * Math.sin(angle);
            var y = -radius * Math.cos(angle);
            // Create a path element
            var arc = document.createElementNS(svgns, "path");
            arc.setAttribute("d", "M " + lastX.toFixed(3) + "," + lastY.toFixed(3)
                                  + " A 100,100 0 0,1 " + x.toFixed(3) + "," + y.toFixed(3));
            arc.setAttribute("stroke", "url(#wheelseg" + i + ")");
            // Append it to our SVG
            paths.appendChild(arc);
            
            // Create a gradient for this segment
            var grad = document.createElementNS(svgns, "linearGradient");
            grad.setAttribute("id", "wheelseg"+i);
            grad.setAttribute("gradientUnits", "userSpaceOnUse");
            grad.setAttribute("x1", lastX.toFixed(3));
            grad.setAttribute("y1", lastY.toFixed(3));
            grad.setAttribute("x2", x.toFixed(3));
            grad.setAttribute("y2", y.toFixed(3));
            // Make the 0% stop for this gradient
            var stop = document.createElementNS(svgns, "stop");
            stop.setAttribute("offset", "0%");
            hue = Math.round(lastAngle * 360 / Math.PI / 2);
            stop.setAttribute("stop-color", "hsl(" + hue + ",100%,50%)");
            grad.appendChild(stop);
            // Make the 100% stop for this gradient
            stop = document.createElementNS(svgns, "stop");
            stop.setAttribute("offset", "100%");
            hue = Math.round(angle * 360 / Math.PI / 2);
            stop.setAttribute("stop-color", "hsl(" + hue + ",100%,50%)");
            grad.appendChild(stop);
            // Add the gradient to the SVG
            defs.appendChild(grad);
    
            // Update lastx/y
            lastX = x;
            lastY = y;
            lastAngle = angle;
        }
    }
    
    
    makeColourWheel(60);
    <svg id="colourwheel" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="-10 -10 220 220">
      <defs id="defs">
      </defs>
    
      <g id="paths" fill="none" stroke-width="15" transform="translate(100,100)">
      </g>
    </svg>

    【讨论】:

    • 请问有什么例子吗?我只想按照图片显示的那样做,大小无所谓。
    • 更新了一个例子。
    • 如何实施新细分?
    • 您需要根据您希望额外弧线开始和结束的位置来计算和添加额外的弧线路径。我在这里使用的六边形的优点是它使计算这些坐标和梯度变得相当容易。
    • 我已经用一些 JS 更新了答案来生成轮子。
    【解决方案2】:

    你可以使用 conic-gradient 来解决它:

    .color-wheel {
      display: inline-block;
      padding: 25px;
      border-radius: 100%;
      background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
      background-repeat: no-repeat;
      background-size: cover;
      background-position: center center;
      background-size: auto;
    }
    
    .color-wheel::after {
      content: '';
      display: block;
      padding: 75px;
      border-radius: 100%;
      background: #ffffff;
    }
    &lt;div class="color-wheel"&gt;&lt;/div&gt;

    但这目前仅在 Chrome 中受支持。在这里查看更多信息:https://caniuse.com/#feat=css-conic-gradients

    我还构建了可以轻松解决的 javascript/svg 解决方案:

    const resolution = 1;
    const outerRadius = 100;
    const innerRadius = 75;
    
    function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
        const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
    
        return {
            x: centerX + radius * Math.cos(angleInRadians),
            y: centerY + radius * Math.sin(angleInRadians)
        };
    }
    
    function describeArc(x, y, radius, startAngle, endAngle) {
        const start = polarToCartesian(x, y, radius, endAngle);
        const end = polarToCartesian(x, y, radius, startAngle);
    
        const arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
    
        const d = [
            'M', start.x, start.y,
            'A', radius, radius, 0, arcSweep, 0, end.x, end.y,
            'L', x, y,
            'L', start.x, start.y
        ].join(' ');
    
        return d;
    }
    
    function generateConicGradiant(radius, resolution, target) {
        for (var i = 0; i < 360 * resolution; i++) {
            const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    
            path.setAttribute(
                "d",
                describeArc(
                    radius,
                    radius,
                    radius,
                    i / resolution,
                    (i + 2) / resolution
                )
            );
            path.setAttribute('fill', 'hsl(' + (i / resolution) + ', 100%, 50%)');
    
            target.appendChild(path);
        } 
    }
    
    function generateOverlay(outerRadius, innerRadius, target) {
        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
    
        circle.setAttribute('cx', outerRadius);
        circle.setAttribute('cy', outerRadius);
        circle.setAttribute('r', innerRadius);
        circle.setAttribute('fill', 'white');
    
        target.appendChild(circle);
    }
    
    var root = document.getElementById('color-wheel');
    
    generateConicGradiant(outerRadius, resolution, root);
    generateOverlay(outerRadius, innerRadius, root);
    #color-wheel {
      width: 200px;
      height: 200px;
    }
    &lt;svg viewBox="0 0 200 200" version="1.1" id="color-wheel"&gt;&lt;/svg&gt;

    【讨论】:

    • 现在支持 Firefox 83+!
    【解决方案3】:

    改进 oVi 的回答:在这里您可以将 diameterstroke-width 设置为精确的像素大小

    .color-wheel {
      --diameter: 160px;
      --stroke-width: 20px;
      position: relative;
      width: var(--diameter); height: var(--diameter);
    }
    
    .color-wheel > .color-circle {
      position: absolute;
      left: 0; top: 0;
      border-radius: 50%;
      width: 100%; height: 100%;
      background: conic-gradient(red, orange, yellow, lime, green, turquoise, blue, purple, red); /* four color system */
    }
    
    .color-wheel > .inner-circle {
      --inner-diameter: calc(var(--diameter) - 2 * var(--stroke-width));
      --margin: calc(-0.5 * var(--inner-diameter));
      position: absolute;
      left: 50%; top: 50%;
      width: var(--inner-diameter); height: var(--inner-diameter);
      margin-left: var(--margin); margin-top: var(--margin);
      border-radius: 50%;
      background: white;
    }
    
    .color-wheel > .overlay {
      position: absolute;
      left: 0; top: 0;
      width: 100%; height: 100%;
    }
    <div class="color-wheel">
      <div class="color-circle"></div>
      <div class="inner-circle"></div>
      <div class="overlay">
        hello world.
        this is a pure CSS color ring : )
      </div>
    </div>

    【讨论】:

      猜你喜欢
      • 2013-02-12
      • 2016-08-19
      • 2017-06-11
      • 2015-11-28
      • 2017-07-21
      • 2016-04-10
      • 2016-07-16
      • 2012-09-16
      • 2023-01-25
      相关资源
      最近更新 更多