Home > Enterprise >  SVG filters outside of a bounding box/clip path/shape
SVG filters outside of a bounding box/clip path/shape

Time:04-01

I have filters working inside <g> elements with clip-paths.

    <g ref="backSphere" id="backSphere"></g>
    <g style="clip-path: url(#clip)">
        <use xlink:href="#backSphere" style="filter: url(#blur)"></use>
    </g>

Is there a simple way to "invert" this, so that the filters effectively apply to everything "outside" the clip path?

My current use case is a rectangle, but a more general answer would also be appreciated.

I know I can, for the most part:

  • Cover the entire SVG with one filter, then try to calculate the inverses for the applied filters with another: not ideal because of calculations, probably double-filter performance hits, and it might not math out precisely.
  • Create a piecemeal set of filter elements to patchwork in the coverage around the shape I want: not ideal because of individual positioning, and with either movement or more complex shapes this would be a bear.

CodePudding user response:

Invert the clip path, not the filter.

SVG clip paths can contain multiple grafical primitives, like two rectangles. In this case,

the silhouettes of the child elements are logically OR’d together to create a single silhouette

But if you use a single <path> element, the path can be composed of multiple subpaths, and what is clipped then is ruled by the clip-rule property.

<clipPath id="clip" clipPathUnits="userSpaceOnUse">
   <rect x="0" y="0" width="100" height="100"/>
   <rect x="30" y="30" width="40" height="40"/>
</clipPath>

would just clip to the first, larger rectangle. But exchanging the rects with equivalent subpaths,

<clipPath id="clip" clipPathUnits="userSpaceOnUse">
   <path d="M0,0 h100 v100 h-100 z M30,30 h40 v40 h-40 z" clip-rule="evenodd"/>
</clipPath>

clips to everything in between the two rectangular subpaths.

And that is your solution: Add an outer rectangle covering your complete viewport (or at least the filter region) to your clip path.

If you want to stay with grafical primitives, you can use a <mask> instead of a clip-path. White areas will be visible, black areas get hidden:

<mask id="clip">
   <rect x="0" y="0" width="100%" height="100%" fill="white"/>
   <rect x="30" y="30" width="40" height="40" fill="black"/>
</mask>

This has the additional benefit that you can write the large rectangle with percentage units, usefull for responsive behavior.

  • Related