I'm trying to do something like:
$('<span>random text in here</span>').width()
But the width it's returning is 0. (The reason I'm trying to do this is to get the pixel width of a given text.)
How would I get this width, programmatically?
Thanks
You have to have it rendered.
You may do this :
var s = $('<span>random text in here</span>');
s.appendTo(document.body);
var w = s.width();
s.remove();
Demonstration
Note that :
nothing is displayed if you do this like I do in one go. For all practical purposes, nothing is inserted in the DOM,
you could also use an in memory canvas but it wouldn't handle anything more complex than simple text and wouldn't take into account your span's css settings.
Here's the solution measuring the width of some text using an in memory canvas :
var canvas = document.createElement('canvas');
var c = canvas.getContext('2d');
// set here c.font to adjust it to your need
var w = c.measureText('random text in here').width;
Demonstration
I would use the first one in the general case but it might depend on why you want to measure the text.
Related
Good time forum users. Please tell me how to get the size of the element taking into account the font parameters (size, type, style)
let tagText = document.createElementNS("http://www.w3.org/2000/svg", "text");
tagText.setAttributeNS(null, "font-size", 18);
tagText.setAttributeNS(null, "font-weight", 400);
tagText.setAttributeNS(null, "font-family", "Roboto");
tagText.innerHTML = 'Some text ...';
// where ViewPort ??
let widthTitle = tagText.getBBox().width;
console.log('width title: ', widthTitle); // return 0;
updated
Unfortunately, it is not very convenient to change the size after adding, because you have to find all the elements and proportionally change the position. (I initially set up the template engine (handlebars.js) where I pass the necessary parameters and it automatically builds an element with dimensions (the problem is only with get length text).
The OP is commenting:
I generate an svg object depending on the data received. The resulting text can be of different lengths and I need to calculate the size of it to properly generate the object in width.
As I've commented: In this case you may begin with whatever size you want for the svg, append the text, get the size of the text, for example using the textLength property, and next you change the size of your svg element
let tagText = document.createElementNS("http://www.w3.org/2000/svg", "text");
tagText.setAttributeNS(null, "y", 20);
tagText.textContent = 'Some text ...';
svg.appendChild(tagText)
let widthTitle = tagText.textLength.baseVal.value;
svg.setAttributeNS(null,"viewBox",`0 0 ${widthTitle} 25`)
text{font-size:18px;
font-weight:400;
font-family:Roboto
}
svg{border:1px solid; width:200px;}
<svg id="svg"></svg>
Assuming that the element has been inserted into the web page, you could use something like this:
getComputedStyle(tagText).width
However, if you did not specify that width yourself (using CSS, for instance), in your case, the default value will be auto.
If that's the case, you could try to look at the width of the element's parent, doing something like this:
tagText.parentElement.offsetWidth
I want to use HTML5 canvas with flexbox. I need to set canvas.width and canvas.height automatically when user resizes window. I have tried to use jQuery for it:
$(".cnvs").attr("width", $(".cnvs").width());
$(".cnvs").attr("height", $(".cnvs").height());
but it keeps increasing actual width of canvas so it almost fills entire screen. I have put it on jsfiddle - try to resize output window with separator.
Is there any reasonable way how to do it? Thanks.
Edit: Just to be clear: I don't want to fill entire screen with that canvas. I want UI where I have:
<div class="container">
<div class="control"></div>
<canvas></canvas>
<div class="control"></div>
</div>
then use flexbox to put those three elements beside eachother, while canvas will be twice as wide as the other. This works without problem, but canvas.width and canvas.height doesn't get updated, so whenever I render something onto that canvas, it is rendered as if that canvas was 320x140 px.
Edit 2: I am sorry, but (perhaps because of my poor English) I am not clear enough. I will try to explain it once again:
Actual width of canvas element is correct (even without using any JavaScript code) only by using flexbox. My problem is that although width is correct (and $(".cnvs").width() returns correct value of width), it doesn't have any "width" attribute, it is still:
<canvas>
</canvas>
and I need to provide width argument by myself (because it renders badly when it's not set). When I try to use my code or proposed:
...
var rect = canvas.parentNode.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
...
it behaves weirdly, canvas's width keeps increasing with every resize, but too much (it erases both control divs almost immediately).
Update 2
If I understand the question correct: the canvas has a flex CSS set (not shown in the question right now). It defines the canvas to be 2x the size of the other two elements, but since the canvas is resized and not its bitmap, the drawings are stretches as well and you want the bitmap to adopt dynamically.
If so, do this change to the code -
This update will leave the CSS rules of the canvas element alone and let flexbox handle it. It will read the actual pixel size of the element and then apply it to the bitmap so that data isn't stretched:
$(window).on("resize", function() {
var cnvs = $(".cnvs")[0]; // cache canvas element
var rect = cnvs.getBoundingClientRect(); // actual size of canvas el. itself
cnvs.width = rect.width;
cnvs.height = rect.height;
// ... redraw content here ...
}
Additionally, since resizing the window can produce a lot of events, you may want to consider "debouncing" so that you only deal with the more recent resize:
var timerID;
$(window).on("resize", function() {
clearTimeout(timerID);
timerID = setTimeout(function() {
var cnvs = $(".cnvs")[0]; // cache canvas element
var rect = cnvs.getBoundingClientRect(); // actual size of canvas el. itself
cnvs.width = rect.width;
cnvs.height = rect.height;
// ... redraw content here ...
}, 180); // adjust at will
}
This will delay the resizing/redrawing until 180ms has passed.
You don't even have to load jQuery, it is simple:
var canvas = document.querySelector("canvas");
window.addEventListener("resize", function(){
canvas.setAttribute("width", window.innerWidth);
canvas.setAttribute("height", window.innerHeight)
})
You have to add a listener to the resize event on the window object.
If your looking for a jquery solution.
$( window ).resize(function() {
$(".cnvs").attr("width", $(window).width());
$(".cnvs").attr("height", $(window).height());
});
This should work just fine.
I'm trying to measure the exact height used to render a given string with a given font with an SVG text tag.
I've tried using getBBox and getExtentOfChar, but the height returned by both of these includes some extra space above (and sometimes below) the actual text rendered.
http://upload.wikimedia.org/wikipedia/commons/3/39/Typography_Line_Terms.svg
Using the terms in this image, I'm trying to get the either the cap height + descender height of the text being rendered. Or, if that's not possible, just the cap height. Is there a good way to calculate these values?
Here's a quick codepen showing the extra space I'm talking about:
http://codepen.io/pcorey/pen/amkGl
HTML:
<div>
<svg><text>Hello</text></svg>
<svg><text>Age</text></svg>
</div>
JS:
$(function() {
$('svg').each(function() {
var svg = $(this);
var text = svg.find('text');
var bbox = text.get(0).getBBox();
svg.get(0).setAttribute('viewBox',
[bbox.x,
bbox.y,
bbox.width,
bbox.height].join(' '));
});
});
I understand that this is a fairly font-specific thing, so this might be totally impossible...
No. All the SVG DOM methods (getBBox(), getExtentOfChar()) are defined to return the full glyph cell height. That extra space above the cap height is allowance for taller glyphs - such as accented capitals. I think this is true for HTML DOM methods as well.
There are, however, JS libraries around which may be of use. For example:
https://github.com/Pomax/fontmetrics.js
I have not used this library myself, so I can't tell you how reliable or accurate it is.
Anyone know of function that can break text at word boundaries to fit into rectangle
Following is code for rectangle and text
window.onload = function () {
var outsideRectX1=30, outsideRectY1=30,outsideRectX2=220, outsideRectY2=480, outsideRectR=10;
var group = paper.set();
var rect1=paper.rect(outsideRectX1+40, outsideRectY1+70, 80, 40,10);
var text3=paper.text(outsideRectX1+75, outsideRectY1+85,"Test code for wrap text").attr({fill: '#000000', 'font-family':'calibri', 'font-size':'14px'});
group.push(rect1);
group.push(text3);
};
When text is greater than rectangle width it automatically wrap so that it always display into rectangle boundaries.
I'm not sure whether there is any direct way to wrap the text according to the size of the rectangle. May be you can specify line breaks or a "\n". Or you can try to resize the rectangle as and when the text length increases.
Here is a sample code where the rectangle resize as the text length increases.
var recttext = paper.set();
el = paper.rect(0, 0, 300, 200);
text = paper.text(0,10, "Hi... This is a test to check whether the rectangle dynamically changes its size.").attr({"text-anchor":"start",fill:'#ff0000',"font-size": 14});
text1=paper.text(0,30,"hi").attr({"text-anchor":"start",fill: '#ff0000',"font-size": 14});
//el.setSize(495,200);
recttext.push(el);
recttext.push(text);
recttext.push(text1);
alert(recttext.getBBox().width);
alert(recttext.getBBox().height);
var att = {width:recttext.getBBox().width,height:recttext.getBBox().height};
el.attr(att);
recttext.translate(700,400);
I know it's a little belated now, but you might be interested in my [Raphael-paragraph][1] 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.
Let's say that I got the following code in a page:
elit ac <a href="http://www.ducksanddos/bh.php" id='link'>Hello world!</a> nunc
And that I want to make the <a> contain a <canvas> element which will display the exact same text and will look exactly like the <a> looked before the change, resulting code:
elit ac <a href="http://www.ducksanddos/bh.php" id='link'><canvas width='xxx' height='xxx' /></a> nunc
After investing some time I arrived to this partial solution (btw I also use jQuery):
var width = $('#link').width();
var height = $('#link').height();
var element = document.getElementById('link');
var content = element.innerHTML;
var fontfamily = document.defaultView.getComputedStyle(element, null).getPropertyValue('font-family');
var fontsize = document.defaultView.getComputedStyle(element, null).getPropertyValue('font-size');
// create the canvas element
var canvas = doc.createElement("canvas");
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.textBaseline = 'bottom';
ctx.font = fontsize+" "+fontfamily;
ctx.fillText(content, 0, 22);
element.innerHTML = ''; // delete original content of <a>
element.appendChild(canvas);
}
My problem is that from some reason the text is displayed a little bit higher (few pixels) then the rest of the text which surround the <a> (that's after I gave it an extra 22px at ctx.fillText(content, 0, 22); in order to make the text visible at all..).
When checking with the firebug selector it seems that the <canvas> element is the same size as the <a> but located a little bit higher (which is weird cause it's a child element of it...).
One last thing, all of this code is being run from a Firefox extension so there is no need for compatibility with other browsers.
Thx a lot!
Yonatan Ben-Nes
Keep in mind that a rendered canvas is sort of like an image on the page. So it will follow layout rules as such (this means it may not align exactly with your text on it's own)
You may need to use CSS to align the resulting image element with your text. Try adding the following JS at the end of the above script:
canvas.style.verticalAlign="middle";
That seemed to do it for me when I tried your sample (I provided my own sample html etc). I also had to change the fillText command to:
ctx.fillText("content", 0, 20);
But that could have been because of my browser/OS font settings.
Could it be that you can just overlay the text on top of the canvas? What exactly do you want the canvas for?