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

Расстояние между буквами в элементе холста

Вопрос говорит о многом. Я искал вокруг и начал беспокоиться о том, что это невозможно.

У меня есть этот элемент canvas, на который я рисую текст. Я хочу установить расстояние между буквами, аналогичное атрибуту CSS letter-spacing. Под этим я подразумеваю увеличение количества пикселей между буквами при рисовании строки.

Мой код для рисования текста выглядит так: ctx - переменная контекста canvas.

ctx.font = "3em sheepsans";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.fillText("Blah blah text", 1024 / 2, 768 / 2);

Я попытался добавить ctx.letterSpacing = "2px"; перед рисунком, но безрезультатно. Есть ли способ сделать это просто с помощью простой настройки, или мне нужно будет сделать функцию для индивидуального рисования каждого символа с учетом расстояния?

4b9b3361

Ответ 1

Я не уверен, что он должен работать (согласно спецификациям), но в некоторых браузерах (Chrome) вы можете установить свойство CSS letter-spacing для самого элемента <canvas>, и оно будет применено ко всему тексту, нарисованному в контексте, (Работает в Chrome v56, не работает в Firefox v51 или IE v11.)

Обратите внимание, что в Chrome v56 вы должны заново получать контекст Canvas 2d (и заново устанавливать любые значения, которые вам нужны) после каждого изменения стиля letter-spacing символов; интервал, кажется, запекается в 2-й контекст, который вы получаете.

Пример: https://jsfiddle.net/hg4pbsne/1/

var inp = document.querySelectorAll('input'),
    can = document.querySelector('canvas'),
    ctx = can.getContext('2d');
    can.width = can.offsetWidth;

[].forEach.call(inp,function(inp){ inp.addEventListener('input', redraw, false) });
redraw();

function redraw(){
  ctx.clearRect(0,0,can.width,can.height);
  can.style.letterSpacing = inp[0].value + 'px';

  ctx = can.getContext('2d');
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.font = '4em sans-serif';
  ctx.fillText('Hello', can.width/2, can.height*1/4);
  
  can.style.letterSpacing = inp[1].value + 'px';
  ctx = can.getContext('2d');
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.font = '4em sans-serif';
  ctx.fillText('World', can.width/2, can.height*3/4);
};
canvas { background:white }
canvas, label { display:block; width:400px; margin:0.5em auto }
<canvas></canvas>
<label>hello spacing: <input type="range" min="-20" max="40" value="1" step="0.1"></label>
<label>world spacing: <input type="range" min="-20" max="40" value="1" step="0.1"></label>

Ответ 2

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

ctx.font = "3em sheepsans";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = "rgb(255, 255, 255)";
var ctext = "Blah blah text".split("").join(String.fromCharCode(8202))
ctx.fillText(ctext, 1024 / 2, 768 / 2);

Это вставляет пространство для волос между каждой буквой.

Использование 8201 (вместо 8202) добавит немного более широкое тонкое пространство

Дополнительные параметры пробела см. этот список Unicode Spaces

Этот метод поможет вам сохранить шрифт кернинга намного легче, чем вручную позиционировать каждую букву, однако вы не сможете закрепить свое письмо таким образом.

Ответ 3

Вы не можете установить межстрочный интервал как свойство контекста Canvas. Вы можете добиться эффекта только с помощью ручного интервала, извините. (Как и в случае, каждое письмо, вручную увеличивающее х на некоторое количество пикселей на каждом)

Для записи вы можете установить несколько свойств текста, используя ctx.font, но расстояние между буквами не является одним из них. Те, которые вы можете установить: "font-style font-variant font-weight font-size/line-height font-family"

Например, вы можете технически написать ctx.font = "bold normal normal 12px/normal Verdana" (или любое упущение любого из них), и он будет правильно разбираться.

Ответ 4

Не верно. Вы можете добавить свойство letter-spacing к элементу canvas в css, и оно отлично работает. Нет необходимости в сложных обходных решениях. Я просто понял это прямо сейчас в моем проекте холста. т.е.:   холст {       ширина: 480 пикселей;       высота: 350 пикселей;       margin: 30px auto 0;       padding: 15px 0 0 0;       фон: розовый;       display: block;       border: 2px пунктирный коричневый;       буквенный интервал: 0.1em;   }

Ответ 5

здесь некоторый coffeescript, который позволяет вам установить кернинг в ваш контекст так

tctx = tcanv.getContext('2d')
tctx.kerning = 10
tctx.fillStyle = 'black'
tctx.fillText 'Hello World!', 10, 10

поддерживающий код:

_fillText = CanvasRenderingContext2D::fillText
CanvasRenderingContext2D::fillText = (str, x, y, args...) ->

  # no kerning? default behavior
  return _fillText.apply this, arguments unless @kerning?

  # we need to remember some stuff as we loop
  offset = 0

  _.each str, (letter) =>

    _fillText.apply this, [
      letter
      x + offset + @kerning
      y
    ].concat args # in case any additional args get sent to fillText at any time

    offset += @measureText(letter).width + @kerning

javascript будет

var _fillText,
  __slice = [].slice;

_fillText = CanvasRenderingContext2D.prototype.fillText;

CanvasRenderingContext2D.prototype.fillText = function() {
  var args, offset, str, x, y,
    _this = this;

  str = arguments[0], x = arguments[1], y = arguments[2], args = 4 <= arguments.length ? __slice.call(arguments, 3) : [];
  if (this.kerning == null) {
    return _fillText.apply(this, arguments);
  }
  offset = 0;

  return _.each(str, function(letter) {
    _fillText.apply(_this, [letter, x + offset + _this.kerning, y].concat(args));
    offset += _this.measureText(letter).width + _this.kerning;
  });
};

Ответ 6

Чтобы разрешить "пары кернинга букв" и т.п., я написал следующее. Это должно учитывать это, и грубое тестирование подсказывает это. Если у вас есть какие-либо комментарии по этому поводу, я бы указал вам на мой вопрос по этому вопросу (Добавление расстояния между буквами в HTML-холсте)

В основном он использует measureText() для получения ширины всей строки, а затем удаляет первый символ строки и измеряет ширину оставшейся строки и использует разницу для вычисления правильного позиционирования - таким образом, принимая во внимание пары кернинга и тому подобное. См. Данную ссылку для получения большего количества псевдокодов.

Здесь HTML:

<canvas id="Test1" width="800px" height="200px"><p>Your browser does not support canvas.</p></canvas>

Здесь код:

this.fillTextWithSpacing = function(context, text, x, y, spacing)
{
    //Start at position (X, Y).
    //Measure wAll, the width of the entire string using measureText()
    wAll = context.measureText(text).width;

    do
    {
    //Remove the first character from the string
    char = text.substr(0, 1);
    text = text.substr(1);

    //Print the first character at position (X, Y) using fillText()
    context.fillText(char, x, y);

    //Measure wShorter, the width of the resulting shorter string using measureText().
    if (text == "")
        wShorter = 0;
    else
        wShorter = context.measureText(text).width;

    //Subtract the width of the shorter string from the width of the entire string, giving the kerned width of the character, wChar = wAll - wShorter
    wChar = wAll - wShorter;

    //Increment X by wChar + spacing
    x += wChar + spacing;

    //wAll = wShorter
    wAll = wShorter;

    //Repeat from step 3
    } while (text != "");
}

Код для теста demo/eyeball:

element1 = document.getElementById("Test1");
textContext1 = element1.getContext('2d');

textContext1.font = "72px Verdana, sans-serif";
textContext1.textAlign = "left";
textContext1.textBaseline = "top";
textContext1.fillStyle = "#000000";

text = "Welcome to go WAVE";
this.fillTextWithSpacing(textContext1, text, 0, 0, 0);
textContext1.fillText(text, 0, 100);

В идеале я бы выбрал несколько случайных строк и сравнил пиксельные пиксели. Я также не уверен, насколько хорош вернианский кернинг по умолчанию, хотя я понимаю его лучше, чем Arial - предложения по другим шрифтам, чтобы с благодарностью принять его.

Итак... пока это выглядит хорошо. На самом деле это выглядит идеально. Все еще надеясь, что кто-то укажет на любые недостатки в этом процессе.

В то же время я поставлю это для других, чтобы посмотреть, ищут ли они решение по этому вопросу.

Ответ 7

На самом деле понятие холста для буквенного интервала не поддерживается.

Итак, я использовал javascript для этого.

var value = $('#sourceText1').val().split("").join(" ");

ИЛИ

var sample_text = "Praveen Chelumalla";
var text = sample_text.split("").join(" ");

Ответ 8

Я не знаю других людей, но я изменил межстрочный интервал, увеличив значение y в тексте, который я пишу. Я на самом деле разбить строку на пробелы и пинаю каждое слово вниз по строке внутри цикла. Числа, которые я использую, основаны на шрифте по умолчанию. Если вы используете другой шрифт, эти цифры, возможно, придется скорректировать.

// object holding x and y coordinates
var vectors = {'x':{1:100, 2:200}, 'y':{1:0, 2:100}
// replace the first letter of a word
var newtext = YOURSTRING.replace(/^\b[a-z]/g, function(oldtext) {
    // return it uppercase
    return oldtext.toUpperCase(); 
});
// split string by spaces
newtext = newtext.split(/\s+/);

// line height
var spacing = 10 ;
// initial adjustment to position
var spaceToAdd = 5;
// for each word in the string draw it based on the coordinates + spacing
for (var c = 0; c < newtext.length; c++) {
    ctx.fillText(newtext[c], vectors.x[i], vectors.y[i] - spaceToAdd);
    // increment the spacing 
    spaceToAdd += spacing;
}               

Ответ 9

Расстояние между буквами в холсте ПОДДЕРЖИВАЕТСЯ, я использовал это

canvas = document.getElementById('canvas');
canvas.style.letterSpacing = '2px';

Ответ 10

Я использую:

ctx.font = "32px Tahoma";//set font
ctx.scale(0.75,1);//important! the scale
ctx.fillText("LaFeteParFete test text", 2, 274);//draw
ctx.setTransform(1,0,0,1,0,0);//reset transform