How to get rid of space before the first glyph in a SVG <text> element? - svg

As you can see, the <text> element has the xattribute set to 0mm, yet there is a gap between the first glyph (H) and the edge of the document.
I don't know what this is caused by, but if I select just the first glyph:
The box does extend to x=0, as well as slightly beyond it - which makes me think that this is a limitation of (SVG's model of) variable-width text layout perhaps?
In either case, Inkscape does show the discrepancy in the positioning - it shows the text's X coordinate at 0.635mm:
Which, on the other hand, makes me think that it is possible to determine somehow.
Of course, if all that was needed was just to align the text, I could enter 0 in the dialog, but I am generating the SVG programatically, so I either need a way to say "align the first glyph at the very edge of the <text> box" or to calculate the gap (so it can be put in the dx attribute).
A minimal test-case which illustrates this is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<svg baseProfile="full" height="150mm" version="1.1" width="150mm" xmlns="http://www.w3.org/2000/svg"
xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs/>
<text x="0mm" y="75mm">Hello</text>
</svg>

Related

Why are the SVG Text elements too high?

I noticed the the root coordinates for a text element are not at the top left corner like a rect element:
Is there a way to set it such that when a text element is at (0,0), it fits inside the parent element?
If I understood you well, you can use this:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dominant-baseline
A) Chromium browsers
svg {
dominant-baseline: hanging;
}
https://jsfiddle.net/e7vc4bqj/
B) Chromium and Firefox
.text {
dominant-baseline: hanging;
}
https://jsfiddle.net/3zskd148/
SVG text coordinates are used to define its left bottom corner by default:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor
Hope this help :)
Why are the SVG Text elements too high?
The x and y coordinates of a <text> element specify the start of the baseline of the text. This makes complete sense. You wouldn't want it to be the top left of the first character - because it would then be a difficult job to get text of different sizes and styles to line up.
There is no global option in SVG that changes that behaviour. However see below for alternatives)
Is there a way to set it such that when a text element is at (0,0), it fits inside the parent element?
Normally you would just adjust the y coordinate based on the font size.
However there are a couple of alternatives you can use:
One is the xxx-baseline properties (as #gengns has pointed out), that can alter how the character glyphs are positioned relative to the baseline. Note however, that those attributes are not entirely reliable, due to mixed browser support. Plus they depend on the font containing the correct data tables. Not all fonts have those tables.
A better option IMO is to use the dy attribute. This adds a relative offset to the text position. Meaning the text is actually positioned at (x, y + dy). And it is supported by all browsers.
<svg width="200" height="150">
<rect x="0" y="0" width="200" height="150" fill="skyblue"/>
<text x="0" y="0"
font-size="25px" dy="1em">asd</text>
</svg>

SVG : line with y attribute expressed in percentage units does not get affected by viewBox

It seems that specifying line coordinates of an SVG line in percentages makes that coordinate exist in viewport coordinate system instead of the user coordinate system established by a viewBox. To me that sounds strange, especially after reading the specs.
In the example below, the green line is defined by user space coordinates while the blue line's y coordinate is in percentage units (50%). When the button is clicked, the viewBox is applied - the green line is scaled properly while the blue line is not ... What is going on there?
The spec says:
For any y-coordinate value or height value expressed as a percentage of the SVG viewport, the value to use must be the percentage, in user units, of the height parameter of the ‘viewBox’ applied to that viewport. If no ‘viewBox’ is specified, then the value to use must be the percentage, in user units, of the height of the SVG viewport.
UPDATE: I grouped all elements in the svg and supplied transform="scale(0.5 0.5)" and the percentage coordinate worked as expected. I start suspecting that the viewBox only transforms coordinates specified in user units and not in explicit units. But I would think the percentage should not be considered as an explicit unit as it is not really physical value. And it would contradict the spec excerpt from above. So what is it ?
function myFunction(){
document.getElementById("maxi").setAttribute("viewBox","0,0,492,124");
}
<svg id="maxi" version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="246" height="62" font-size="23px" xml:space="preserve" >
<line id="greenline" x1="0" y1="31" x2="232" y2="31" stroke="#00FF00" stroke-width="4"/>
<line id="blueline" x1="0" y1="50%" x2="232" y2="50%" stroke="#0000FF"/>
<path class="cutContour" fill="none" stroke="#EC008C" stroke-miterlimit="3.8637" d="M6.8,2.3H225
c2.3,0,4.3,1.9,4.3,4.3v48.2c0,2.3-1.9,4.3-4.3,4.3H6.8c-2.3,0-4.3-1.9-4.3-4.3V6.6C2.5,4.2,4.4,2.3,6.8,2.3z"/>
</svg>
<input type="button" value="Click Me" onClick="myFunction();">
I'm not seeing anything unusual about the behaviour you're describing. See Codepen at https://codepen.io/MSCAU/pen/JapPQd.
The blue line is staying in the (vertical) centre of the SVG as its Y-coordinates are expressed as 50%. When the viewBox changes value, this is not affected. Only its X values are expressed in absolute terms so the line gets halved when the viewBox is made explicit.
The green line is getting displaced in X- and Y-axes when the button is clicked as the coordinate system is changing - in your example doubling - and its coordinates are expressed in absolute terms.
I changed the colours and stroke-widths to make it clearer what's going on. I've also commented out your PATH and put a (dotted) border round the SVG for clarity. I have also added a handy reset button:
function reset() {
document.getElementById("maxi").removeAttribute("viewBox");
}

Center a character in svg

I'm looking to produce a SVG file containing a single ascii character (say 'g' or 'W') from an arbitrary font centered within a 100 x 100 window. This is the closest I've got, but it's not quite right...
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<text x="50" y="50" font-size="100px"
text-anchor="middle" alignment-baseline="middle">g</text>
</svg>
SVG does not have automatic vertical layout capabilities on its own; you need something else to compute the height of the box, like JavaScript or…
Looks like you're embedding this inside of a web browser. If so, then you can use the automatic layout capabilities of HTML to do this for you, using <foreignObject> to embed an HTML snippet inside your SVG with display:table-cell; vertical-align:middle on the content.
There is no general way to centre text vertically in SVG.
The best you can to is work out where the baseline (<text> y attribute) should go for a particular font and group of characters (eg. all capitals).

Slanted text in SVG

In SVG is it possible to slant text to specified angle? This is of course different from rotate or putting on a path etc. One of things I want to do is to have a parallelogram with embedded text, with text tilted to the angle of the parallelogram.
Thank you.
Yes. You need to use the transform attribute.
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="100">
<text font-size="50" transform="translate(20,50) skewX(20)">Skewed text</text>
</svg>
Note that the transform applies to the text position (x and y attributes) as well. That's why I have used a translate to set the text position instead.

How can I make text automatically scale down in an SVG?

I've got an SVG element that I've created with Inkscape. I then take that SVG and put in as part of an XSL-FO stylesheet that is used to transform XML data and then passed through the IBEX renderer to create a pdf (which is usually then printed). As an example, I have elements in the svg/stylesheet that look like this (extra noise due to the Inkscape export):
<text x="114" x="278.36218" id="id1" xml:space="preserve" style="big-long-style-string-from-inkscape">
<tspan x="114" y="278.36218" id="id2" style="style-string">
<xsl:value-of select="Alias1"/>
</tspan>
</text>
My problem lies in the fact that I don't know how big this text area is going to be. For this particular one, I've got an image to the right of the text in the SVG. However, if this string is the maximum allowed number of W's, it's way too long and goes over the image. What I'd like (in a perfect world) is a way to tell it how many pixels wide I want the text block to be and then have it automatically make the text smaller until it fits in that area. If I can't do that, truncating the text would also work. As a last ditch resort, I'm going to use a fixed width font and do the string truncation myself in the XML generation, although that creates something both less usable and less pretty.
I've poked around the SVG documentation and looked into flowRegions a bit as well as paths, but neither seem to be be quite what I want (maybe they are though). If it helps, here's that style string that Inkscape generates:
"font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
Thanks in advance for the help.
You have text of arbitrary line length (in terms of characters) and you want to scale it to fit inside a fixed amount of space? The only way I can think of to rescale text to a fixed size is to place it inside an svg element and then scale the SVG to that size:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Resizing Text</title>
<defs>
<svg id="text-1" viewBox="0 0 350 20">
<text id="text-2" x="0" y="0" fill="#000" alignment-baseline="before-edge">It's the end of the world as we know it, and I feel fine!</text>
</svg>
</defs>
<rect x="500" y="100" width="200" height="40" fill="#eee" />
<use x="510" y="110" width="180" height="20" xlink:href="#text-1" />
</svg>
However, as seen above, the viewBox on the encapsulating svg element needs to be set to the width of the text, which you presumably don't know.
If you're referencing this SVG inside a user agent with scripting available (e.g. a web browser) then you could easily write a script to capture the width of the text or tspan element and set the viewBox accordingly.

Resources