user3014233
user3014233

Reputation:

SVG clipPpath multiple polygon elements does not work because xor

This is first time I use SVG to make transparent areas on thr picture(marked red) and probably I have very naive question, I wrote this code according to this answer and all elements are closed with /> as noted in this answer. The problem is its not work, because with my points the polygon elements are working as "XOR", how ca do the polygon elements "AND"?

enter image description here

<img src="https://i.sstatic.net/iZ7xG.jpg" style="clip-path: url(#myClip);">

<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <clipPath id="myClip"  clipPathUnits="objectBoundingBox">
      <polygon points="0 0, 0 1, .54 .99, .5682 .156, .746 .151, .7397 .557, .51 .508, .54 .99, 1 1, 1 0" />
      <polygon points="0 0, 0 1, .737 1, .747 .321, .816 .321, .81 .666, .74 .645, .74 1, 1 1, 1 0" />
      /*  It doesn't work, but if delete one of them so its work with only one polygon */
    </clipPath>
  </defs>
</svg>

Upvotes: 1

Views: 193

Answers (2)

herrstrietzel
herrstrietzel

Reputation: 17240

You can also use a compound path with alternating path directions.
As described here: The Winding Order of the Fill Rule

The <path> will contain 3 supaths:

M 0 0 ,0 1, 1 1, 1 0 z outer rectangle: drawn counterclockwise
M .747 .321 L .816 .321 L .81 .666 L .74 .645z 1rst screen shape: drawn clockwise
M 0.56 0.508 L 0.5682 0.156 L 0.746 0.151 L 0.7397 0.557 z 2nd screen shape: drawn clockwise

You can easily convert <polygon> points to <path> d commands by prepending an M command to the points values and appending a z (for closing the path). See also: "Convert SVG polygon to path"

Example: multiple polygons vs. compound path

body{
  background:#999;
}

img, svg{
  width:25%;
}
<img src="https://i.sstatic.net/iZ7xG.jpg" style="clip-path: url(#myClipPoly1); ">
<img src="https://i.sstatic.net/iZ7xG.jpg" style="clip-path: url(#myClipPoly2); ">
<img src="https://i.sstatic.net/iZ7xG.jpg" style="clip-path: url(#myClipCompoundPath); ">


<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <clipPath id="myClipPoly1"  clipPathUnits="objectBoundingBox" >
      <polygon id="poly1" points=".747 .321 , .816 .321 , .81 .666 , .74 .64" />
      <polygon id="poly2" points="0.56 0.508 , 0.5682 0.156 , 0.746 0.151 , 0.7397 0.557"  />
    </clipPath>
    <clipPath id="myClipPoly2"  clipPathUnits="objectBoundingBox" >
      <polygon id="outerRect" points="0 0 , 1 0, 1 1, 0 1"  />
      <polygon id="poly1" points=".747 .321 , .816 .321 , .81 .666 , .74 .64" />
      <polygon id="poly2" points="0.56 0.508 , 0.5682 0.156 , 0.746 0.151 , 0.7397 0.557"  />
    </clipPath>
    
    <clipPath id="myClipCompoundPath"  clipPathUnits="objectBoundingBox" >
      <path d="
      M 0 0 ,0 1, 1 1, 1 0  z
      M  .747 .321 L .816 .321 L .81 .666 L .74 .645z
      M 0.56 0.508 L 0.5682 0.156 L 0.746 0.151 L 0.7397 0.557 z
      " />
    </clipPath>
  </defs>
</svg>

As you can see the second example doesn't clip anything, since both torus fill areas are overlapping.

multiple polygon clip path

Upvotes: 1

ccprog
ccprog

Reputation: 21821

It is not very suprising this does not work. You are trying to make "inverse" clip paths. Clip paths hide anything that is outside their shape. but you want to hide only what is inside a shape. For that, you draw a torus consisting of the bounding box and your shape, and then cut a line through to make one continous polygon.

Now think about how multiple shapes in a clip path work: everything that is inside one of the shapes is shown. Everything that is outside both shapes is hidden.

The way your polygons are formed, the areas you want to hide are inside one shape and ouside the other. Accordingly, they remain visible.

In this case, it is much easier to use a mask. It works by coloring shapes. Everything that is white (luminance = 1) is shown, everything that is black (luninance = 0) is hidden.

<img src="https://i.sstatic.net/iZ7xG.jpg" style="mask: url(#myMask);">

<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <mask id="myMask"  maskContentUnits="objectBoundingBox">
      <!--white surrounding rectangle: visible-->
      <rect width="1" height="1" fill="white" />
      <!-- black cutout shapes: hidden -->
      <polygon points=".556 .518, .5682 .156, .746 .151, .7397 .557" fill="black" />
      <polygon points=".747 .321, .816 .321, .81 .666, .74 .645" fill="black" />
    </mask>
  </defs>
</svg>

Upvotes: 1

Related Questions