I am using svg elements in our blazor applications. In that I am using text elements inside an Svg. Meanwhile I need text element's height and width in pixels. Based on that I am doing some dimension changes in SVG element. Unfortunately, I have no idea on how to get the text element's size.
In ASP.Net applications, there is a way like below,
using System.Drawing;
private float GetWidthOfString(string str)
{
Bitmap objBitmap = default(Bitmap);
Graphics objGraphics = default(Graphics);
objBitmap = new Bitmap(500, 200);
objGraphics = Graphics.FromImage(objBitmap);
SizeF stringSize = objGraphics.MeasureString(str, new Font("Arial", 12));
objBitmap.Dispose();
objGraphics.Dispose();
return stringSize.Width;
}
But I can't use this in blazor application. Is there any way find the text element's size in pixels?
To get the SVG's text element's width and height with JavaScript, we can call the getBBox method of the text element to get the text's width and height. We get the text element with document. querySelector . Then we call getBBox on the returned textElement to get an object with the dimensions of the text.
You can not change the font size or font width because SVG is not a font. It is Scalable Vector Graphics. If you would have some text in your SVG then you could do something with the font from the text element.
The simplest way to get graphical information in Blazor is to use the DOM.
Measure the text using javascript by creating a temporary svg element.
In your javascript, create the following function:
window.measureString = function(textParams) {
const svg = `
<svg style="position:absolute">
<text
font-family="${textParams.Font}"
font-size="${textParams.Size}">
${textParams.Text}
</text>
</svg>`;
const el = document.createElement("div");
el.innerHTML = svg;
document.body.appendChild(el);
const svgText = el.querySelector('text').getBBox();
el.remove();
return { Height: svgText.height, Width: svgText.width };
}
...and interop to that function.
In your .blazor
file:
@inject IJsInterop js;
@code {
public class Measurement { public decimal Width { get;set; } public decimal Height { get;set; }}
Task MeasureString(string text, string font, int size) {
var measurement = await js.InvokeAsync<Measurement>("measureString",
new {
Text = text,
Font = font,
Size = size
});
Console.WriteLine($"Width: {measurement.Width} Height: {measurement.Height}";
}
}
The code above averages at 2ms
per call.
Out of curiosity, I also found a way of doing (more or less) the same measurement with native c# using the library SixLabors.Fonts
.
The following code gets you a measurement. The font itself must be provided first as a Stream
, so quite a bit of work. Also, the measurement does not yield the same result as the js code above, so probably not compatible with SVG measurements. I used C:\Windows\Fonts\Arial.ttf
as a source in a MemoryStream
.
using SixLabors.Fonts;
var fontStream = GetFontAsMemoryStream();
var fonts = new FontCollection();
var font = fonts.Install(fontStream);
var renderOption = new RendererOptions(font.CreateFont(size));
var measurement = TextMeasurer.Measure(text, renderOption);
The above code averages at 2500ms
, so a bit more than 1000 times slower than js interop. Might be possible to cache the result of fonts.Install()
somehow, but I did not immediately succeed to re-use the font
instance without exceptions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With