[Vuejs]-Calculate font size based on image resolution and user size inputs

0đź‘Ť

Linear scale

It is straight forward to scale to match a given dimension as long as you establish the relationship between pixels and the scale you are working in.

For example the image size and the representative physical size can be expressed as

const imageSize = {
    cm: {width: 24, height: 21},
    px: {width: 1200, height: 950},
    cm2px: {width: 1200 / 24, height: 950 / 21},
    px2cm: {width: 24 / 1200, height: 21 / 950},
};

Giving the size of the canvas and the physical, and the conversion scales between them.

With that and knowing the scale relationship between “Points” and “cm” as 1pt = 0.0353 you can scale canvas text to match the points size in the cm scale of the canvas.

To scale and render from “px” to “point” with the above info

    const pt2cm = 0.0353;
    const textPointSize = 38;

    ctx.font = textPointSize + "px arial"; // In px (pixels)

    const xScale = pt2cm * imageSize.cm2px.width;
    const yScale = pt2cm * imageSize.cm2px.height;
    ctx.setTransform(xScale, 0, 0, yScale, 100, 100);

    ctx.fillText("38pt text", 0, 0);

Example

The example creates a canvas and draws a cm grid. Then draws the font at various pt sizes on the canvas.

The function drawText takes the font size in points, and the text position in cm

The 38pt text is approx 13mm tall in the scale of the canvas image using a point size of 0.0352778cm

const ctx = canvas.getContext("2d");

const imageSize = {
    cm: {width: 24, height: 21},
    px: {width: 1200, height: 950},
    cm2px: {width: 1200 / 24, height: 950 / 21},
    px2cm: {width: 24 / 1200, height: 21 / 950},
};
const pt2cm = 0.0352778;

canvas.width = imageSize.px.width;
canvas.height = imageSize.px.height;
drawGrid();

for (let i = 10; i < 40; i += 4) {
    drawText("Test text "+i+"pt", i, 3, 1 + (i - 10) / 2);
}

function drawText(text, sizePt, xCm, yCm) {
    const x = imageSize.cm2px.width * xCm;
    const y = imageSize.cm2px.height * yCm;
    ctx.font = sizePt+"px Arial";
    ctx.textAlign = "left";
    ctx.textBaseline = "top"
    ctx.fillStyle = "#000";
    const xs = pt2cm * imageSize.cm2px.width;
    const ys = pt2cm * imageSize.cm2px.height;
    ctx.setTransform(xs, 0, 0, ys, x, y);
    ctx.fillText(text, 0, 0);
    ctx.setTransform(1,0,0,1,0,0);
}














// Draws a grid
function drawGrid() {
    const w = imageSize.px.width;
    const h = imageSize.px.height;
    const sx = imageSize.cm2px.width;
    const sy = imageSize.cm2px.height;
    ctx.globalAlpha = 0.3;
    ctx.fillStyle = "#aaa";
    ctx.beginPath();
    for(let i = 0; i < Math.max(imageSize.cm.height, imageSize.cm.width) * 5; i += 1) {
        if (i % 5) {
            ctx.rect(0, i * sy / 5 | 0, w, 1);
            ctx.rect(i * sx / 5 | 0, 0, 1, h);
        }
    }
    ctx.fill();
    ctx.fillStyle = "#000";
    ctx.beginPath();
    for(let i = 0; i < Math.max(imageSize.cm.height, imageSize.cm.width); i += 1) {
        ctx.rect(0, i * sy | 0, w, 1);
        ctx.rect(i * sx | 0, 0, 1, h);
    }    
    ctx.fill();
    ctx.globalAlpha = 1;
    ctx.font = "12px arial";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillStyle = "#000";
    ctx.strokeStyle = "#FFF";
    ctx.lineWidth = 4;
    ctx.strokeText("cm", 12, 10);
    ctx.fillText("cm", 12, 10);
    for(let i = 1; i < Math.max(imageSize.cm.height, imageSize.cm.width); i += 1) {
        ctx.strokeText(i, 10, i * sy);
        ctx.strokeText(i, i * sx, 10);
        ctx.fillText(i, 10, i * sy);
        ctx.fillText(i, i * sx, 10);
    }
}
<canvas id="canvas"></canvas>

Note That the physical and pixel sizes do not match and thus the canvas scale is stretched in the y direction.

To get a square aspect you should use only one scale for both the x and y scale or change the canvas size to match the physical aspect.

Leave a comment