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

Рисование повернутого текста на холсте HTML5

Часть веб-приложения, которое я разрабатываю, требует от меня создания гистограмм для отображения различной информации. Я полагал, что если пользовательский браузер способен, я бы рисовал их с помощью элемента canvas HTML5. У меня нет проблем с рисованием линий и баров для моих графиков, но когда дело доходит до маркировки осей, баров или линий, я столкнулся с препятствием. Как рисовать повернутый текст на элемент холста так, чтобы он выравнивался с элементом, который он маркирует? Примеры пара включают:

  • Повернуть текст на 90 градусов по часовой стрелке для обозначения оси y
  • Повернуть текст на 90 градусов по часовой стрелке для маркировки полос по вертикали гистограмма
  • Поворот текста произвольной суммой строки меток на линейном графике

Любые указатели будут оценены.

4b9b3361

Ответ 1

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

ctx.rotate(Math.PI*2/(i*6));

Угол находится в радианах. Код берется из этого примера, который, как мне кажется, был сделан для части преобразования в учебнике холста MDC.

Пожалуйста, см. Ответ ниже для более полного решения.

Ответ 2

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

Я думаю о переводах и преобразованиях в контекст как манипулирование сеткой координат, наложенной на холст. По умолчанию начало (0,0) начинается в верхнем левом углу холста. X увеличивается слева направо, Y увеличивается сверху вниз. Если вы делаете "L" с указательным пальцем и большим пальцем левой руки и удерживаете его перед собой пальцем, большой палец будет указывать в направлении увеличения Y, а указательный палец будет указывать в направлении возрастания X. Я знаю, что это элементарно, но я считаю это полезным, когда размышляю о переводах и поворотах. Вот почему:

Когда вы переводите контекст, вы перемещаете начало сетки координат в новое место на холсте. Когда вы поворачиваете контекст, подумайте о вращении "L", который вы сделали левой рукой по часовой стрелке, количество, указанное углом, указанным в радианах относительно начала координат. Когда вы нажимаетеText или fillText, указываете свои координаты относительно вновь выровненных осей. Чтобы ориентировать текст так, чтобы он читался снизу вверх, вы переводили бы в позицию ниже, где вы хотите начать свои метки, поверните на -90 градусов и заполните или потянитеText, смещая каждую метку вдоль оси x. Что-то вроде этого должно работать:

 context.save();
 context.translate(newx, newy);
 context.rotate(-Math.PI/2);
 context.textAlign = "center";
 context.fillText("Your Label Here", labelXposition, 0);
 context.restore();

.restore() сбрасывает контекст обратно в состояние, которое оно имело, когда вы вызывали .save() - удобно для возвращения возвращаемых данных к "нормальным".


Ответ 3

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

В основном я хочу уточнить, что обычно мы думаем рисовать такие вещи, как draw a rectangle at 10, 3.

Итак, если мы подумаем об этом так: move origin to 10, 3, тогда draw rectangle at 0, 0. Тогда все, что нам нужно сделать, это добавить поворот между ними.

Другим важным моментом является выравнивание текста. Проще всего нарисовать текст в 0, 0, поэтому использование правильного выравнивания может позволить нам сделать это без измерения ширины текста.

Мы должны по-прежнему перемещать текст на величину, чтобы получить ее по центру по вертикали, и, к сожалению, холст не имеет большой поддержки высоты линии, так что угадайте и проверяйте вещь (исправьте меня, если что-то лучше).

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

enter image description here

var font, lineHeight, x, y;

x = 100;
y = 100;
font = 20;
lineHeight = 15; // this is guess and check as far as I know
this.context.font = font + 'px Arial';


// Right Aligned
this.context.save();
this.context.translate(x, y);
this.context.rotate(-Math.PI / 4);

this.context.textAlign = 'right';
this.context.fillText('right', 0, lineHeight / 2);

this.context.restore();

this.context.fillStyle = 'red';
this.context.fillRect(x, y, 2, 2);


// Center
this.context.fillStyle = 'black';
x = 150;
y = 100;

this.context.save();
this.context.translate(x, y);
this.context.rotate(-Math.PI / 4);

this.context.textAlign = 'center';
this.context.fillText('center', 0, lineHeight / 2);

this.context.restore();

this.context.fillStyle = 'red';
this.context.fillRect(x, y, 2, 2);


// Left
this.context.fillStyle = 'black';
x = 200;
y = 100;

this.context.save();
this.context.translate(x, y);
this.context.rotate(-Math.PI / 4);

this.context.textAlign = 'left';
this.context.fillText('left', 0, lineHeight / 2);

this.context.restore();

this.context.fillStyle = 'red';
this.context.fillRect(x, y, 2, 2);

Строка this.context.fillText('right', 0, lineHeight / 2); в основном 0, 0, за исключением того, что мы немного двигаемся, чтобы текст был центрирован вблизи точки

Ответ 4

Здесь альтернатива HTML5 для доморощенного: http://www.rgraph.net/ Возможно, вы сможете развернуть свои методы....

Вы также можете рассмотреть что-то вроде Flot (http://code.google.com/p/flot/) или GCharts: (http://www.maxb.net/scripts/jgcharts/include/demo/#1) Это не совсем так здорово, но полностью обратно совместимо и страшно легко реализовать.

Ответ 5

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

Прежде всего, высота текста равна размеру пикселя. Теперь это было кое-что, что я прочитал некоторое время назад, и это получилось в моих расчетах. Я не уверен, что это работает со всеми шрифтами, но, похоже, работает с Arial, sans-serif.

Кроме того, чтобы убедиться, что вы поместили весь текст в свой холст (и не обрезаете хвосты с вашего "p"), вам нужно установить context.textBaseline *.

Вы увидите в коде, что мы поворачиваем текст о его центре. Для этого нам нужно установить context.textAlign = "center" и context.textBaseline снизу, иначе мы обрезаем части нашего текста.

Зачем изменять размер холста? Обычно у меня есть холст, который не добавляется к странице. Я использую его, чтобы нарисовать весь мой повернутый текст, затем нарисую его на другой холст, который я покажу. Например, вы можете использовать этот холст, чтобы нарисовать все метки для диаграммы (один за другим) и нарисовать скрытый холст на холсте диаграммы, где вам нужна метка (context.drawImage(hiddenCanvas, 0, 0);).

ВАЖНОЕ ПРИМЕЧАНИЕ. Установите шрифт перед измерением текста и повторно примените весь свой стиль к контексту после изменения размера холста. Контекст холста полностью сбрасывается при изменении размера холста.

Надеюсь это поможет!

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var font, text, x, y;

text = "Mississippi";

//Set font size before measuring
font = 20;
ctx.font = font + 'px Arial, sans-serif';
//Get width of text
var metrics = ctx.measureText(text);
//Set canvas dimensions
c.width = font;//The height of the text. The text will be sideways.
c.height = metrics.width;//The measured width of the text
//After a canvas resize, the context is reset. Set the font size again
ctx.font = font + 'px Arial';
//Set the drawing coordinates
x = font/2;
y = metrics.width/2;
//Style
ctx.fillStyle = 'black';
ctx.textAlign = 'center';
ctx.textBaseline = "bottom";
//Rotate the canvas and draw the text
ctx.save();
ctx.translate(x, y);
ctx.rotate(-Math.PI / 2);
ctx.fillText(text, 0, font / 2);
ctx.restore();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">