Thursday 31 January 2019

Javascript/Jquery making text to fit perfectly on div given dimensions with line break(if needed)

I'm having a little hard time working this out: I have these functions that I use in order to fit a single lined text into given dimensions.

function getFontSize(width, height, text, font, callback) {
    var n = 100;
    var ctxfont = n + 'px ' + font;
    var result = measureTextHeight(ctxfont, text);
    while (result.width > width || result.height > height) {
        n--;
        var ctxfont = n + 'px ' + font;
        var result = measureTextHeight(ctxfont, text);
    }
    callback({
        'width': result.width,
        'height': result.height,
        'size': n
    });
}

function measureTextHeight(ctxFont, text) {
    var width = 1500;
    var height = 500;

    var canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    var ctx = canvas.getContext("2d");
    ctx.save();
    ctx.font = ctxFont;
    ctx.clearRect(0, 0, width, height);
    ctx.fillText(text, parseInt(width * 0.1, 10), parseInt(height / 2, 10));
    ctx.restore();
    document.body.appendChild(canvas);
    var data = ctx.getImageData(0, 0, width, height).data;


    var topMost = false;
    var bottomMost = false;
    var leftMost = false;
    var rightMost = false;
    for (var x = 0; x < width; x++) {
        for (var y = 0; (y < height) && (!leftMost); y++) {
            //console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
            if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
                leftMost = x;
            }
        }
    }
    for (var y = 0; y < height; y++) {
        for (var x = 0; (x < width) && (!topMost); x++) {
            //console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
            if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
                topMost = y;
            }
        }
    }
    for (var x = width - 1; x >= 0; x--) {
        for (var y = height - 1; (y >= 0) && (!rightMost); y--) {
            //console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
            if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
                rightMost = x;
            }
        }
    }
    for (var y = height - 1; y >= 0; y--) {
        for (var x = width - 1; (x >= 0) && (!bottomMost); x--) {
            //console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
            if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
                bottomMost = y;
            }
        }
    }
    canvas.remove();
    return ({
        width: (rightMost - leftMost) + 1
        , height: (bottomMost - topMost) + 1
    });
}

function getAlphaIndexForCoordinates(x, y, width, height) {
    return (((width * 4 * y) + 4 * x) + 3);
}

I pass the wanted dimensions and font to getFontSize function and it returns the real width and height of the text as well as the font size needed for it to be accomplished. This way I can draw the text to canvas using ctx.filltext() function, the best fit possible, and align it in the center based on its width and height. I'm not sure if it's the most efficient way of achieving the wanted result but it's working.

What I want to do now is instead of making it single lined, I can set a given width and height for a div and then, giving the text, it would fit perfectly those dimensions adding line breaks if needed, and still return the real width and height of the text so I can draw it correctly to the canvas like this fiddle: http://jsfiddle.net/vkgjrd3e/ although in the fiddle it still has some space on the bottom of the div.

What I'm trying to achieve is the best fit possible for the text, given its font and its container dimensions; adding line breaks if needed.



from Javascript/Jquery making text to fit perfectly on div given dimensions with line break(if needed)

No comments:

Post a Comment