Подтвердить что ты не робот

Определить ширину строки в холсте HTML5.

Я рисую текст в холсте HTML5 поверх изображения (генератор мем.). Я хочу рассчитать размер шрифта, чтобы строка охватывала всю ширину холста.

Итак, есть ли в JavaScript способ определить, какой размер шрифта я должен использовать для некоторой строки определенного шрифта для заданной ширины?

4b9b3361

Ответ 1

Метод fillText() имеет необязательный четвертый аргумент, который является максимальной шириной для визуализации строки.

Документация MDN говорит...

MaxWidth

Необязательно; максимальная ширина для рисования. Если указано, и строка вычисленный таким образом, чтобы ширина была больше ширины, шрифт настраивается так, чтобы использовать более горизонтально сконденсированный шрифт (если он доступен или если достаточно читаемый, можно синтезировать, масштабируя текущий шрифт горизонтально) или меньший шрифт.

Однако на момент написания этого аргумента этот аргумент не поддерживается хорошо перекрестным браузером, что приводит ко второму решению, используя measureText() для определения размеров строки без ее рендеринга.

var width = ctx.measureText(text).width;

Вот как я могу это сделать...

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d');

// Font sizes must be in descending order. You may need to use `sort()`
// if you can't guarantee this, e.g. user input.
var fontSizes = [72, 36, 28, 14, 12, 10, 5, 2],
    text = 'Measure me!';

// Default styles.
ctx.textBaseline = 'top';
ctx.fillStyle = 'blue';

var textDimensions,
    i = 0;

do {
   ctx.font = fontSizes[i++] + 'px Arial';
   textDimensions = ctx.measureText(text);        
} while (textDimensions.width >= canvas.width);

ctx.fillText(text, (canvas.width - textDimensions.width) / 2, 10);​

jsFiddle.

У меня есть список размеров шрифтов в порядке убывания, и я перебираю список, определяя, будет ли отображаемый текст соответствовать размерам холста.

Если это произойдет, я выровняю текстовый центр. Если вы должны иметь прописку слева и справа от текста (который будет выглядеть лучше), добавьте значение прокладки к textDimensions.width при расчете, если текст будет соответствовать.

Если у вас есть длинный список размеров шрифта, попробуйте, вам будет лучше использовать алгоритм поиска . Однако это увеличит сложность вашего кода.

Например, если у вас 200 размер шрифта, линейная итерация через элементы массива будет равна O (n).

Бинарная отбивная должна быть O (log n).

Вот мужество функции.

var textWidth = (function me(fontSizes, min, max) {

    var index = Math.floor((min + max) / 2);

    ctx.font = fontSizes[index] + 'px Arial';

    var textWidth = ctx.measureText(text).width;

    if (min > max) {
        return textWidth;
    }

    if (textWidth > canvas.width) {
        return me(fontSizes, min, index - 1);
    } else {
        return me(fontSizes, index + 1, max);
    }

})(fontSizes, 0, fontSizes.length - 1);

jsFiddle.

Ответ 2

У меня есть следующий код, и он отлично работает для меня. Возможно, есть небольшая ошибка, но мне не нужно иметь список размеров шрифтов. Я просто получаю ширину с размером шрифта, и если она слишком большая, я вычисляю пропорциональный размер в зависимости от ширины холста и заполнения (50)

ctx.font = FONT_SIZE+"pt Verdana";
var textWidth = ctx.measureText(markText).width;
if(textWidth > canvas.width - 50) {
    ctx.font = parseInt(FONT_SIZE*(canvas.width-50)/textWidth)+"pt Verdana";
    textWidth = ctx.measureText(markText).width;
}
ctx.textBaseline = "middle";
ctx.fillStyle = "rgba(255,255,255,0.5)";
ctx.strokeStyle = "rgba(0,0,0,0.5)";
var xT = image.width / 2 - textWidth / 2;
var yT = image.height / 2;
ctx.fillText(markText, xT, yT);
ctx.strokeText(markText, xT, yT);