SVG text element not positioning correctly - svg

I've set up a minimalist example of what I have here. I need to position the text element at the very top of the SVG. However if you inspect the text element, you'll see that it actually starts somewhere outside the SVG (like -3px on Chrome, -4px on FF) -- see below screenshot. I'm building something which needs to be pixel-perfect, so I need to get the text to start exactly where the SVG starts. As you can see, the rect starts where it's supposed to.
Since SO won't let me post links to jsfiddle without code inside the post, here's the code:
<svg width="100%" height="360" style="background-color: rgb(0, 249, 253);margin-top: 50px;">
<rect y1="0" y2="100" x="0" width="100" height="100"></rect>
<text x="100" y="0" dominant-baseline="hanging">2022</text>
</svg>
Any idea why this is happening?

According to the SVG specification, a dominant baseline of hanging is only meaningful for Indic scripts like Devanagari. If you want the top edge of the text box to align with a particular Y coordinate, then use text-before-edge instead:
<svg width="300" height="55" viewBox="0 0 300 55">
<rect x="20" y="5" width="30" height="30" fill="#f00"/>
<text x="50" y="5" dominant-baseline="hanging">8888</text>
<text x="35" y="50" text-anchor="middle">hanging</text>
<rect x="220" y="5" width="30" height="30" fill="#f00"/>
<text x="250" y="5" dominant-baseline="text-before-edge">8888</text>
<text x="235" y="50" text-anchor="middle">text-before-edge</text>
</svg>

Related

Add inline labels to a horizontal bar with pure SVG

I use the bellow SVG code to build a horizontal bar chart. It is OK, but I need also two inline labels before and after the chart. I know how to add them with HTML and CSS, but I want to solve this only with pure SVG. How to do this?
<svg class="chart" width="300px" height="40">
<g transform="translate(0,0)">
<rect width="82%" height="22" fill="lightskyblue"></rect>
<rect width="100%" height="22" style="fill:none; stroke-width:1; stroke:gray;"></rect>
<text y="30" dx="0.25em" dy=".35em">0</text>
<text x="20%" y="10" dy=".35em" fill="red">|</text>
<text x="20%" y="30" dx="-0.25em" dy=".35em" fill="red">13</text>
<text x="100%" y="30" dx="-1.25em" dy=".35em">63</text>
</g>
</svg>
This is what I have now:
And this is what I want:
In order to make it work I'm using your code as a nested svg inside a larger svg element. Please observe I'm using a viewBox attribute where the x component has a negative value (-50) making space for the text.
svg{border:solid;}
<svg class="chart" width="300px" viewBox="-50 0 400 40">
<text y="20" x="-45">TXT</text>
<text x="345" y="20" text-anchor="end">TXT</text>
<svg viewBox="0 0 300 40" width="300">
<rect width="82%" height="22" fill="lightskyblue"></rect>
<rect width="100%" height="22" style="fill:none; stroke-width:1; stroke:gray;"></rect>
<text y="30" dx="0.25em" dy=".35em">0</text>
<text x="20%" y="10" dy=".35em" fill="red">|</text>
<text x="20%" y="30" dx="-0.25em" dy=".35em" fill="red">13</text>
<text x="100%" y="30" dx="-1.25em" dy=".35em">63</text>
</svg>
</svg>
I must tell you that I wouldn't percentages for the position and size of the rects. I would have done it using user units (without unit identifier) and I wouldn't have needed to wrap it in another svg element.
UPDATE
the OP is commenting
Can you give another example, without percentages for the position and size of the rects and without wrapping it in another svg element
svg{border:solid}
<svg class="chart" width="300px" viewBox="-50 0 400 40">
<text y="20" x="-45">TXT</text>
<text x="345" y="20" text-anchor="end">TXT</text>
<rect width="246" height="22" fill="lightskyblue"></rect>
<rect width="300" height="22" style="fill:none; stroke-width:1; stroke:gray;"></rect>
<text y="30" dx="0.25em" dy=".35em">0</text>
<text x="60" y="10" dy=".35em" fill="red">|</text>
<text x="60" y="30" dx="-0.25em" dy=".35em" fill="red">13</text>
<text x="300" y="30" dx="-1.25em" dy=".35em">63</text>
<svg>

How to make SVG black bar with centered text responsive?

I'm trying to make an SVG element fit to the bottom of the page with "Loading..." text centered regardless of the container's width. This is my current code which isn't working as the message is always in a fixed position.
<svg id="svg-bottom" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="bottom">
<rect height="40" width="100%" y="0" x="0" fill="#000000" fill-opacity="0.676460598" id="panel"></rect>
<text id="status" font-family="GothamRounded-Medium, Gotham Rounded" font-size="20" font-weight="400" fill="#FFFFFF">
<tspan x="190.97" y="16">Loading…</tspan>
</text>
</g>
I solved the above with the following:
<text font-family="GothamRounded-Medium, Gotham Rounded" font-size="20" font-weight="400" fill="#FFFFFF" x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">Loading…</text>

SVG how to set max width for group

I have some SVG elements grouped together in a <g> element (exactly the barcode 1D, PHP generates a barcode).
<g
style="fill:#000000;stroke:none"
id="barcode1D"
transform="matrix(1.2083333,0,0,0.8247805,62.027778,573.54235)">
<rect
x="0"
y="0"
width="4"
height="30"
id="xyz" />
....
<rect
x="224"
y="0"
width="0"
height="30"
id="xyzn" /> </g>
The barcode is generated in various widths, lengths. How can I set the width permanently ?
Based on this example, I am asking for a hint. Thank you for your help in advance.
SVG g element does not have width and height attributes. Therefore, you can not set height and width on it.
You should use a foreignObject with a svg inside of it to do so.
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
<foreignObject id="G" width="300" height="200">
<svg>
<!-- Barcode here -->
<rect fill="black" stroke-width="2" height="112" width="84" y="55" x="55" stroke="#000000"/>
<circle fill="#FF0000" stroke="#000000" stroke-width="5" cx="155" cy="65" id="svg_7" r="50"/>
</svg>
</foreignObject>
</svg>

svg mask and bounding box

I need to apply mask to a different objects.
Mask should cover whole object (visible part of it). I put the mask inside one specific place, at the top of the page, changed maskContentUnits to objectBoundingBox, so it worked perfectly.
But then a problem appeared.
I made a fiddle to illustrate the problem: http://jsfiddle.net/8qdt7vjr/1/
<body>
<svg width="0" height="0">
<defs>
<mask id="mask1" maskContentUnits="objectBoundingBox">
<ellipse cx=".5" cy=".5" rx=".5" ry=".5" fill="white" />
</mask>
</defs>
</svg>
<svg class="svg" width="200" height="150" overflow="visible">
<rect x="-50" y="-50" width="350" height="250" fill="none" stroke="green" stroke-width="2" />
<svg id="zzz" x="0" y="0" width="100%" height="100%" overflow="visible" mask="url(#mask1)">
<rect x="-50" y="-50" width="350" height="250" fill="blue" fill-opacity=".3" />
</svg>
<rect width="100%" height="100%" fill="red" fill-opacity=".1" stroke="red" stroke-width="1" />
</svg>
</body>
In this fiddle i want to apply mask to svg element with id="zzz". But inside this element there is a rect element, that increases zzz's bounding box. In the fiddle it is rect, but in my project it is an image tag. zzz has overflow set to hidden (in the fiddle I changed it to visible, so it is easier to see the problem), so I have a specific portion of image visible inside zzz.
The real problem is that zzz's inner content increases zzz's bounding box.
In the fiddle I want ellipse mask to be inside red rectangle (visible zzz's area), but it is inside green rectangle (zzz's bounding box) instead.
So the main question is: is there any way to achieve this goal? Mask will be used by many elements with different sizes and content and I do not want to clone it.
Is there any way to do this without cloning mask inside each element?
Is there any way to reduce bounding box to visible area?
Is there any way to show a part of an image without expanding parent's bounding box?
Is there any other way to do this?
Is it something like this you try to achieve?
<body>
<svg width="0" height="0">
<defs>
<mask id="mask1" maskContentUnits="userSpaceOnUse">
<ellipse cx="100" cy="75" rx="100" ry="75" fill="white" />
</mask>
</defs>
</svg>
<svg class="svg" width="200" height="150" overflow="visible">
<rect x="-50" y="-50" width="350" height="250" fill="none" stroke="green" stroke-width="2" />
<svg id="zzz" x="0" y="0" width="100%" height="100%" overflow="visible" mask="url(#mask1)">
<rect x="-50" y="-50" width="350" height="250" fill="blue" fill-opacity=".3" />
</svg>
<rect width="100%" height="100%" fill="red" fill-opacity=".1" stroke="red" stroke-width="1" />
</svg>
</body>
Maybe using userSpaceOnUse instead of objectBoundingBox can help achieve what you want... In combination with nested svg elements you can define the userspace to use and with that the part the mask is applied to...

Cut off half of the SVG's text element

How can I make this
to look like this
So I want to halve the text element. I don't want to hide half of the text outside of SVG. Hiding it outside of g would be ok, but haven't found solution.
<svg width="500" height="500">
<g transform="translate(50,50)">
<rect width="80" height="50" style="fill:rgb(0,0,255);"/>
<text font-size="40" x="0" y="15" fill="black">SVG</text>
</g>
</svg>
JSFIDDLE:
http://jsfiddle.net/64nkLcdy/
Use the clip-path property :
<svg width="500" height="500">
<defs>
<clipPath id="myClip">
<rect width="80" height="50" />
</clipPath>
</defs>
<g transform="translate(50,50)">
<rect width="80" height="50" style="fill:rgb(0,0,255);" />
<text font-size="40" x="0" y="15" fill="black" clip-path="url(#myClip)">SVG</text>
</g>
</svg>
Use an <svg> element rather than a <g> as the svg element will clip its contents by default. The overflow property controls clipping i.e overflow="visible" doesn't clip but overflow="hidden" does.
<svg width="500" height="500">
<svg transform="translate(50,50)" width="80" height="50" overflow="hidden">
<rect width="80" height="50" style="fill:rgb(0,0,255);"/>
<text font-size="40" x="0" y="15" fill="black">SVG</text>
</svg>
</svg>

Resources