llimllib
llimllib

Reputation: 3702

Clipping transformed text in an SVG

I've created a radial plot with d3, and I want to clip text that's on top of a path. However, to get the text above the path, it needs to be translated and rotated.

the effect I'm trying for

The first image in this codepen shows the a path with text that's been rotated and translated overlaid; what I want is to clip the text to the path below it.

The second image shows what happens when I do; the clipPath (which is just a link to the path on the svg) is subject to the same transform that's been applied to the text, so it gets tilted and shifted to the right instead of being in the same spot as the arc it refers to.

The third image shows what I want to happen. However, I achieved this by inverting the transform applied to the text, and applying it to the clipPath, like this:

   <clipPath id="clipfix" transform="translate(-30,0)rotate(-30)">

I can solve my problem by doing that, but it seems a bit ridiculous. In my actual drawing I have lots of paths, and lots of text. Is there a better way to clip my text to the path below it, or have I got the right answer and just need to accept the ugliness?

The full text of the demo SVG follows:

<svg width=1000 height=1000>
  <g transform="translate(20,200)">
    <path d="M0,-150A150,150 0 0,1 150,0L100,0A100,100 0 0,0 0,-100Z"
          style="fill: #ffffff; stroke: #000000;"></path>
    <path d="M150,0A150,150 0 0,1 0,150L0,100A100,100 0 0,0 100,0Z"
          style="fill: #ffffff; stroke: #000000;"></path>
    <text transform="rotate(30)translate(30,0)">The first thing to know about Schnauzers</text>
    <text transform="rotate(-45)translate(30,0)">I once met a cactus that could talk</text>
  </g>
  <g transform="translate(320,200)">
    <path d="M0,-150A150,150 0 0,1 150,0L100,0A100,100 0 0,0 0,-100Z"
          id="path3" style="fill: #ffffff; stroke: #000000;"></path>
    <path d="M150,0A150,150 0 0,1 0,150L0,100A100,100 0 0,0 100,0Z"
          id="path4" style="fill: #ffffff; stroke: #000000;"></path>
    <clipPath id="clip">
      <use xlink:href="#path3"></use>
      <use xlink:href="#path4"></use>
    </clipPath>
    <text transform="rotate(30)translate(30,0)"
          clip-path="url(#clip)">The first thing to know about Schnauzers</text>
    <text transform="rotate(-45)translate(30,0)"
          clip-path="url(#clip)">I once met a cactus that could talk</text>
  </g>
  <g transform="translate(550,200)">
    <path d="M0,-150A150,150 0 0,1 150,0L100,0A100,100 0 0,0 0,-100Z"
          id="path5" style="fill: #ffffff; stroke: #000000;"></path>
    <path d="M150,0A150,150 0 0,1 0,150L0,100A100,100 0 0,0 100,0Z"
          id="path6" style="fill: #ffffff; stroke: #000000;"></path>
    <clipPath id="clipfix" transform="translate(-30,0)rotate(-30)">
      <use xlink:href="#path5"></use>
      <use xlink:href="#path6"></use>
    </clipPath>
    <text transform="rotate(30)translate(30,0)"
          clip-path="url(#clipfix)">The first thing to know about Schnauzers</text>
    <text transform="rotate(-45)translate(30,0)"
          clip-path="url(#clipfix)">I once met a cactus that could talk</text>
  </g>
</svg>

Upvotes: 4

Views: 722

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101820

Just wrap your text elements in a group and apply the clip to that.

  <g transform="translate(320,200)">
    <path d="M0,-150A150,150 0 0,1 150,0L100,0A100,100 0 0,0 0,-100Z"
          id="path3" style="fill: #ffffff; stroke: #000000;"></path>
    <path d="M150,0A150,150 0 0,1 0,150L0,100A100,100 0 0,0 100,0Z"
          id="path4" style="fill: #ffffff; stroke: #000000;"></path>
    <clipPath id="clip">
      <use xlink:href="#path3"></use>
      <use xlink:href="#path4"></use>
    </clipPath>
    <g clip-path="url(#clip)">
      <text transform="rotate(30)translate(30,0)"
            >The first thing to know about Schnauzers</text>
      <text transform="rotate(-45)translate(30,0)"
            >I once met a cactus that could talk</text>
    </g>
  </g>

Upvotes: 5

Related Questions