HTML5 Canvas fillText со строкой справа налево

Я пытаюсь использовать метод fillText() в 2d-контексте холста HTML5, чтобы нарисовать строку, написанную на арабском языке. Он работает отлично, пока я не поставлю знак препинания в конце строки. Затем знак препинания появляется не на той стороне строки (в начале, а не в конце, как если бы это была строка ltr, а не rtl). Я играл со свойством Context.textAlign, но, похоже, это касается только того, как строка рисуется относительно указанной позиции, а не фактического направления текста. Кто-нибудь знает решение этого?

Спасибо.

Обновление: ответ, который я нашел, состоит в том, чтобы добавить атрибут "dir" к элементу холста на странице. Например,

<canvas dir="rtl">

Однако я до сих пор не знаю, как изменить атрибут dir для отдельных строк, отправляемых в fillText. Любые идеи?


person user1145886    schedule 22.01.2012    source источник
comment
Извините, что поторопился. Я нашел решение в спецификации: whatwg.org/specs/web-apps/current-work/multipage/ Очевидно, нужно установить элемент dir на холсте в rtl, т.е. ‹canvas dir=rtl›.   -  person user1145886    schedule 22.01.2012
comment
Пожалуйста, добавьте свое решение в качестве ответа. Спасибо!   -  person Adam Lear    schedule 23.01.2012
comment
какой шрифт вы используете? Как называется шрифт?   -  person Zelter Ady    schedule 03.04.2012


Ответы (4)


Вам не нужно устанавливать направление для каждой отдельной строки. См. следующий пример, который также показывает правильное использование неявных меток управления двунаправленным текстом для правильного порядка отображения:

<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

person Shervin    schedule 12.04.2013
comment
Вы случайно не знаете, как соединить арабские буквы, если рисуете их по одной на холсте? - person sq1020; 01.10.2013
comment
Это должно быть прозрачно для разработчика. Механизм компоновки текста должен позаботиться об этом. У вас есть какой-то конкретный сценарий, когда это не работает? - person Shervin; 01.10.2013
comment
Подход, который я использую, аналогичен следующему: stackoverflow.com/questions/7665342/ -- Концептуально первое решение работает хорошо, но при использовании арабских букв в этом случае они не соединяются, потому что вы повторный вызов context.fillText один раз для каждой буквы вместо всей строки. - person sq1020; 02.10.2013
comment
Я понимаю. Этот обходной путь концептуально не работает для объединения сценариев в целом (одним из них является арабский). Если это очень важно, вы можете имитировать поведение соединения и окрашивать каждый соединяющийся ряд форм букв отдельно в один цвет (что является своего рода переизобретением некоторой части механизма рендеринга текста). - person Shervin; 02.10.2013

Установка параметра dir предназначена для всего холста — для отдельных строк, которые ведут себя плохо, вы можете вручную добавить маркер RTL (U+200F) после кавычки.

person Ansari    schedule 06.05.2012
comment
не могли бы вы уточнить или привести пример того, как это делается? - person omerkarj; 07.04.2016
comment
пример: אבג + ‏; - person elad gasner; 22.05.2018

Проблема в том, что '.' символ является «направленным нейтральным символом», это означает, что он получает направление от следующего сильно направленного символа, если после него нет символа, он получает его из контейнера. В вашем случае это последний. Одно из решений, как уже было найдено, состоит в том, чтобы сделать контейнер справа налево. Но есть еще два решения:

1- Поместите еще один невидимый сильный символ направления справа налево после '.'. К счастью, в юникоде есть один специальный символ для «метки справа налево» (U+200F).

2- Поместите «символ переопределения справа налево» (U + 202E) перед текстом, чтобы после этой отметки любой нейтральный символ получил направление справа налево. Вы можете завершить переопределение, добавив символ «всплывающее направленное форматирование» (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, что похоже на переопределение направления.

person karianpour    schedule 14.04.2018

Вы можете сделать это следующим образом:
ctx.textAlign="end";
или
ctx.textAlign="right"

И чтобы снова сделать это слева направо:
ctx.textAlign="start";

person mansim    schedule 28.01.2018