37

I have done a table in SVG, and I want to fill it with data dynamically. That means that I don't know how much space the text takes, and I want to clip or hide the overlapping text. How can I do that in SVG?

My HTML document with SVG looks like:

<!DOCTYPE html>
<html>
<body>
<svg>
<text x="100" y="100">Orange</text>     <text x="160" y="100">12</text>
<text x="100" y="115">Pear</text>       <text x="160" y="115">7</text>
<text x="100" y="130">Banana</text>     <text x="160" y="130">9</text>
<text x="100" y="145">Pomegranate</text><text x="160" y="145">2</text>

<line x1="157" y1="85" x2="157" y2="155" style="stroke:rgb(100,100,100)"/>
</svg>
</body>
</html>

And this will render to:

enter image description here

Is there any way I can clip the text i my SVG-"table"?


Implemented solution from Erik's answer:

<!DOCTYPE html>
<html>
<body>
<svg>
    <text x="10" y="20" clip-path="url(#clip1)">Orange</text>       
    <text x="10" y="35" clip-path="url(#clip1)">Pear</text>     
    <text x="10" y="50" clip-path="url(#clip1)">Banana</text>       
    <text x="10" y="65" clip-path="url(#clip1)">Pomegranate</text>

    <text x="70" y="20">12</text>
    <text x="70" y="35">7</text>
    <text x="70" y="50">9</text>
    <text x="70" y="65">2</text>

    <line x1="67" y1="5" x2="67" y2="75" style="stroke:rgb(100,100,100)"/>

    <clipPath id="clip1">
        <rect x="5" y="5" width="57" height="90"/>
    </clipPath>
</svg>
</body>
</html>

enter image description here

Jonas
  • 121,568
  • 97
  • 310
  • 388
  • 1
    you can see in the image above it clips in the middle of the letter `a`. prefer textPath instead http://stackoverflow.com/a/9249966/592792 – André Werlang Apr 11 '17 at 21:39

5 Answers5

41

You can use clip-path to clip to whatever shape you want, see e.g masking-path-01 from the svg testsuite.

Relevant parts, defining the clip path:

<clipPath id="clip1">
  <rect x="200" y="10" width="60" height="100"/>
  ... you can have any shapes you want here ...
</clipPath>

and then apply the clip path like this:

<g clip-path="url(#clip1)">
  ... your text elements here ...
</g>
Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • 9
    is there a way to do this inline? Like having all information directly in the clip-path attribute? – Matthias Mar 12 '13 at 14:01
  • @Matthias it might be possible to use a data URI, but that would be rather ugly, and I'm not certain that that's supported in all browsers. In the future however, it may become possible to use some simple shapes directly in the `clip-path` property, see https://dvcs.w3.org/hg/FXTF/raw-file/default/masking/index.html#the-clip-path. – Erik Dahlström Mar 12 '13 at 15:15
  • thank you for your response. I am interested in this ugly data-uri approach ;) Could you give me an example? – Matthias Mar 12 '13 at 18:35
  • as I suspected, here's an example: http://xn--dahlstrm-t4a.net/svg/clippath/clip-data-uri.svg – Erik Dahlström Mar 13 '13 at 14:39
  • this can clip in the middle of a letter. for text, prefer textPath http://stackoverflow.com/a/9249966/592792 – André Werlang Apr 11 '17 at 21:38
  • 1
    @Matthias nowadays you'd just use CSS's `clip-path: polygon(...)` – caub May 09 '18 at 09:05
8

If for some reason you don't want to use clipping, you can also use a nested SVG tag:

<svg>
  <svg x="10" y="10" width="10" height="10">
    <text x="0" y="0">Your text</text>
  </svg>
</svg>

This way, your text will be cut off when it's outside the nested SVG viewport. Note that the x and y of the text tag refer to the coordinate system of the nested SVG, and correspond to 10 in the coordinate system of the outer SVG.

xaviert
  • 5,653
  • 6
  • 29
  • 31
Alexander Jank
  • 2,440
  • 2
  • 18
  • 19
3

As Marcin said in point (2) of his answer (unfortunately downvoted but actually this is a good point) an alternative way to achieve the effect is to overpaint the part not wanted with a white rectangle.

<!DOCTYPE html>
<html>
<body>
<svg>
<text x="100" y="100">Orange</text>     
<text x="100" y="115">Pear</text>       
<text x="100" y="130">Banana</text>     
<text x="100" y="145">Pomegranate</text>

<!-- Overpaint the overflowing text -->
<rect x="155" y="85" width="100" height="100" fill="white" />

<line x1="157" y1="85" x2="157" y2="155" style="stroke:rgb(100,100,100)"/>

<text x="160" y="100">12</text>
<text x="160" y="115">7</text>
<text x="160" y="130">9</text>
<text x="160" y="145">2</text>

</svg>
</body>
</html>

svg overlay sample

Reference to the SVG specification: SVG 2.0 Rendering Order

Edward
  • 8,028
  • 2
  • 36
  • 43
1

If you don't want to use a clip-path, which can be a pain if each element has a different size, then you can also use nested <svg> elements for clipping. Just make sure the svg elements have the CSS style overflow:hidden.

<!DOCTYPE html>
<html>
<body>
<svg>
    <svg width="57" height="15" x="10" y="5"><text y="15">Orange</text></svg>       
    <svg width="57" height="15" x="10" y="20"><text y="15">Pear</text></svg>
    <svg width="57" height="15" x="10" y="35"><text y="15">Banana</text></svg>   
    <svg width="57" height="15" x="10" y="50"><text y="15">Pomegranate</text></svg>

    <text x="70" y="20">12</text>
    <text x="70" y="35">7</text>
    <text x="70" y="50">9</text>
    <text x="70" y="65">2</text>

    <line x1="67" y1="5" x2="67" y2="75" style="stroke:rgb(100,100,100)"/>
</svg>
</body>
</html>
drarmstr
  • 680
  • 1
  • 8
  • 16
1

(1) There is no reason to use SVG for tables. Use HTML tables.

(2) By "clipping" I understand you to mean that the excess text will be obscured. SVG uses a "painter's model" whereby elements specified later in the document are drawn above elements specified earlier. This will allow you to clip regions.

(3) If you really needed to do this in an SVG document you could use a foreign object, and embed HTML.

Marcin
  • 48,559
  • 18
  • 128
  • 201
  • 1
    The HTML is just a preview, I will render my SVG in a Java Swing desktop application too, so I can not use HTML. – Jonas Jul 14 '11 at 10:30
  • Jonas, are you sure that Swing won't render embedded HTML? In any case, I believe I have answered your question regarding clipping. – Marcin Jul 14 '11 at 10:33
  • Swing has very limited support for HTML e.g. no rounded corners on tables. I can't get `foreignObject` working in IE9. I will try more about clipping regions, but so fat no luck. Do you have any example code? – Jonas Jul 14 '11 at 11:08
  • You don't need clipping regions. Put the items you want to be clipped at the start of your document. If you really want, you can use a rectangle to clip them. – Marcin Jul 14 '11 at 11:13
  • 1
    @Jacek Thanks. I can only imagine that it's ignorance of how SVG works. – Marcin May 08 '14 at 13:45
  • 1
    Agreed. The community here is somehow strange. Sometimes helpful, sometimes mindless. It's a lottery ;). Best regards! – Jacek Kowalewski May 08 '14 at 21:07