在 HTML5 画布上绘制旋转文本
Posted
技术标签:
【中文标题】在 HTML5 画布上绘制旋转文本【英文标题】:Drawing rotated text on a HTML5 canvas 【发布时间】:2011-03-11 05:20:41 【问题描述】:我正在开发的 Web 应用程序的一部分要求我创建条形图来显示各种信息。我想,如果用户的浏览器有能力,我会使用 html5 画布元素来绘制它们。我为我的图表绘制线条和条形图没有问题,但是在标记轴、条形图或线条时,我遇到了障碍。如何将旋转的文本绘制到画布元素上,使其与正在标记的项目对齐?几个例子包括:
逆时针旋转文本 90 度 顺时针标记 y 轴 逆时针旋转文本 90 度 顺时针标记垂直条形 条形图 将文本任意旋转到 在折线图上标注线条任何指针将不胜感激。
【问题讨论】:
您是否考虑过研究现有的图形解决方案而不是尝试构建自己的解决方案? flot (code.google.com/p/flot) 是一个使用画布的例子。 【参考方案1】: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 context 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;">
【讨论】:
【参考方案2】:就像其他人提到的那样,您可能希望重用现有的图形解决方案,但旋转文本并不太难。 (对我来说)有点令人困惑的是,您旋转了整个上下文,然后在上面绘制:
ctx.rotate(Math.PI*2/(i*6));
angle is in radians。代码是taken from this example,我相信它是为transformations part of the MDC canvas tutorial 制作的。
请参阅the answer below 以获得更完整的解决方案。
【讨论】:
radians = (angle * Math.PI / 180)
【参考方案3】:
虽然这是对上一个答案的跟进,但它增加了一点(希望如此)。
我主要想澄清的是,通常我们会想到画draw a rectangle at 10, 3
之类的东西。
所以如果我们这样想:move origin to 10, 3
,然后是draw rectangle at 0, 0
。
然后我们要做的就是在两者之间添加一个旋转。
另一个重点是文本的对齐方式。在 0、0 处绘制文本是最简单的,因此使用正确的对齐方式可以让我们在不测量文本宽度的情况下做到这一点。
我们仍然应该将文本移动一定量以使其垂直居中,不幸的是画布没有很好的行高支持,所以这是一个猜测和检查的东西(如果有更好的东西请纠正我)。
我创建了 3 个示例,它们提供了一个点和一个具有 3 种对齐方式的文本,以显示屏幕上的实际点是字体所在的位置。
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】:发布此内容是为了帮助其他有类似问题的人。我通过五步方法解决了这个问题——保存上下文、翻译上下文、旋转上下文、绘制文本,然后将上下文恢复到保存状态。
我认为对上下文的翻译和转换是对覆盖在画布上的坐标网格的操作。默认情况下,原点 (0,0) 从画布的左上角开始。 X从左到右增加,Y从上到下增加。如果你用左手的食指和拇指做一个“L”,然后用拇指向下把它放在你面前,你的拇指会指向 Y 增加的方向,你的食指会指向这个方向增加 X。我知道这是基本的,但在考虑平移和旋转时我发现它很有帮助。原因如下:
翻译上下文时,会将坐标网格的原点移动到画布上的新位置。当您旋转上下文时,请考虑以顺时针方向旋转您用左手制作的“L”,旋转量由您以弧度指定的关于原点的角度表示。当您 strokeText 或 fillText 时,指定与新对齐的轴相关的坐标。要调整文本的方向,使其从下到上可读,您可以平移到要开始标签的位置下方,旋转 -90 度并填充或描边文本,沿旋转的 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() 时的状态——方便将事物恢复为“正常”。
【讨论】:
很好的翻译/旋转解释。 +1 如果你想将角度设置为特定的东西,你可以这样做:context.rotate(angle * (Math.PI / 180));
为了进一步澄清......:上面的-Math.PI / 2.0
旋转代码逆时针旋转你的文本......大概很多人都想做这一切来在左侧绘制垂直文本图形,所以...:平移到图形的左下角(没有填充或任何东西),这样做-Math.PI / 2.0
旋转,以图形的中心 Y 为中心绘制 X 位置(当旋转)和负一半的 Y 位置的文本大小。 (您也可以事先将文本大小的一半翻译成正数,但这更容易理解 imo。)
就个人而言,我不需要翻译,但同样感谢!【参考方案5】:
这里有一个 HTML5 替代 homebrew:http://www.rgraph.net/ 你也许可以对他们的方法进行逆向工程......
您也可以考虑使用 Flot (http://code.google.com/p/flot/) 或 GCharts:(http://www.maxb.net/scripts/jgcharts/include/demo/#1) 它不是很酷,但完全向后兼容且易于实现。
【讨论】:
以上是关于在 HTML5 画布上绘制旋转文本的主要内容,如果未能解决你的问题,请参考以下文章