Background color of tspan element - css

Is it possible to give SVG <tspan> element background color? If not, what would be the best way to simulate it?
My goal is to give text background color, and I figured that filling <tspan> elements would be perfect — they already "outline" text chunks (<tspan> elements) that represent lines in multiline text.
The example I'm working with:
<text x="100" y="100" font-size="30">
<tspan>hello</tspan>
<tspan x="100" dy="1.2em">world</tspan>
</text>
I tried "fill" attribute but it seems to affect fill (color) of text, not the area behind it:
<tspan fill="yellow">hello</tspan>
I also tried setting background-color via CSS:
<style type="text/css">tspan { background-color: yellow }</tspan>
..but that doesn't work (in at least Chrome 17 and Firefox 12).
Wrapping tspan in <g> (or text itself in <g>) with "fill" doesn't work either:
<g fill="yellow"><tspan>hello</tspan></g>
<tspan><g fill="yellow">hello</g></tspan>
Aside from creating a <rect> element positioned at the same location — something I'd like to avoid — is there another way to achieve this?

A rect is probably the best way to do that (assuming you are only dealing with the simplest forms of text).
The tspans have no "background" themselves in SVG 1.1, the background is whatever gets painted before the tspan. There are many cases to consider, such as the case where a tspan is inside a textPath that has the shape of a circle. Also note that it's not as simple as a continous rectangle in all cases, a single tspan can be skewed, rotated and partitioned into several intersecting and non-intersecting shapes due to transforms, glyph positioning, etc.
There's another way I can think of that would do this without scripting, but then you'd need to know the width of the string in advance (e.g by using a monospaced font). If you have that then you can add another tspan element using the Ahem font, placing it before the other tspan in the document and giving it the same x,y position as the tspan you want to give a "background".
Otherwise the way to do this is through scripting, and adding rectangles (or tspans with an Ahem-like font).

SVG does not support directly specifying an image background color...but you can adjust the four values of the viewBox attribute (complicated). I know it's something you want to avoid, but CSS wouldn't help you.
...or you can use getBBox and getCTM...it would give you advantages for rotated text.
EXAMPLE:
http://srufaculty.sru.edu/david.dailey/svg/getCTM.svg

Related

How to prevent inconsistent thickness and gaps in SVG lines?

My use case is probably a bit unique, but I am creating a dynamically-sized square grid using DOM elements encased in a flexbox. Each DOM element has an SVG image background and a height/width equal to calc(100vmin / <gridSize>). The SVG elements are simple:
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<path stroke-width="2" stroke="#000" stroke-linecap="square" d="M0,50 h100 M50,0 v50"/>
</svg>
However, I noticed that some lines appear darker than others, and there are gaps between some SVG lines. (See picture below) I'm assuming this is due to pixel rounding because when I resize the browser, the gaps and thicknesses jump around.
I tried to round the pixels from the calc, but I am using styled-components so I am unable to use SASS / LESS functions like floor / ceil. I also noticed making the stroke width thicker alleviates the problem, but I would prefer to keep my lines thin.
Are there other ways I can make the lines consistent?
It's antialiasing. Setting shape-rendering="crispEdges" will turn it off on most UAs.
vector-effect='non-scaling-stroke'
non-scaling-stroke
This value modifies the way an object is stroked. Normally stroking involves calculating stroke outline of the shapeʼs path in current user coordinate system and filling that outline with the stroke paint (color or gradient). The resulting visual effect of this value is that the stroke width is not dependent on the transformations of the element (including non-uniform scaling and shear transformations) and zoom level.
MDN web docs

Scaling <use>d external SVGs with correct aspect ratio

I want to use an (external) SVG icon and want to be able to style the fill color using CSS (as far as I can see, the best way to do this is creating a <svg><use xlink:href="…" /></svg> structure at every place where I want to use it). Simultaneously I want it to be scalable with correct aspect ratio, so it can be used around different text sizes.
But scaling with height:1.5em;width:auto AFAICS only works when the SVG has a viewBox. Is there a way to obtain that viewBox or do the scaling correctly without it?
If your SVG editor doesn't add a viewBox, there is no easy way to get it - other than working out the dimensions yourself and adding it manually.
Use your mouse coordinates readout in your editor, or
Use javascript and call getBBox() on an appropriate element, or
Use trial and error. Fiddle with the x, y, width, and height iteratively until you narrow in on the dimensions.

SVG: Need border on hover only on the rectangle and not the text within

I have a rectangle and some text within it. The entire rectangle and the text within it is clickable, and opens a new web page when clicked.
I need to use styling within my SVG document such that, when I move the mouse over the text or the rectangle, it should show a border around the rectangle. Because everything in the box is clickable, the <path> and <text> elements are within an <a> element. So, if a do something like this, I get a border around the path as well as the text.
<style type="text/css">
<![CDATA[
a:hover
{
stroke:#26a9e0
}
]]>
</style>
How can I get border just around the box, even when the mouse is moved over path or text?
Edit: This is an edit to the original question that was originally posted as an answer by the OP
Thanks for the response. Putting in more code here for clarity
<a aria-labeledby="itemTitle" cursor="pointer" xlink:href="http://some-link" target="_blank">
<path id="path3856" fill-rule="evenodd" fill="#26a9e0" d="m808.52,167.06,0,58.146,3.7936,0,0-58.146-3.7936,0z"/>
<path id="path3858" fill-rule="evenodd" fill="#FFF" d="m811.83,167.06,0,58.146,172.16,0,0-58.146-172.16,0z"/>
<text id="text3860" style="text-anchor:start;text-align:start;" font-weight="normal" xml:space="preserve" font-size="17.65748024px" font-style="normal" y="191.36598" x="822.92633" font-family="Segoe UI" fill="#000000">Some Text</text>
</a>
So, you can see that I have which includes and . The effect I need is to have a border around the box, which is denoted by in the code. The important thing is that border should show both on moving the mouse over the shape as well as text. So, if do what you suggested, i get the border on the rectangle only when the mouse is on the rectangle. If i move it over the text in the rectangle, the border goes away.
To fix this, if I do
a:hover
{
stroke:#26a9e0;
}
I see the border on the box as well as the text when I move the mouse over it.
This is a little tricky to explain, i know. I hope I am making myself clear.
It's hard to tell from your code, as it's incomplete (e.g. need to see the rectangle), but I suspect what you need is to use the rect element instead of the a element. Currently you're setting the stroke color when on an a, try this instead:
rect:hover
{
stroke:#26a9e0
}
Of course, it would be better to me more specific (this would affect all rectangles) so you'd want to make it a particular class (say glow) and use rect.glow instead of just rect.

How do I scale a group of text tags relative to the size of a page?

I've been messing with this for weeks, so I'm just gonna flat out ask how to do it.
I've been working on a little SVG countdown clock just for the hell of it. But when I try and position things relative to how the page might be sized, I get stuck. I can't seem to size text tags relative to the page, and I can't find a way to put them into a group for sizing.
I've tried putting them into symbol tags, and using viewBox, but I can't seem to get that to work either.
My intended goal is to have this working on any sized screen from monitors to smartphones. So I wanted to do something with a min, and max width/height, or something along those lines, and apply it to a combination of the number and it's associated label. So I would have one group for days with both the number of days(being changed by the script), and then the word "days" underneath it.
Here is what I'm working with if it helps:
http://jsfiddle.net/2P9qV/
Does anyone have any ideas? I've been stumped for weeks.
Ok, so I finally figured it out. Luckily, I was able to use multiple SVGs within an SVG to create content, and then display it using use tags.
So I had each set as part of it's own symbol in defs. From there, I used the viewBox on the symbol tag to limit the draw space to the exact width and height of the content created, which I found by inspecting the element, and using the height and width it had been made as(without the 'px'). This way, I could center the whole set in the SVG that had the use tag, then set the width of the SVG to 100%, and the height to the percentage I wanted to scale it to. Since these are set as percentages, the page will limit the SVG's size to whichever is most limiting, while still maintaining scale, so it won't skew.
So one of the symbols would be:
<symbol id="daysSymbol" viewBox="0 0 110 156">
<g>
<text id="days" y="0" x="50%" font-size="100" class="time big">00</text>
<text id="daysT" y="100" x="50%" font-size="40" class="text bigText">DAYS</text>
</g>
</symbol>
and the SVG for this would be
<svg id="daysSVG" height="50%" width="100%" y="30%">
<use xlink:href="#daysSymbol" height="100%"/>
</svg>
It also let me get creative with how I managed the contents on the page. As something happened, I was able to dynamically remove content, and scale other elements to take up the new space.
For those curious, here is the final product
https://hostr.co/file/PLCY7lodb7Lk/xboxCountdown.svg
It won't last for that long, since it was a countdown clock. But I won't take it down(as long as it doesn't get automatically deleted), and if you wanted to see how it worked, you cold just download it and change the date it counted down to.

SVG text disappears on larger label

I am using Morris.js for making charts. Morris.js uses SVG to draw the graphs. I have set up a JSbin here: JSbin example
Morris.js uses Raphael to draw the svg graphs. The issue is with the labels on the X-Axis. They disappear when the size of labels is too large. I tinkered around with the size of the div element holding the graph and font size of the labels but since the labels are dynamically generated for various users I cannot decide on a fixed value. An ideal solution would be to have the text wrapped up. What can be done to counter the situation?
Morris.js uses the following snippet to make the text svg element.
this.raphael.text(xPos, yPos, text).attr('font-size', '11').attr('font-family', 'calibri').attr('fill', this.options.gridTextColor);
It seems raphael supports multiline strings by putting "\n" in the text. This could be a cheap solution for you, systematically replacing " " by "\n" in your labels.
The other (more tricky) solution would be to replace the "text" element in the SVG generated by raphael by a foreign element that allows word wrapping:
<foreignObject x="20" y="10" width="150" height="200">
<p xmlns="http://www.w3.org/1999/xhtml">Wrapping text using some foreignObject in SVG!</p>
</foreignObject>
or if you need a fallback:
<switch>
<foreignObject x="160" y="10" width="150" height="200"><p xmlns="http://www.w3.org/1999/xhtml">Wrapping text using some foreignObject in SVG!</p></foreignObject>
<text x="20" y="20">Your SVG viewer cannot display html.</text>
</switch>
I don't know the best way to do this replacement of "text" by a foreign object: either after the Morris rendering or by hacking Morris/Raphael.
I think the problem definition need more clarification,
at my end the code you have sent works fine, also I have replicated the same in JSFIDDLE that is also working fine..
I think the label problem is done automatically as I have tested the default size you have kept was carrying width 385px when looking in to CSS and 518px when looking the same, in both case the rendered labels were different, in-fact the label exceeding certain width were not rendered. SO there is no meaning to set style and override.
I think the things are built in library. So its a long way to go, or change the library.
let me know which will be convenient way, I will help you accordingly :)
Edit:
However, you can change property of GridTextSize: that is 16 by default
Fiddle2 here I have updated
'gridTextSize:8' that displays all text in size 8.
Not perfect but will do :)
Download not minimized morris.js from there. In zip-archive you can find a file morris.js. Open it in edit mode and change value of default label angle parameter (line 133):
133 | xLabelAngle: 90,//original value 0
Now, if you really need it minimized, you can compress file by any online js compress tool.

Resources