HTML5画布fillText如何处理从右到左的字符串

9
我正在尝试使用fillText()方法在HTML5画布的2d上下文中绘制用阿拉伯文写的字符串。它完美地工作,直到我在字符串末尾放一个标点符号。然后,标点符号出现在字符串的错误一侧(在开头而不是结尾,就像是ltr而不是rtl字符串)。我尝试了Context.textAlign属性,但它似乎只涉及字符串相对于指定位置的绘制方式,而不涉及文本实际方向。有人知道解决这个问题的方法吗?
谢谢。
更新:我发现的答案是在页面的canvas元素上添加一个“dir”属性。例如,
<canvas dir="rtl">

然而,我仍然不知道如何更改发送到fillText的单个字符串的dir属性。有什么想法吗?

抱歉提前发言。我在规范中找到了解决方案:http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#the-directionality显然,必须将canvas元素上的“dir”属性设置为“rtl”,即“<canvas dir =“rtl”>”。 - user1145886
请将您的解决方案添加为答案。谢谢! - Adam Lear
你使用什么字体?这个字体的名字是什么? - Zelter Ady
4个回答

10

您不需要为每个单独的字符串设置方向。请参阅以下示例,其中还展示了正确使用隐式双向控制符以获取正确的显示顺序:

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>

  <body>
    <canvas id="myCanvas" width="700" dir="rtl" height="250" style="border:1px solid #d3d3d3;">
      Your browser does not support the HTML5 canvas tag.
    </canvas>

    <script type="text/javascript" charset="utf-8">
      var c = document.getElementById("myCanvas");
      var cArabic = c.getContext("2d");
      cArabic.font="25px Arial";

      // Simple Sentence with punctuation.
      var str1 = "این یک آزمایش است.";
      // Few sentences with punctuation and numerals. 
      var str2 = "۱ آزمایش. 2 آزمایش، سه آزمایش & Foo آزمایش!";
      // Needs implicit bidi marks to display correctly.
      var str3 = "آزمایش برای Foo Ltd. و Bar Inc. باشد که آزموده شود.";
      // Implicit bidi marks added; "Foo Ltd.&lrm; و Bar Inc.&lrm;"
      var str4 = "آزمایش برای Foo Ltd.‎ و Bar Inc.‎ باشد که آزموده شود.";

      cArabic.fillText(str1, 600, 60);
      cArabic.fillText(str2, 600, 100);
      cArabic.fillText(str3, 600, 140);
      cArabic.fillText(str4, 600, 180);
    </script>

  </body>
</html>

这里是输出结果:由Chrome <code>26.0.1410.64 m</code>在MS Windows XP SP3上渲染的样子


你是否知道如何在画布上逐个绘制阿拉伯字母时进行连接? - sq1020
这应该对开发人员透明。文本布局引擎应该处理它。您有任何特定的情况,它不起作用吗? - Shervin
我采用的方法类似于这个:https://dev59.com/hGsz5IYBdhLWcg3wxq4V -- 从概念上讲,第一个解决方案很好,但是当使用阿拉伯字母时,在这种情况下它们不会连接,因为您是针对每个字母调用context.fillText而不是整个字符串。 - sq1020
我明白了。那个解决方法在整体连接脚本(其中包括阿拉伯语)方面并不具备概念上的可行性。如果非常关键,您可以模仿连接行为,并将每个连接字形运行单独以一种颜色着色(这有点重新发明文本呈现引擎的某些部分)。 - Shervin

4
问题在于'.'字符是一个'directional neutral character',这意味着它的方向来自下一个强定向字符,如果没有字符紧随其后,则从容器获取。在您的情况下,它是后者。一种解决方法是使容器从右到左。但还有另外两个解决方案:
1- 在'.'之后放置另一个不可见的强制从右到左的定向字符。幸运的是,unicode有一个特殊字符,即“从右到左标记”(U+200F)。
2- 在文本之前放置“right-to-left override character”(U+202E),因此在此标记后,任何中性字符都会得到从右到左的方向。您可以通过添加“pop directional formatting”字符(U+202C)来结束覆盖。
我已更改@shervin的示例代码以进行演示。
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>

  <body>
    <canvas id="myCanvas" width="700" height="250" style="border:1px solid #d3d3d3;">
      Your browser does not support the HTML5 canvas tag.
    </canvas>

    <script type="text/javascript" charset="utf-8">
      var c = document.getElementById("myCanvas");
      var cArabic = c.getContext("2d");
      cArabic.font="20px Arial";

      //option 1 : adding right-to-left mark at the end to put the '.' between two strong right to left charachters, so it will treated as right to left.
      var str1 = "این یک آزمایش است." + "\u200F";

      //option 2 : adding right-to-left override at the begining of the text so every neutral charachter afterward becomes righ to left.
      var str2;
      str2 = "\u202E";
      str2+= "این یک آزمایش است.";
      //           you might want to finish the override by 'pop directional formatting' charachter
      str2 += "\u202C";

      cArabic.fillText(str1, 200, 30);
      cArabic.fillText(str2, 200, 70);
    </script>

  </body>
</html>

结果图像

还有其他解决方案。您可以在 Unicode 规范的这个页面中找到它们。它们是“方向隔离”(U+2067),在 Chrome 中存在渲染问题。还有一个类似于方向覆盖的“方向嵌入”,使用 U+202B。


3

设置dir选项是针对整个画布的 - 对于行为不良的单个字符串,您可以考虑在引号后手动添加RTL标记(U+200F)。


请问您能否详细说明或举个例子来说明如何完成这个任务? - omerkarj
"אבג" + "\u200F"; 的例子: - elad gasner

0
你可以使用以下代码实现:
ctx.textAlign="end";
或者
ctx.textAlign="right";

如果需要再次从左到右排列:
ctx.textAlign="start";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接