svgstrokesvg-filters

Using SVG filter to create an inside stroke


I would like to simulate and "inside stroke" on an svg path. I have an svg map with multiple complex paths (countries) each with a different fill color stroke. And i would like to add a "fake inside stroke" in the first one. I managed to get a few things done with the inner-shadow trick (with gaussian blur filter) but can't manage to have it as "non-blurry".

The ideal solution would be as an svg filter so i can apply it dynamicaly via JS without changing path or manipulating dom.

Thanks a lot ! Edit 1 : So far i tried this trick but the fake shadow is sometimes over the stroke and always blurry so i'm not sure that's even the best way ...

  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="150" style="transform:scale(2);transform-origin:0 0 ">
     <defs>
  <filter id='inset' x='-50%' y='-50%' width='200%' height='200%'>
  
    <feFlood fill-color="black"/>
    <feComposite in2="SourceAlpha" operator="out"/>
    
    <feGaussianBlur stdDeviation='10' edgeMode="none" />
    <feOffset dx='0' dy='0' result='offsetblur'/>
    <feFlood flood-color='#00ff00' result='color'/>
    <feComposite in2='offsetblur' operator='in'/>
    <feComposite in2='SourceAlpha' operator='in' />
    <feMerge>
      <feMergeNode in='SourceGraphic'/>
        <feMergeNode/>
    </feMerge>
  </filter> 
       
	</defs>
  
<path class="st0" d="M144.7,126.2l-2.8,8.8l-3.9-2.3l-2-7.7l1.7-4.3l5.5-4.4L144.7,126.2z M93.5,24.2l6,6.3l4.4-1l7.5,6l1.9,1.1
	l2.5-0.3l4,3.4l12.3,2.4l-4.3,8.9l-1.1,9.1l-2.4,2.2l-3.9-1.2l0.3,3.2l-6.3,7l-0.1,5.6l4.1-1.9l2.9,5.4L121,84l2.5,4.6l-3,3.7
	l2.2,9.3l4.6,1.5l-1,5.1l-7.8,6.6l-16.9-3.2l-12.5,3.8l-1,7l-9.9,1.5l-9.6-5.3l-3.1,2.5l-15.8-5.3l-3.4-4.6l4.4-7.1l1.6-24.1
	l-8.8-13l-6.3-6.4l-13.1-4.9l-0.9-9.4l11.1-2.8L48.9,47l-2.7-14.8l8.1,5.7l20-10.3l2.6-11l7.5-2.8l1.3,4.8l4,0.2L93.5,24.2z" stroke-width="1" fill="#00ffff"  stroke="#FF0000" filter="url(#inset)"/>
</svg>


Solution

  • If you want clear shape, you should use SVG transform instead of applying CSS transform to svg element.

    And when you draw "inside stroke", the feMorphorogy element is useful. This reduces(or increases) paint area of target shape, thus you can draw "fake inside/outside" stroke.

    <svg xmlns="http://www.w3.org/2000/svg" 
      xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300">
      <defs>
        <filter id='inset' x='-50%' y='-50%' width='200%' height='200%'>
          <!--outside-stroke-->
          <feFlood flood-color="red" result="outside-color"/>
          <feMorphology in="SourceAlpha" operator="dilate" radius="2"/>
          <feComposite in="outside-color" operator="in" result="outside-stroke"/>
          <!--inside-stroke-->
          <feFlood flood-color="blue" result="inside-color"/>
          <feComposite in2="SourceAlpha" operator="in" result="inside-stroke"/>
          <!--fill-area-->
          <feMorphology in="SourceAlpha" operator="erode" radius="2"/>
          <feComposite in="SourceGraphic" operator="in" result="fill-area"/>
          <!--merge graphics-->
          <feMerge>
            <feMergeNode in="outside-stroke"/>
            <feMergeNode in="inside-stroke"/>
            <feMergeNode in="fill-area"/>
          </feMerge>
        </filter>
      </defs>
      <g transform="scale(2)">
        <path class="st0" d="M144.7,126.2l-2.8,8.8l-3.9-2.3l-2-7.7l1.7-4.3l5.5-4.4L144.7,126.2z M93.5,24.2l6,6.3l4.4-1l7.5,6l1.9,1.1
      l2.5-0.3l4,3.4l12.3,2.4l-4.3,8.9l-1.1,9.1l-2.4,2.2l-3.9-1.2l0.3,3.2l-6.3,7l-0.1,5.6l4.1-1.9l2.9,5.4L121,84l2.5,4.6l-3,3.7
      l2.2,9.3l4.6,1.5l-1,5.1l-7.8,6.6l-16.9-3.2l-12.5,3.8l-1,7l-9.9,1.5l-9.6-5.3l-3.1,2.5l-15.8-5.3l-3.4-4.6l4.4-7.1l1.6-24.1
      l-8.8-13l-6.3-6.4l-13.1-4.9l-0.9-9.4l11.1-2.8L48.9,47l-2.7-14.8l8.1,5.7l20-10.3l2.6-11l7.5-2.8l1.3,4.8l4,0.2L93.5,24.2z"
    fill="#00ffff" filter="url(#inset)"/>
      </g>
    </svg>