【问题标题】:Konva.TextPath doesn't render whole textKonva.TextPath 不呈现整个文本
【发布时间】:2021-04-23 13:40:12
【问题描述】:

晚安,读者。

我正在使用 Konva.TextPath 来创建弯曲的文本。我正在根据文本长度和角度计算路径,它应该是弯曲的(例如,从 270 到 90 是半弯曲,从 0 到 359,几乎是它自己的圆)。当我将路径传递给 Konva.Path 时,它可以完美地绘制,但是使用 TextPath(在某些情况下)它会呈现没有最后一个字母和错误的字母间距。我在 github 上看到过this issue,但我不确定这是否是同一个问题。

你可以看到附加的图片,它的路径 你可以在codesandbox上找到计算方法

如果需要更多信息,请询问。

谢谢。

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

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

【问题讨论】:

  • 沙盒的链接已损坏。绘制文本路径时是否不存在您要使用的字体?
  • 抱歉,我马上更新。它是默认字体,使用自定义字体更显眼
  • 链接现在有效。嗯,很奇怪,看起来问题在“低弯”时最严重。

标签: konvajs


【解决方案1】:

这不是答案,而是提供一些关于潜在 DIY 解决方案的见解,以备不时之需。

一般来说,路径上的文本算法在概念上很简单,但实现起来有点麻烦。 Konva 为您提供与此任务相关的原始 HTML5 画布命令相同的功能,因此无需放弃 Konva。

概念是

  1. 有路径和字符串;
  2. 获得直线位置 字符串中的字符(考虑字距调整以令人愉悦 间距) - 很容易实现;
  3. 找到每个字符在路径上的位置 应该开始和结束 - 不是那么容易;
  4. 绘制文本。

复杂的步骤是 3,因为无法预测路径。它“可能”是一条直线、一个圆或一个椭圆,但你必须假设一个不可预知的疯狂锯齿状的东西。

为了简单起见,我忽略了任何对齐或额外的字符填充。

对于每个字符,您将知道要绘制的起点 (x, y) - 这是第一个字符路径的起点,也是字符串中每个后续字符的前一个字符的终点。知道起点就好了,现在要找到字符空间的终点。

现在需要快速讨论一下 path.getPointAtLength() 方法。画布知道您要求它绘制的任何路径的长度,并且您可以向它询问沿该路径的任何距离的 (x, y) 点(Konva 源代码有这方面的代码 - 这是一个有趣的阅读!)。因此,给定一条长度为 100 的路径,您可以使用 path.getPointAtLength(42) 请求长度为 42 的 (x, y) 点,Konva 会告诉您。

那又怎样?我们可以用它去钓曲线上的角色终点。

您将需要一个算法来执行此操作:

  1. 对长度进行初步猜测 - 类似于字符开头的长度 + 此字符宽度是合理的。
  2. 询问路径上该位置的点。
  3. 计算字符起点和该点之间的点-点直线长度。
  4. 如果路径是弯曲的/弯曲的,那么这个长度将是
  5. 重复步骤 2-4,每次按增量调整长度。

你想要的是一种二分法,这样你的步数每次都会减少,从而在某个时候达到完美。虽然您应该定义一个容差,以便在找到足够接近的点时放弃。

请记住,您在这里所做的是感觉路径上您要绘制的角色的终点看起来合理的点。

一旦你有了角色的位置,你就可以做更多的数学运算来计算出每个角色的旋转角度和左上角的位置。然后就可以输出文本了。

如果您需要对齐或字符间距,您可以在运行主算法后轻松添加这些功能。

my blog 上有一篇类似的博文。

玩得开心。

【讨论】:

  • 感谢您的回答,我会深入研究的!
【解决方案2】:

看起来Konva.TextPath的渲染逻辑并不完美,所以它的字母间距不一致。

关于丢失的最后一个字母。您将文本宽度计算为

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

对于直 Konva.Text,这是一个正确的解决方案,但 Konva.Path 在通过指定路径渲染时使用近似值。因此生成的文本可能需要更大的长度。所以最后一个字母没有空格。作为解决方法,您可以稍微增加textLength。例如通过添加textNode.fontSize()

【讨论】:

  • 感谢您的回答。我尝试了该解决方案,也尝试添加随机数,例如长度的 10%,但仍然面临一些不好的情况。其中一种情况是文本不能被圈出。作为字母的解决方法,我正在检查原始文本和 glyphinfo 长度,如果它们不同,我将使用 + 1 更改范围,因此它不会呈现没有字母的文本。我知道这也不是很好的解决方案,有没有其他方法可以影响计算?
猜你喜欢
  • 1970-01-01
  • 2022-06-30
  • 2015-05-07
  • 1970-01-01
  • 2011-03-27
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2015-11-12
相关资源
最近更新 更多