Gradient across path in SVG

2019-07-27 01:53发布

I have a very simple path within a SVG.

<svg
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 61 57" 
    version="1.1" x="0px" y="0px">
    <defs>
        <style type="text/css"><![CDATA[
            ]]>
        </style>
    </defs>
    <path id="pipe" d="
        M8.0178,52.0035
        L27.0178,52.0035
        C42.4568,52.0035 55.0178,39.4425 55.0178,24.0035
        L55.0178,8.0035
        L43.0178,8.0035
        L43.0178,24.0035
        C43.0178,32.8255 35.8398,40.0035 27.0178,40.0035
        L8.0178,40.0035
        L8.0178,52.0035
        Z">
    </path>
</svg>

(Preview: https://i.imgur.com/nVnxcRg.png)

What I'd like to achive is that I have 3 separate gradients or filling spaces:

  • The first one is from the inner curve to the center of the bended tube (curve).
  • The second one is the center area.
  • The third one from the center area to the outer curve of the tube.

Alternatively I could also use a single gradient with multiple stop colors.

The following image illustrates the wanted result: https://i.imgur.com/oPEFAZT.png In this case the rectangles I added illustrate the gradient that I want to use along the whole curve.

I did some research regarding advanced gradients in SVG but I was not able to understand how to apply them or if that is even necessary. I understand how to apply radial and linear gradients to rectangles or even to curves but that did not deliver the expected result.

I also found Can I apply a gradient along an SVG path? which creates a gradient in the tube from left to right (so to say) and I'd like it from top to bottom.

Do you guys have any ideas how to solve this?

标签: svg
2条回答
爷的心禁止访问
2楼-- · 2019-07-27 02:42

You can may get the result you want by using filters with blur or lighting. Here is a good article on advanced filters: https://www.smashingmagazine.com/2015/05/why-the-svg-filter-is-awesome/

<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300" viewBox="0 0 150 150" >
    <defs>
        <filter id="filter1">
            <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blurOut" />
            <!-- We cut off the parts that overlap the source graphic… -->
            <feComposite operator="in" in="blurOut" in2="SourceAlpha" result="COMPOSITE"/>
            <!-- … and then merge source graphic and lighting effect: -->
            <feMerge>
                <feMergeNode in="SourceGraphic" />
                <feMergeNode in="COMPOSITE"/>
            </feMerge>
        </filter>

        <!-- https://www.smashingmagazine.com/2015/05/why-the-svg-filter-is-awesome/ -->
        <filter id="filter2">
            <!--We create a heightmap by blurring the source: -->
            <feGaussianBlur stdDeviation="5" in="SourceAlpha" result="BLUR"/>
            <!-- We then define a lighting effect with a point light that is positioned at virtual 3D coordinates x: 40px, y: -30px, z: 200px: -->
            <feSpecularLighting surfaceScale="6" specularConstant="1" specularExponent="30" lighting-color="#white" in="BLUR" result="SPECULAR">
                <fePointLight x="40" y="40" z="2000" />
            </feSpecularLighting>
            <!-- We cut off the parts that overlap the source graphic… -->
            <feComposite operator="in" in="SPECULAR" in2="SourceAlpha" result="COMPOSITE"/>
            <!-- … and then merge source graphic and lighting effect: -->
            <feMerge>
                <feMergeNode in="SourceGraphic" />
                <feMergeNode in="COMPOSITE"/>
            </feMerge>
        </filter>
    </defs>

    <path stroke="white" stroke-width="20" fill="none" filter="url(#filter1)" 
          d="M-90,50 h150 a20,20 0 0,0 20,-20 v-150" />

    <path stroke="black" stroke-width="20" fill="none" filter="url(#filter2)" 
          d="M-40,100 h150 a20,20 0 0,0 20,-20 v-150" />
</svg>

查看更多
唯我独甜
3楼-- · 2019-07-27 02:48

In general it is not possible to create gradients that flow along a path.

However, in cases like yours which only involve straight pieces and circular arcs, you can achieve the effect by breaking the shape up into those sections. Then you apply a different gradient to each part. You use a <linearGradient> for the straight sections, and a <radialGredient> for the curved sections.

In the example below, I have used a very simplified gradient for the "pipe" effect. You will probably wish to add more stops to yours to give a better 3D effect.

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 61 57" 
    version="1.1" x="0px" y="0px">
    <defs>
      <linearGradient id="horizontalPipe" x2="0" y2="1">
        <stop offset="0" stop-color="white"/>
        <stop offset="0.25" stop-color="black"/>
        <stop offset="0.75" stop-color="black"/>
        <stop offset="1" stop-color="white"/>
      </linearGradient>
      <linearGradient id="verticalPipe">
        <stop offset="0" stop-color="white"/>
        <stop offset="0.25" stop-color="black"/>
        <stop offset="0.75" stop-color="black"/>
        <stop offset="1" stop-color="white"/>
      </linearGradient>
      <radialGradient id="curvedPipe" cx="0" cy="0" r="1">
        <stop offset="0.57" stop-color="white"/>
        <stop offset="0.677" stop-color="black"/>
        <stop offset="0.893" stop-color="black"/>
        <stop offset="1" stop-color="white"/>
      </radialGradient>
    </defs>
    
    <rect x="8" y="40" width="19" height="12" fill="url(#horizontalPipe)"/>
    <path d="M 27,40 A 16,16, 0,0,0 43,24 H 55 A 28,28, 0,0,1, 27,52 Z" fill="url(#curvedPipe)"/>
    <rect x="43" y="8" width="12" height="16" fill="url(#verticalPipe)"/>
</svg>

查看更多
登录 后发表回答