Konva.textPath не отображает весь текст целиком

#konvajs

#конвайс

Вопрос:

Добрый день, читатель.

Я использую Konva.textPath для создания изогнутого текста. Я вычисляю путь на основе длины текста и угла, под которым он должен быть изогнут (например, от 270 до 90 наполовину изогнут, 359 от 0, это почти сам круг). Когда я передаю path в Konva.Path, он отлично рисуется, но с помощью textPath (в некоторых случаях) он отображает без последних букв и с неправильными интервалами между буквами. Я видел эту проблему на github, но я не уверен, что это та же проблема.

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

Если требуется дополнительная информация, пожалуйста, спросите.

Спасибо.

 Path 1
M6.587352859507078 6.779702002611884,
A665.1292665214339, 665.1292665214339, 0, 0, 0, 271.78815041484745 4.465329704342594 
 

Путь 1 :

 Path 2
M8.968283494812425 14.597383097232182,
A993.126844893427, 993.126844893427, 0, 0, 0, 268.2165426505044 12.334957814595896
 

Путь 2 :

Комментарии:

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

2. Извините, я обновлю его сейчас. Это шрифт по умолчанию, с пользовательскими шрифтами он намного заметнее

3. Ссылка теперь работает. Хммм, очень странно, похоже, что проблема хуже всего при «низком изгибе».

Ответ №1:

Это не ответ, но дает некоторое представление о потенциальном самостоятельном решении на случай, если оно вам понадобится.

В общем, алгоритм для текста в пути концептуально прост, но его реализация немного сложна. Konva предоставляет вам те же возможности, что и необработанные команды HTML5 canvas в отношении этой задачи, поэтому нет необходимости отказываться от Konva.

Концепция

  1. есть путь и строка;
  2. получить прямолинейное размещение символов в строке (учитывает пары кернингов, чтобы обеспечить приятный интервал) — легко достигается;
  3. найти позицию на пути, где должен начинаться и заканчиваться каждый символ — не так просто;
  4. нарисуйте текст.

Сложный шаг равен 3, потому что нет способа предсказать путь. Это «может» быть прямая линия, или круг, или эллипс, но вы должны предположить непредсказуемую безумную зубчатую петлю.

Я игнорирую любое выравнивание или дополнительное заполнение символов, чтобы упростить задачу.

Для каждого символа вы будете знать начальную точку (x, y) для рисования — это начало пути для первого символа и конечная точка предыдущего символа для каждого последующего символа в строке. Знание начальной точки — это хорошо, теперь вам нужно найти конечную точку символьного пространства.

Теперь требуется краткое обсуждение метода path.getPointAtLength(). Холст знает длину любого пути, который вы попросите его нарисовать, и вы можете задать ему точку (x, y) для любого расстояния вдоль этого пути (в исходном коде Konva есть код для этого — это интересное чтение!). Итак, учитывая путь длиной, скажем, 100, вы можете запросить точку (x, y) длиной 42 с помощью path.getPointAtLength(42), и Konva вам сообщит.

Ну и что? Мы можем использовать это, чтобы найти конечную точку символа на кривой.

Вам понадобится алгоритм, который делает это:

  1. сделайте первоначальное предположение о длине — что-то вроде длины в начале символа эта ширина символа является разумной.
  2. Попросите указать точку в этой позиции на пути.
  3. Вычислите длину прямой линии от точки до точки между началом символа и этой точкой.
  4. Если путь изогнут / изогнут, то эта длина будет < ширина символа, и вам нужно повторить попытку с большим расстоянием, если вы промахнетесь, тогда идите немного короче.
  5. Повторите шаги 2-4, каждый раз регулируя длину с шагом.

То, что вам нужно, — это бинарный подход, чтобы ваши шаги сокращались каждый раз, тем самым достигая совершенства в какой-то момент. Хотя вы должны определить допуск, чтобы отказаться, когда найдена достаточно близкая точка.

Помните, что то, что вы здесь делаете, — это нащупывание точки на пути, где конечная точка символа, который вы хотите нарисовать, будет выглядеть разумно.

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

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

В моем блоге есть похожее сообщение в блоге.

Получайте удовольствие.

Комментарии:

1. Спасибо за ваш ответ, я углублюсь в него!

Ответ №2:

Похоже, логика рендеринга Konva.TextPath просто не идеальна, поэтому она имеет несогласованные интервалы между буквами.

О пропущенной последней букве. Вы вычисляете ширину текста как

 const textLength =
      textNode.getTextWidth()  
      (textNode.text().length - 1) * textNode.letterSpacing();
 

Это правильное решение для прямого Konva.Text , но Konva.Path использует приближения при рендеринге по указанному пути. Поэтому результирующий текст может занимать большую длину. Поэтому для последней буквы нет места. В качестве обходного пути вы можете немного увеличить textLength . Например, путем добавления textNode.fontSize() .

Комментарии:

1. Спасибо за ваш ответ. Я попробовал это решение, также я попытался добавить случайные числа, например, 10% длины, но все еще сталкивался с некоторыми плохими случаями. одним из таких случаев является то, что текст нельзя обвести. В качестве обходного пути для букв я проверяю исходный текст и длины глифов, если они разные, я меняю диапазон на 1, поэтому он не будет отображать текст без букв. Я знаю, что это тоже не очень хорошее решение, есть ли какой-либо другой способ повлиять на вычисления?