1

I need to be able to find the width of a string variable if it were to be displayed on the screen. The technique I've found for doing this entails using a span, filling it with the string in question and then measuring the width of that span. Unfortunately I need to calculate the width of my string a couple hundred times during the loading of my page to determine the dimensions of various elements on my screen. The calls to the existing version of this function takes about 95% of my execution time and I'm wondering if there's a faster way to calculate the width of a string that maybe doesn't use the DOM which I'm assuming is why this function is bottlenecking my page. The code I'm using to calculate string width presently looks like this:

<script>
String.prototype.strWidth = function(){
    $("#ruler").html(this);
    return $("#ruler").width();
};
</script>
<span id="ruler" style="visibility:hidden;white-space:nowrap"></span>
10
  • 1
    Care to explain WHY you need to calculate the width of the screen? There is no guarantee that your string width is going to be the same for all users depending on the browser settings, etc, and if it has anything to do with formatting it would probably much better be done with css. Commented Nov 4, 2015 at 19:18
  • not the width of the screen. the width of the string if it were displayed on the screen. I'm trying to display divs in place of those selects, hopefully of an appropriate width, so I don't have to load hundred of selects when the page loads which takes a long time. Commented Nov 4, 2015 at 19:22
  • Indeed. And depending on the user's font size settings, or screen width and the way it affects the elements in the dom, the width of the string itself will be changing. Different fonts are used depending on the language packs available, etc, many things could cause it to be inconsistent. Hence, why knowing why would be good. If there's a good reason for it, then we can figure it out. But odds are there is a different and simpler way to accomplish your goal. So, worth checking what the goal is :) Commented Nov 4, 2015 at 19:25
  • My comment edited with why I need to get the string's width. Commented Nov 4, 2015 at 19:27
  • So why don't you just create the div with the text in it? Commented Nov 4, 2015 at 19:30

2 Answers 2

1

You're looking for the canvas' measureText method.

I know w3 isn't the best, but this link explains it: http://www.w3schools.com/tags/canvas_measuretext.asp

Just have a hidden canvas in your DOM:

<canvas id="secret-canvas"></canvas>

var stringBounds = function(string, style) {
    var canvas = document.getElementById("secret-canvas");
    var context = canvas.getContext("2d");
    // Specify the styling
    context.font = style;
    return context.measureText(string);
}

console.log(stringBounds("hello???", "12px sans-serif").width);

For performance gains you could create a reference to context a single time in the global scope, and then use that reference in stringBounds instead of calculating context every time.

Sign up to request clarification or add additional context in comments.

5 Comments

The problem is that this only works for canvas, the OP's code will tell you the length of a string with all the CSS applied to it (kerning, font-stretch)
It's not perfect because of what @JuanMendes pointed out but it executes much faster and gives me a result that at least approximates the correct result. Fortunately there's not a lot of CSS for me to consider in terms of how the text is displayed on my page.
It definitely has its problems - but this is THE way to efficiently calculate rendered string width. I am confident in saying that there may be no efficient way to get the bounds of strings which are styled in a complicated manner. Glad it worked in your case!
Do you really want an "approximate" result? If you underestimate the size of the string by one pixel and allocate space for it accordingly, it will spill over onto the next line. Or else it will create a scrollbar or something equally ugly.
That ought to be kept in mind, and probably handled with white-space: nowrap, ensuring that the container is sufficiently long, or any other method. As I said, I believe this is THE method for efficient string bound calculation. Until someone else comes up with an improvement on this, I'll hold the belief that there is no way to efficiently calculate string bounds for a string with multifarious styling.
0

For an efficiency upgrade, you could simply change up how often you do a jQuery selector:

<script>
String.prototype.strWidth = (function() {
    // Keep variable in closed-over function (don't pollute global scope)
    var $ruler = $('<span>');
    return function() {
        $ruler.html(this);
        return $ruler.width();
    };
})();
</script>

Edit: Used a virtual span

1 Comment

You have to put this in a DOM ready handler otherwise $('#ruler') will be an empty jQuery object

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.