setting line height for text element in raphael - svg

I'd like to increase the line height for a multiline text element generated with raphael. This does not appear to work:
text_element.attr({"line-height": "16" });
How can this be done? Thanks

You can do the following, but it's not pretty and breaks the encapsulation provided by Raphael. Consider the following:
text_element = r.text(10, 10, "Text in\nRaphael\nis a pain");
text_element.node.childNodes[0].setAttribute('dy', 0);
text_element.node.childNodes[1].setAttribute('dy', 5);
text_element.node.childNodes[2].setAttribute('dy', 5);
This will yield overlapping lines of text with the default font settings.
If I discover a better way, I'll update my answer.

Related

How to right/end align text along an textPath inside an arc using d3.js?

Here's the fiddle: http://jsfiddle.net/DevChefOwen/CZ6Dp/
var text = g.append("text")
.style("font-size",30)
.style("fill","#000")
.attr("dy",0)
.append("textPath")
.attr("xlink:href","#yyy")
.style("text-anchor","left") // using "end", the entire text disappears
.text("some text");
I've tried a number of different things to no avail. The left align is the easy part. If you did a middle, though, you see only "text" instead of "some text", implying that "some" is just hidden because it went "out of span" for the given arc.
If, however, I added:
.attr("startOffset","39%")
(as in here: http://jsfiddle.net/DevChefOwen/2H99c/)
It would look right aligned, but outside of programmatically trying to get the width/height of the text element and look for sharp changes in width/height (which seems wrong and likely error-prone), I can't seem to find a way to right align the text.
I've also tried using an SVG path (essentially a curved arc line) and the same disappearing act happens with the text when "text-anchor" is set to "left".
Thanks ahead for your time!
The question is somewhat confusing matters. The issue isn't aligning text at the end of the path -- that's easy to do with "text-anchor"="end" and "startOffset"="100%".
However, using those settings with the path created by the d3 arc function, you end up with the text cornering around the end of the inside curve and the left straight edge, to the end of the path as defined by the arc function:
http://jsfiddle.net/CZ6Dp/8/
The real issue is that the path that you want the text to be aligned along (the outside arc of the shape) is only one segment of the path that defines the shape.
(By the way, "left" and "right" are not valid values for the "text-anchor" property, and will just be ignored).
The answer by #defghi1977 gives one way to approach the problem, by figuring out the length of the path segment that you do want to use and adjusting the start offset accordingly.
Another way to approach the problem is to create a separate path (not drawn on screen) that represents only the part of the path that you want to be used for positioning text.
There are a number of possible ways to create a path that only represents the outside arc (some example code here). #defghi1977's approach of grabbing it from the existing path with regular expressions is probably the most efficent for your situation. But instead of just creating a temporary element to calculate a length, I actually have to add the new path to the DOM so it can be used as the reference path for the <textPath> element. (Which I suppose is the downside to this approach -- twice as many DOM elements!)
var path = g.append("svg:path")
.attr("d", arct)
.style("fill","#ccc")
.attr("transform", "translate("+cfg.w/2+","+cfg.h/2+")")
.each(function(d,i) {
var justArc = /(^.+?)L/;
//grab everything up to the first Line statement
var thisSelected = d3.select(this);
var arcD = justArc.exec( thisSelected.attr("d") )[1];
defs.append("path")
.attr("id", "yyy") //normally the id would be based on the data or index
.attr("d", arcD)
.attr("transform", thisSelected.attr("transform") );
//if you can avoid using transforms directly on the path element,
//you'll save yourself having to repeat them for the text paths...
});
var text = g.append("text")
.style("font-size",30)
.style("fill","#000")
.attr("dy",0)
.append("textPath")
.attr("xlink:href","#yyy")
.style("text-anchor","end")
.attr("startOffset","100%")
.text("some text");
http://jsfiddle.net/CZ6Dp/9/
Again, factoring in the extra DOM load #defghi1977's method is probably slightly preferrable, although this version has the benefit of not being dependent on browser support for getTotalLength. But as far as I know that method is fairly well implemented.
So just consider this an alternate approach for completeness' sake.
This path is constructed by 4(or 5) path segments.
So, this probrem will be solved to get first arc path length.
But I don't know how to get sub path length by using d3.js, thus I use svgdom directly.
I tried to fix your code. If this code is not what you hope, I'm sorry.
path-anchor attribute to end.
define function to get startOffset value.
var path = g.append("svg:path")
.attr("id","yyy")
.attr("d", arct)
.style("fill","#ccc")
.attr("transform", "translate("+cfg.w/2+","+cfg.h/2+")");
var text = g.append("text")
.style("font-size",30)
.style("fill","#000")
.attr("dy",0)
.append("textPath")
.attr("xlink:href","#yyy")
//.style("text-anchor","left") // using "end", the entire text disappears
.attr("text-anchor", "end")
.text("some text")
.attr("startOffset",function(){
var d = document.getElementById("yyy").getAttribute("d");
var tmp = document.createElementNS("http://www.w3.org/2000/svg" ,"path");
//get the arc segment of path
var arc = d.match(/(^.+?)L/)[1];
tmp.setAttribute("d", arc);
//return offset position
return tmp.getTotalLength();
});
I think the confusion comes from the meaning of text-anchor - it's not "relative to where on the parent will I justify" but rather "what part of me should I align to the start".
You're right to try to use startOffset to move the origin. Since the outer radius of your path is longer than the inner radius, the correct start offset is a little more than half of the path (around 53%).
Just a little more twiddling with your settings and you should have it. Here's a fiddle with my interpretation of what you're looking for.

SKIA - Inaccurate value returned by measureText()

I have a problem measuring text using skia measureText() function.
The value returned is inaccurate.
SkPaint *skPaint = new SkPaint();
SkTypeface* myFont = SkTypeface::CreateFromName("Impact", SkTypeface::kNormal);
skPaint->setTypeface(myFont);
skPaint->setAntiAlias(true);
skPaint->setTextAlign(SkPaint::kLeft_Align);
skPaint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
skPaint->setTextSize(SkIntToScalar(120));
skPaint->setColor(0xff000001);
canvas->drawText(text, length, SkIntToScalar(x) , SkIntToScalar(y) , *skPaint);
SkScalar width = skPaint->measureText(text, length);
The width returned by measureText() is 451.
I checked the generated bitmap text via a photo editor app, the actual width is only 438.
Any thoughts on getting the accurate width of text in SKIA?
Thank you!
I believe what you are trying to match will come from "bounds"
SkRect bounds;
SkScalar textWidth = paint.measureText("some", 4, &bounds);
which is a minimum rectangle to fit a given text, whereas textWidth is slightly larger than that.
I faced this issue too. Dont know why exactly it happens, maybe because of kerning differences, but i came to this:
SizeF RenderTextAndroid::GetStringSizeF() {
UpdateFont();
const base::string16& text = GetLayoutText();
std::vector<SkScalar> widths(text.length());
paint_.getTextWidths(text.c_str(), GetStrByteLen(text), &widths[0], NULL);
return SizeF(std::accumulate(widths.begin(), widths.end(), 0),
font_metrics_.fBottom - font_metrics_.fTop);
}
Where UpdateFont just sets new parameters to SkPaint

Drawing strings with slick2d and TTF

I've been experimenting with String printing in LWJGL using slickutils. Generally when browsing the web I found two approaches to this. First being bitmaps where you have an entire alphabet and print each letter as a Texture, the other being using TrueTypeFonts and the truetypefont.drawString(20f,20f,"LWJGL String Test", Color.green) method.
However, most of the literature I found was a few years old. What is the right way to do this at the current time?
At the moment I'm using the TrueTypeFont method, however my result confuses me.
//It doesn't matter which Font I try to load, I get the same green bar.
//I think it has something to do with not finding the Fonts?
Font awtFont = new Font("Times New Roman", Font.BOLD, 24);
TrueTypeFont font = new TrueTypeFont(awtFont, true);
font.drawString(20f, 20f, "LWJGL TEST STRING",Color.green);
I've also copied an example from the internet and get the same result(just a bar).
Tried googling but couldn't find any fixes.
TrueTypeFont is deprecated. Use UnicodeFont instead.
Check this:
// Create a font with the size of 20, and not bold or italic.
Unicode font = new UnicodeFont("res/font.ttf", 20, false, false);
font.addAsciiGlyphs();
font.getEffects().add(new ColorEffect());
font.loadGlyphs();
g.setFont(font);
g.drawString("Shit example", 100, 100);

How can I change text object on the fly (RaphaelJS)?

Lets' say I have following text object:
var text = r.print(50, 50, "demo", r.getFont("Impact", 50), 30).attr({fill: '#fff', stroke: '#000'});
And later want to change it on mouse event to "something".
How can I do that?
text.attr('text', 'something') doesn't work, nor text[0].attr['text'], 's')
You are looking for...
text.attr({'text': 'something'})
Demo http://jsfiddle.net/EUrQv/
Paper.print() is not that same as Paper.text(). As far as I can tell, it's possible to change the text of the latter, but not the former (as print converts the text into a series of paths).

Raphael - how to draw a path that stretches to width?

This may be a very dumb question, but how do I draw a path that will stretch to a div's width?
I am experimenting with Raphaeljs to make an interactive chart: the user can click sparklines and the lines shift up and down to reveal text content. I see that Raphael's rectangles and other shapes will stretch to width fine by setting the width to 100%, but I can't get a line to do this.
I've set up the paper like this:
var SLAPaper = new Raphael( document.getElementById("LineSLA"), "100%", 60);
Set up the line like this:
var lineSLA = SLAPaper.path("F1 M 0,42L 103,12L 222,45L 390,13L 460,45L 453,27L 455,28L 450,0L 479,25");
I also set a viewbox but this doesn't seem to make a difference. I can't set a % width on the viewbox anyway:
SLAPaper.setViewBox(0,0,1500,60, true);
Any help appreciated. Thanks.
I've personally had problems with using percentages for defining size of both paper and objects in Raphael, especially with Internet Explorer. The best I could come up with would be to scale the line to fit inside paper, based on the width of the path (assuming that the width is more than the height):
var line = SLAPaper.path("F1 M 0,42L 103,12L 222,45L 390,13L 460,45L 453,27L 455,28L 450,0L 479,25");
var scl = SLAPaper.width / line.getBBox().width;
line.transform('S' + scl + ',' + scl + ',0,0');

Resources