I have a bar chart I've created using D3. I've left out the JS code because the issue has to do with html and css not D3.
Run the snippet below. There are 3 sections (g elements) each with a label and 3 bars (with some text inside). The first g element seems to be rendering outside the svg, cutting off the label text, and I cannot figure out why.
Things I've already tried (that don't work):
Position relative on the svg and g elements.
overflow: visible (would be more of a hack than a solution)
wrapping the svg in a clearfix div
I would prefer a solution, opposed to a hack like translate the g elements down by 20 each...
#chart{ width:100%;}
#chart rect {
fill: steelblue;
}
#chart text.value {
fill: white;
font-size: 10px;
text-anchor: end;
}
#chart text.value2 {
fill: white;
font-size: 12px;
}
#chart text.label {
fill: black;
font-size: 20px;
}
<svg id="chart" width="908" height="375">
<g transform="translate(0,0)">
<text class="label" x="0" y="0">test 1</text>
<rect x="0" y="10" width="314.3076923076923" height="25"></rect>
<text class="value" x="309.3076923076923" y="22.5" dy=".35em">25</text>
<text class="value2" x="10" y="22.5" dy=".35em">a</text>
<rect x="0" y="38" width="440.03076923076924" height="25"></rect>
<text class="value" x="435.03076923076924" y="50.5" dy=".35em">35</text>
<text class="value2" x="10" y="50.5" dy=".35em">b</text>
<rect x="0" y="66" width="326.88000000000005" height="25"></rect>
<text class="value" x="321.88000000000005" y="78.5" dy=".35em">26</text>
<text class="value2" x="10" y="78.5" dy=".35em">c</text>
</g>
<g transform="translate(0,119)">
<text class="label" x="0" y="0">test 2</text>
<rect x="0" y="10" width="377.1692307692308" height="25"></rect>
<text class="value" x="372.1692307692308" y="22.5" dy=".35em">30</text>
<text class="value2" x="10" y="22.5" dy=".35em">a</text>
<rect x="0" y="38" width="502.8923076923077" height="25"></rect>
<text class="value" x="497.8923076923077" y="50.5" dy=".35em">40</text>
<text class="value2" x="10" y="50.5" dy=".35em">b</text>
<rect x="0" y="66" width="628.6153846153846" height="25"></rect>
<text class="value" x="623.6153846153846" y="78.5" dy=".35em">50</text>
<text class="value2" x="10" y="78.5" dy=".35em">c</text>
</g>
<g transform="translate(0,238)">
<text class="label" x="0" y="0">test 3</text>
<rect x="0" y="10" width="565.7538461538462" height="25"></rect>
<text class="value" x="560.7538461538462" y="22.5" dy=".35em">45</text>
<text class="value2" x="10" y="22.5" dy=".35em">a</text>
<rect x="0" y="38" width="817.2" height="25"></rect>
<text class="value" x="812.2" y="50.5" dy=".35em">65</text>
<text class="value2" x="10" y="50.5" dy=".35em">b</text>
<rect x="0" y="66" width="477.7476923076924" height="25"></rect>
<text class="value" x="472.7476923076924" y="78.5" dy=".35em">38</text>
<text class="value2" x="10" y="78.5" dy=".35em">c</text>
</g>
</svg>
The text.label elements "baseline" is, by default, at the bottom edge of the text. Meaning, when you render text at (0,0), the text is rendered from the bottom left corner.
To fix your issue, you can add dominant-baseline: hanging; to the text.label rule in your CSS, and adjust the bars down by the height of the text.
Related
Please check my code link
<div class="suj_content">
<header class="suj_content_hd">
<div id="suj_content_hd_ytb"><iframe class="suj_content_hd_ytb" src="https://www.youtube.com/embed/kOc6ME2J_Us?mute=1&loop=1&playlist=kOc6ME2J_Us&autoplay=1&showinfo=0&controls=0" width="100%" height="100%" frameborder="0"></iframe></div>
<h2>
<svg id="suj_content_svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100% 100%" preserveAspectRatio="xMidYMid slice">
<defs>
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%"></rect>
<text>
<tspan x="0" dy="33.333333333333%" alignment-baseline="middle" text-anchor="start">mittel</tspan><tspan x="0" dy="23.222222222222%" alignment-baseline="middle" text-anchor="start">stand</tspan><tspan x="0" dy="23.222222222222%" alignment-baseline="middle" text-anchor="start">digital</tspan> </text>
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%"></rect>
</svg>
</h2>
</header>
How can I set the width and height of SVG tag to fit its content (the tspan tags). The number of tspan tags is not fixed.
Thanks
First: you are using an invalid viewBox attribute. No percentages are allowed. The value of the viewBox is fromX fromY width height.
I am using a viewBox where the width is 41 - the width of the bounding box of the text.
Second: I suspect you intend to cut the text from the last rect. In this case you need the text to be white.
console.log(t.getBBox())
text{font-size:16px;}
<svg id="suj_content_svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 41 50" preserveAspectRatio="xMidYMid slice">
<defs>
<mask id="mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%"></rect>
<text fill="white" id="t">
<tspan x="0" dy="25%" dominant-baseline="middle" text-anchor="start">mittel</tspan>
<tspan x="0" dy="25%" dominant-baseline="middle" text-anchor="start">stand</tspan>
<tspan x="0" dy="25%" dominant-baseline="middle" text-anchor="start">digital</tspan>
</text>
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%" mask="url(#mask)"></rect>
</svg>
I am using svg to display text at specific position, But the text at end of the svg container is cropped.
How to display that text.
I am using the following code
<svg width="100" style="background:yellow">
<text x="0" y="100" stroke="red" text-anchor="middle">0</text>
<text x="20" y="100" stroke="red" text-anchor="middle">20</text>
<text x="40" y="100" stroke="red" text-anchor="middle">40</text>
<text x="60" y="100" stroke="red" text-anchor="middle">60</text>
<text x="80" y="100" stroke="red" text-anchor="middle">80</text>
<text x="100" y="100" stroke="red" text-anchor="middle">100</text>
</svg>
I want to display 0 and 100 completely and don't want to change the svg container width
In order not to change the size of the numbers and see all of them, you need to add a viewBox and increase the width
<svg width="130" viewBox="-10 0 130 130" style="background:yellow">
<text x="0" y="100" stroke="red" text-anchor="middle">0</text>
<text x="20" y="100" stroke="red" text-anchor="middle">20</text>
<text x="40" y="100" stroke="red" text-anchor="middle">40</text>
<text x="60" y="100" stroke="red" text-anchor="middle">60</text>
<text x="80" y="100" stroke="red" text-anchor="middle">80</text>
<text x="100" y="100" stroke="red" text-anchor="middle">100</text>
</svg>
I'm trying to put some text as labels inside some scaled elements, and the text is too big to fit in the container. What can I do here?
<div class="t_container">
<div class="t_x" style="position: relative;">
<svg position="absolute" viewBox="0 0 6 1" preserveAspectRatio="none">
<g>
<rect x="0" y="0" width="1" height="0.4"><title>Nov-21</title></rect>
<text x="0.5" y="0.5" fill="red">A<text>
</g>
<rect x="1" y="0" width="1" height="1"><title>Nov-22</title></rect>
<rect x="2" y="0" width="1" height="1"><title>Nov-23</title></rect>
<rect x="3" y="0" width="1" height="1"><title>Nov-24</title></rect>
<rect x="4" y="0" width="1" height="1"><title>Nov-25</title></rect>
<rect x="5" y="0" width="1" height="1"><title>Nov-26</title></rect></svg>
</div>
Here is a codepen with the result.
You have a very small custom viewport="0 0 6 1" size. 6px - width, 1px - height, so the font can not be displayed with such parameters.
I increased the size of the viewBox 100 times viewBox="0 0 600 100"
Squares for clarity painted in different colors. You can change their coloring according to your choice.
The text is placed inside the squares. I hope that's exactly what you wanted when you used the command
<title> Nov-24 </ title> inside the squares.
But the command <title> in SVG is a system tooltip, the information from which appears when you hover the cursor.
The size of the tooltip and its font can not be changed, so I added in the squares more tags <text> ... </ text>, the parameters of which you can change.
<div class="t_container">
<div class="t_x" style="position: relative;">
<svg position="absolute" viewBox="0 0 600 100" >
<g>
<rect x="0" y="0" width="100" height="40"><title>Nov-21</title></rect>
<text x="35" y="75" font-size="36" fill="red">A</text>
</g>
<rect x="100" y="0" width="100" height="100" fill="orange">
<title>Nov-22</title></rect>
<text x="125" y="55" font-size="18" fill="white">Nov-22</text>
<rect x="200" y="0" width="100" height="100" fill="orangered">
<title>Nov-23</title></rect>
<text x="225" y="55" font-size="18" fill="white">Nov-23</text>
<rect x="300" y="0" width="100" height="100" fill="green">
<title>Nov-24</title></rect>
<text x="325" y="55" font-size="18" fill="white">Nov-24</text>
<rect x="400" y="0" width="100" height="100" fill="dodgerblue">
<title>Nov-25</title></rect>
<text x="425" y="55" font-size="18" fill="white">Nov-25</text>
<rect x="500" y="0" width="100" height="100" fill="yellowgreen">
<title>Nov-26</title></rect>
<text x="525" y="55" font-size="18" fill="white">Nov-26</text>
</svg>
</div>
I wanted to position text in the bottom left of an SVG element, and managed to achieve that using groups and transforms, but noticed that it won't update if i resize my window vertically, and also it won't apply on page load, but if i add the transform properties through developer console. they work perfectly, until i resize the window.
Is it some kind of a bug or i am doing something wrong? Is there another way to position text inside SVG element relative to bottom left and keep it responsive to window resize? I am using chrome 61 by the way.
here's a link to jsfiddle too:
https://jsfiddle.net/eow1c4o4/
*,*:before,*:after {
box-sizing: border-box;
}
body, html {
padding: 0;
margin: 0;
height: 300vh
}
tspan {
font-weight: 900;
font-size: 50px;
dominant-baseline: hanging;
}
<svg width="100%" height="100vh">
<defs>
<mask id="mask" maskUnits="userSpaceOnUse">
<rect width="100%" height="100%" fill="white"/>
<g style="transform: translate(0, 100%);">
<rect x="0" y="0" width="100%" height="100%" fill="white"></rect>
<g style="transform: translate(50px, -100%);">
<text x="0" y="0" text-anchor="start" font-family="Roboto">
<tspan x="0" dy="0">SOME</tspan>
<tspan x="0" dy="0.81em">ABSOLUTELY</tspan>
<tspan x="0" dy="0.81em">RANDOM TEXT</tspan>
</text>
</g>
</g>
</mask>
</defs>
<rect width="100%" height="100%" fill="#dedede" fill-rule="evenodd" mask="url(#mask)"></rect>
</svg>
Transforms in SVGs don't allow percentages. But geometric attributes do allow them. So the simplest way to do this is with a <use> element.
*,*:before,*:after {
box-sizing: border-box;
}
body, html {
padding: 0;
margin: 0;
height: 300vh
}
tspan {
font-weight: 900;
font-size: 50px;
}
<svg width="100%" height="100vh">
<defs>
<text id="mytext" x="0" y="-80" text-anchor="start" font-family="Roboto">
<tspan x="0" dy="0">SOME</tspan>
<tspan x="0" dy="0.81em">ABSOLUTELY</tspan>
<tspan x="0" dy="0.81em">RANDOM TEXT</tspan>
</text>
<mask id="mask" maskUnits="userSpaceOnUse">
<rect width="100%" height="100%" fill="white"/>
<use xlink:href="#mytext" x="5%" y="95%" fill="black"/>
</mask>
</defs>
<rect width="100%" height="100%" fill="#dedede" fill-rule="evenodd" mask="url(#mask)"></rect>
</svg>
The way we get the text to sit at the bottom, is to initially position it just off the top of the screen. Then we use a <use> element to reposition it at y="95%". That's just a little less than 100% so it ends up just above the bottom.
https://jsfiddle.net/eow1c4o4/1/
This might be fairly simple question but unable to find the answer. I want to line break g element tags inside svg element.
CSS
.container { position: reletive; width: 200px; background: #ccc; }
.container g { display: inline-block; display: inline; }
HTML
<div class="container">
<svg>
<g transform="translate(0, 0)">
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Canada</text>
</g>
<g transform="translate(100, 0)">
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Germany</text>
</g>
<g transform="translate(200, 0)">
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Norway</text>
</g>
<g transform="translate(300, 0)">
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Russia</text>
</g>
<g transform="translate(400, 0)">
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">USA</text>
</g>
</svg>
</div>
Here is the JSFiddle Link
SVG doesn't have a layout model like HTML, each element is painted on top of the previous elements and doesn't affect positioning of other elements.
You could use separate <svg /> elements so the HTML layout model can take control of positioning / wrapping the elements:
.container { width: 200px; background: #ccc; }
.container svg { width:100px; margin:0; display: inline-block; }
<div class="container">
<svg>
<g>
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Canada</text>
</g>
</svg><svg>
<g>
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Germany</text>
</g>
</svg><svg>
<g>
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Norway</text>
</g>
</svg><svg>
<g>
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">Russia</text>
</g>
</svg><svg>
<g>
<rect width="18" height="18"></rect>
<text x="24" y="9" dy=".35em">USA</text>
</g>
</svg>
</div>