44

So basically as my title says, I want to "cut a hole" in a rect element.

I have two rect elements, one on top of the other. The one on the bottom has a fill colour of white, and the one on the top has a fill colour of grey.

What I want to do is cut a triangle out of the top rect element so that the rect element below shows through.

This svg element is going to be used as an audio button for a media player on a page. In other words, you'll be able to click (or drag) your mouse left/right and the change in audio level will be represented by a change in the width of the rect element on the bottom, which shows through the triangle cut out of the top rect element.

I hope that's not too confusing. :P

Here is a quick mockup of what it should look like: http://forboden.com/coding/s1.png

Here is my code: http://forboden.com/coding/svgClipTest.html

Where am I going wrong here?

Yansky
  • 4,580
  • 8
  • 29
  • 24

3 Answers3

95

You should be able to use the fill-rule: evenodd(default) property to achieve this effect, if you want to prevent the fill of the rectangle from painting where the circle is. See this example from the SVG specification:

A pentagram and two circles, filled in red, with the centers cut showing the white background

The key point is draw outer shape and inner shapes(holes) in different direction (clockwise vs anti-clockwise).

  • Draw the outer shape clockwise and draw the inner(holes) shapes anti-clockwise.
  • Or conversely, draw the outer shape(holes) anti-clockwise and draw the inner shapes clockwise.
  • Concat the path datas of outer shape and inner shapes(holes).

You can cut more holes by concat more hole path data.

This image explain how to cut a hole:

enter image description here

Community
  • 1
  • 1
cuixiping
  • 24,167
  • 8
  • 82
  • 93
  • This is on the right track, but doesn't explain how to do it (use a `` with arcto commands). – Phrogz Oct 12 '14 at 01:55
  • use arcto draw outer cirle then inner circle in one path with different directions like this picture. – cuixiping Mar 17 '15 at 11:07
  • 6
    The direction of the paths doesn't actually matter. evenodd just makes it so that every time you cross a path, it "toggles" the state between fill and don't fill. The triangle example would work just as well with them both going clockwise or both going anti-clockwise. – Jake Griffin Mar 18 '17 at 03:07
  • 2
    @JakeGriffin fill-rule can be "nonzero" not only "evenodd". path direction take difference under "nonzero" mode. – cuixiping Apr 27 '17 at 08:23
  • Thanks. But is there a way how to solve overlapping "holes"? Please see my question [here](https://stackoverflow.com/questions/44446544/svg-using-path-element-to-create-an-area-with-holes). – Milan Hlinák Jun 09 '17 at 05:53
  • amazing illustrations, thanks for this explanation – T.W.R. Cole Sep 27 '18 at 14:54
  • is there anyway to draw cicle path? I need to draw rectangle with circle hole on the top of it. – Yestay Muratov Dec 10 '19 at 15:32
  • @YestayMuratov Use `A/a` command to draw circle, like the first example. – cuixiping Dec 11 '19 at 06:52
14

I see that you have it solved already, just wanted to add that if you want something more advanced then it's often quite easy to use a <mask>, see http://dev.w3.org/SVG/profiles/1.1F2/test/svg/masking-path-11-b.svg for example.

However, if you can avoid masking and clipping (e.g by just drawing things on top) that usually leads to better performance/user-experience.

Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
3

Easiest way is to use <path> with the hole, and set pointer-events to none so events can pass through to the <rect> under. Of course there are many other ways to handle events such as wrapping them with a <g> and handling events on it.

You don't need to limit yourself to the basic shapes and use complicated clipping. Make things felxible enough so you can copy&paste path data generated by tools like inkscape.

artificialidiot
  • 5,309
  • 29
  • 27