Search code examples
javascriptjqueryhtmlcssmonospace

How many monospace characters fit horizontally and vertically in an element?


I'm trying to find out how many monospace characters fit in an element (e.g. div), knowing the size and the font-size.

For instance I expected the result being:

{
   x: Math.floor(divWidth / fontSize)
 , y: Math.floor(divHeight / lineHeight)
}

But it seems that they are not right: for a font size 50px and width: 100px, the expected answer would be 2, but it is 3:

div {
    font-family: monospace;
    background: black;
    color: lightgreen;
    font-weight: bold;
    width: 100px;
    height: 100px;
    font-size: 50px;
}
<div>
123
123
</div>

For the example above the answer should be:

{
   x: 3 // 3 chars horizontally
 , y: 1 // 1 char vertically
}

How to compute these values automatically?

var $div = $("div");
var divSize = {
    w: $div.width()
  , h: $div.height()
};
var fontSize = parseInt($div.css("font-size"));

Solution

  • I built a jQuery plugin that does this:

    $.fn.textSize = function () {
        var $self = this;
        function getCharWidth() {
            var canvas = getCharWidth.canvas || (getCharWidth.canvas = $("<canvas>")[0])
              , context = canvas.getContext("2d")
              ;
            
            context.font = [$self.css('font-size'), $self.css('font-family')].join(' ');
            var metrics = context.measureText("3");
            return metrics.width;
        };
    
        var lineHeight = parseFloat(getComputedStyle($self[0]).lineHeight);
        return {
            x: Math.floor($self.width() / getCharWidth())
          , y: Math.floor($self.height() / lineHeight)
        };
    };
    
    alert(JSON.stringify($("div").textSize()));
    div {
        font-family: monospace;
        background: black;
        color: lightgreen;
        font-weight: bold;
        width: 100px;
        height: 100px;
        font-size: 50px;
        line-height: 1;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div>
    </div>