Add concentric lines around a rect in svg

Viewed 62

I try to create a rect with 3 borders around using filters. The result should look like this:

enter image description here

but my result looks like this:

enter image description here

code:

<svg width=1000 height=1000 >
    <rect width=300 height=50 rx=25 x=100 y=100 filter="url(#filter)" fill="white"></rect>
    <filter id="filter">

      <feFlood flood-color="RGBA(173, 15, 91, 1.00)" result="fill1"></feFlood>
      <feMorphology in="SourceAlpha" operator="dilate" radius="8" result="radius1"></feMorphology>
      <feComposite in="fill1" in2="radius1" operator="in" result="compose1"></feComposite>
     
      <feFlood flood-color="RGBA(217, 145, 180, 1.00)" result="fill2"></feFlood>
      <feMorphology in="SourceAlpha" operator="dilate" radius="16" result="radius2"></feMorphology>
      <feComposite in="fill2" in2="radius2" operator="in" result="compose2"></feComposite>
      
           
      <feFlood flood-color="RGBA(247, 231, 239, 1.00)" result="fill3"></feFlood>
      <feMorphology in="SourceAlpha" operator="dilate" radius="24" result="radius3"></feMorphology>
      <feComposite in="fill3" in2="radius3" operator="in" result="compose3"></feComposite>
      
      <feMerge result="a452afbd-5e3f-4c25-abcf-3c77051dd340">
        <feMergeNode in="compose3"></feMergeNode>
        <feMergeNode in="compose2"></feMergeNode>

        <feMergeNode in="compose1"></feMergeNode>
        <feMergeNode in="SourceGraphic"></feMergeNode>

      </feMerge>
    </filter>
  </svg>

any idea how to get this right using filters.

3 Answers

If you want to retain the shape, you can't use feMorphology because it uses a square evenly weighted kernel. Instead you have to use a blur and an alpha boost (aka the gooey effect). (Also need to increase the filter region)

<svg width="1000px" height="1000px" >
    <rect width=300 height=50 rx=25 x=100 y=100 filter="url(#filter)" fill="white"></rect>
    <filter id="filter" x="-50%" y="-100%" height="400%" width="200%" color-interpolation-filters="sRGB">

      <feFlood flood-color="RGBA(173, 15, 91, 1.00)" result="fill1"/>
      <feGaussianBlur stdDeviation="8" in="SourceGraphic"/>
      <feColorMatrix type="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 20 -2" result="radius1"/>
      <feComposite in="fill1" in2="radius1" operator="in" result="compose1"/>
     
      <feFlood flood-color="RGBA(217, 145, 180, 1.00)" result="fill2"/>
      <feGaussianBlur stdDeviation="8" in="compose1"  />
      <feColorMatrix type="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 20 -2" result="radius2"/>
      <feComposite in="fill2" in2="radius2" operator="in" result="compose2"/>
      
           
      <feFlood flood-color="RGBA(247, 231, 239, 1.00)" result="fill3"/>
      <feGaussianBlur stdDeviation="8" in="compose2"/>
      <feColorMatrix type="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 20 -2" result="radius3"/>
      <feComposite in="fill3" in2="radius3" operator="in" result="compose3"/>
      
      <feMerge result="a452afbd-5e3f-4c25-abcf-3c77051dd340">
        <feMergeNode in="compose3"></feMergeNode>
        <feMergeNode in="compose2"></feMergeNode>
        <feMergeNode in="compose1"></feMergeNode>
        <feMergeNode in="SourceGraphic"></feMergeNode>
      </feMerge>
    </filter>
  </svg>

You just neede to increase the filter bounds so they extend far enough outside the object being filtered.

The defaults are an additional 10% in all directions but that's not enough for your use case.

<svg width=1000 height=1000 >
    <rect width=300 height=50 rx=25 x=100 y=100 filter="url(#filter)" fill="white"></rect>
    <filter id="filter" y="-70%" height="240%">

      <feFlood flood-color="RGBA(173, 15, 91, 1.00)" result="fill1"></feFlood>
      <feMorphology in="SourceAlpha" operator="dilate" radius="8" result="radius1"></feMorphology>
      <feComposite in="fill1" in2="radius1" operator="in" result="compose1"></feComposite>
     
      <feFlood flood-color="RGBA(217, 145, 180, 1.00)" result="fill2"></feFlood>
      <feMorphology in="SourceAlpha" operator="dilate" radius="16" result="radius2"></feMorphology>
      <feComposite in="fill2" in2="radius2" operator="in" result="compose2"></feComposite>
      
           
      <feFlood flood-color="RGBA(247, 231, 239, 1.00)" result="fill3"></feFlood>
      <feMorphology in="SourceAlpha" operator="dilate" radius="24" result="radius3"></feMorphology>
      <feComposite in="fill3" in2="radius3" operator="in" result="compose3"></feComposite>
      
      <feMerge result="a452afbd-5e3f-4c25-abcf-3c77051dd340">
        <feMergeNode in="compose3"></feMergeNode>
        <feMergeNode in="compose2"></feMergeNode>

        <feMergeNode in="compose1"></feMergeNode>
        <feMergeNode in="SourceGraphic"></feMergeNode>

      </feMerge>
    </filter>
  </svg>

Couldn't you just draw this with separate paths instead?

<svg width="320" height="120" viewBox="0 0 320 120">
<rect x="10" y="10" width="300" height="100" rx="50" ry="50" fill="none" stroke="#fad" stroke-width="10"/>
<rect x="20" y="20" width="280" height="80" rx="40" ry="40" fill="none" stroke="#b58" stroke-width="10"/>
<rect x="30" y="30" width="260" height="60" rx="30" ry="30" fill="none" stroke="#603" stroke-width="10"/>
</svg>

Related