SVG - how to set text line-height - javascript

It seems line-height is the one CSS property absent from svg text. The best resource on SVG I have found is: Jenkov.com SVG Tutorials and there is no mention of it, neither could I find mention of it on MDN.
So if anyone can shed definitive light on this or share a technique. I am basically interested in the spacing between lines of text that wrap, not independent text elements.
Thanks

SVG 1.1 (officially) only supports single line text, hence no line-height setting.
I've just tried creating a block of text in Inkscape, and it's using a flowRoot element (containing a flowPara element with the actual text in it). Then the flowRoot element actually has line-height assigned to it (in %).
I don't know how wide-spread support for that way is, since it used to be part of SVG 1.2. You might also want to have a look here: Auto line-wrapping in SVG text

Related

The width seems to be zero (or NaN) always for an svg:text element in Firefox 15

I am using d3 to make a chart with multiple paths. I am displaying the path(s) description on the left hand side. The data & descriptions are dynamic so the size of the legend is naturally also dynamic, since it is not a big deal as long as I know the size of the text (just a minor adjustment to the domain/range). The problem is that I do not see an easy way to find the size of the text element in Firefox browsers.
Previously I was doing it with jquery's .width() but the clientWidth on the element is zero which seems to cause a NaNpx to be returned.
...
.on("click", function(){
alert( $(this).width() ); // NaNpx
})
...
DEMO: Click on the words.
While writing up this question I found the solution (but still going to post it because I spent a very long time searching before finding it deep in a code example). Might be just because I am brand new to d3 and svg this month but there is a getBBox() method on the text element (most elements) that will generate an object with the width/height/x/y (and it really should be used instead of jquery for all svg dimensions).
Hope posting this will help anyone else who runs into this problem because it did not seem very visible to me.
DEMO
And in the example the ~~ is a flip-bit-operator, twice will actually work like a Math.floor() but will likely be faster in all browsers then .floor().
Got the same problem. Seems like there is a bug in firefox (45.0) that <text> elements width inside SVG is always 0.
I overcame the bug by using a <tspan> element (inside the <text> element), and seems like the <tspan> has the correct width of text.
Hope it helps.

Text masks out the background

You have an object (span or div e.g.) with text. And this text should mask out the colored background of the object so that you can see the very background (of body element e.g.).
I know there is "mask-image". But they don't want to develop this CSS3 technique further. Is there a Javascript solution maybe so anyone can see this?
Is there any chance to do this cross-browser?
Can't think of a technique to do this in javascript or html. However, an approach that could be used (although not entirely desirable - I realize that this is going to be time consuming) would be to create a transparent .png for each letter, set the background of the letter to transparent and the rest of the image to some color, and then use those. You would have to make a whole set for each color you wished to use. You could also just make an image which was one word in a .png and use that which would be easier. This would be the only current way to get this to work with all browsers including older ones such as IE6 where the newer techniques are not available.
The reason, in my opinion, that this will not currently work, is that when you have text inside of a <div> or <span> even if the text is transparent, it would merely default to the color of the <div> or <span>. If their background was set to transparent, then nothing would even show up. Conversely, if their color was set, the text would not show up because it would merely inherit that color.
It looks like the closest you can get to full cross-browser support (without using images for each character in the text) is the very-limited tricks shown here. These tricks wouldn't work with a photographic bg image though.
If you don't require support for IE8 or earlier, you could investigate doing this in SVG or Canvas. Note however that Android prior to 3.0 doesn't support SVG, which rules out as much as 85% of existing Android devices.
Webkit has a proprietary background-clip:text style, but it only works on Chrome and Safari.
Using color:transparent for the text turned out to be completely useless for this.
On the whole, the best bet may be canvas, especially if you can find a JS library or jQuery plug-in that provides a VML alternative for IE8 and earlier (assuming the VML solution supports text masks), or if you can provide a graceful-degradation fallback option for IE8 and earlier that looks adequate even without a text mask.
Another solution that's easily overlooked: If you can dynamically render an image on the server using the current text on the page (caching it as needed), and then serve that image to the client, then there are no cross-browser issues to deal with. This could possibly be done in PHP using the GD graphics library, for instance.

Word Wrap in Raphael JS / SVG

How do you get words to wrap inside a box in RaphaelJS? Or in browser-based SVG in general?
I found this thread on it, but it doesn't make any sense. They say to use "widthToCharNum" but as far as I can tell, this thread is the only place those words have ever been used on the internet. They suggest using a "width" attribute, but this has no effect.
Text-wrapping is not built into Raphael or the SVG spec. Period. Coming from the HTML world, I found the absence of text wrapping pretty shocking.
However, you can do it yourself without too much difficulty. See this question for details and an example. Unfortunately, you have to burn some client-side cycles to make it work dynamically.
The svg.js library has a svg.textflow.js plugin. It's not ultra fast but it does the trick. It even stores overflowing text in a data attribute so you can use it to create continuously flowing columns. Here the text flow example page.
The tspan tag can give the illusion of word wrap, but there is no built in word wrap functionality.
The tspan tag is identical to the text tag but can be nested inside text tags and inside itself. Coupled with the 'dy' attribute this allows the illusion of word wrap in SVG 1.1. Note that 'dy' is relative to the last glyph (character) drawn. There is a tutorial on how to use tspan at http://tutorials.jenkov.com/svg/text-element.html.
The article at http://www.xml.com/pub/a/2002/09/11/quint.html might also be useful.
I know it's a little belated now, but you might be interested in my Raphael-paragraph project.
It's a small library that allows you to create auto-wrapped multiline text with maximum width and height constraints, line height and text style configuration. It's still quite beta-ish and requires a lot of optimization, but it should work for your purposes.
Usage examples and documentation are provided on the GitHub page.

One <span> per character in web-based text editor

I'm developing a web-based text editor without any contentEditable, textarea or input things. The biggest portion of my work is to measure widths of text on the left (right) side from the current caret position and moving the caret in the text.
For example when user presse the DOWN key a current left-offset of the caret must be computed and on the line below a character which's position is most similar must be found.
One very convenient way to do is to use one DOM element per character - I can just look at the offsetLeft property. Also, positioning the caret is much easier. Actually, everything is easier.
However I'm very unsure about the performance implications. I have seen this technique (or similar) used on some web-based JavaScript "IDE"s and it works just fine there.
Do you have any hints, tips?
Do you know some other fast way how to measure width of text. I want to avoid putting sections of a line to a DOM element and measuring its width each time as I think it will be much slower.
EDIT: I'm mostly asking about the main fact of EXISTENCE of many dom elements. How to do the measuring is a different thing.
I've seen this done (unfortunately can't find the link now) by using a canvas object and its measureText() method - basically you can ask a canvas "what size would this piece of text be if i rendered it in this style?" and use that to determine your caret position on the surrounding lines. This is performant, but of course it will only work in HTML5-capable browsers, and maybe not all of them.
But frankly this sounds like a big pain in the neck and probably more trouble than it's worth for an in-browser editor :)
You might be interested in this, which is a javascript implementation of the VI text editor. Unfortunately it does use a textarea, however not in the typical manner.

Hover effects on irregular polygons in CSS

I'm wondering how to go about marking up and coding hover effects for a map similar to this image.
When each district (or section) is moused over/touched/clicked I need to change the colour of it without affecting any other section. The boundaries on each section must be representative of the image and shouldn't be squares. The solution can't use canvas since the site I'm working on has to be usable in older browsers (I'm gutted, personally.)
Ideally I want to do this with CSS without using too much JavaScript or loads of images. Has anyone done this before?
Edit: I know people are suggesting the <area> tag, but AFAIK, it doesn't accept the :hover pseudo class.
Edit 2: I might use this: http://www.netzgesta.de/mapper/
Another self answer...
A few months ago I came across a library called Raphael JS - http://raphaeljs.com/. For those of you unfamiliar with it, it's an SVG DOM library first and foremost. If you know a thing or two about SVG, you'll know that IE doesn't support it, but it does support VML. Raphael caters for this as well. Awesome, right?
Anyway, I ended up saving the AI file for the map as an SVG file and importing the paths into a JSON block, basically doing the same thing as this code: http://raphaeljs.com/australia.html
The only issue I came across:
I wanted the map background to be transparent. Setting fill to transparent whilst allowing the section to accept mouseover worked in Firefox, but in IE, it failed. I instead opted for filling the path with white, then setting the opacity to 0.01. After that I duplicated the path and didn't fill it to create the border.
You can use HTML <area> Tag
If you use jQuery you can use the maphilight plugin. documented at http://davidlynch.org/projects/maphilight/docs/ and available from github at https://github.com/kemayo/maphilight
I see what the problem here is: making let's say a world map the usual way is quite a load. If I get it right, what you want is to have a territory map image and put hover effects making hover area match country borders exactly. SVG can be used for the map (the drawing part is already done) but the problem is how to generate HTML area map using SVG map coordinates. There's a solution (I've tried it, looks good at least with the demo provided) which translates SVG into Raphael (generates the coords) using PHP. But again you need raphael.js for that... well if you change your mind: https://github.com/atirip/svg2raphael. And if you're not familiar with Raphael it will take a time to get used to it, documentation is not so good -for me-.
Edit: I can confirm that translation from SVG->rapahel.js works but SVG files needs some tweaks. For what I see in the example SVG provided in svg2raphael the files were made with Adobe Illustrator. I've tried with SVG (plain) from Inkscape and it didn't work properly, but I could manage to fix the issues, for example:
svg2raphael won't translate Inkscape generated <path style="fill:#ff0000" ...></path> (will set fill="none"!!! so the result is invisible, but will translate correctly <path fill="#ff0000" ...></path> Seems like it will ignore everything inside style="".
svg2raphael misreads the alignments from Inkscape SVG, so you need to either move the illustration inside Inkscape or edit the SVG file with text editor and change the M value to M0,0.
svg2raphael can translate multiple svg elements, but looks at the main tag which Inkscape generates to align groups of illustrations, sometimes the whole illustration moves away from the render area and you see nothing. Hope this helps!
Edit 2: You can use Inkscape's style="" for creating CSS rules to apply to the SVG, that works great ang keeps style outside SVG/Raphael!

Categories