我正在开发的Web应用程序的一部分要求我创建条形图以显示各种信息。我认为,如果用户的浏览器具有功能,则可以使用HTML5 canvas元素绘制它们。我可以为图形绘制线条和条形没有问题,但是在标注轴,条形或线形标签时遇到了障碍。如何将旋转的文本绘制到画布元素上,使其与要标记的项目对齐?几个示例包括:
- 逆时针旋转文本90度以标记y轴
- 逆时针旋转文本90度以在垂直条形图上标记条形
- 任意旋转文本以标记折线图上的线
任何指针将不胜感激。
我正在开发的Web应用程序的一部分要求我创建条形图以显示各种信息。我认为,如果用户的浏览器具有功能,则可以使用HTML5 canvas元素绘制它们。我可以为图形绘制线条和条形没有问题,但是在标注轴,条形或线形标签时遇到了障碍。如何将旋转的文本绘制到画布元素上,使其与要标记的项目对齐?几个示例包括:
任何指针将不胜感激。
Answers:
发布此信息是为了帮助有类似问题的其他人。我通过五步方法解决了这个问题-保存上下文,转换上下文,旋转上下文,绘制文本,然后将上下文恢复为其保存状态。
我认为翻译和转换为上下文是操纵覆盖在画布上的坐标网格。默认情况下,原点(0,0)从画布的左上角开始。X从左到右增加,Y从上到下增加。如果您用左手的食指和拇指做一个“ L”,并在您的拇指向下的情况下将其伸出在您的面前,则拇指将指向增加Y的方向,而食指将指向该方向我知道它是基本的,但在考虑平移和旋转时会有所帮助。原因如下:
翻译上下文时,将坐标网格的原点移动到画布上的新位置。旋转上下文时,请考虑将用左手制作的“ L”沿顺时针方向旋转,以您指定的弧度(相对于原点)的角度表示的数量。当您描边文本或填充文本时,请指定相对于新对齐的轴的坐标。要调整文本的方向以便从下到上可读,您可以将其转换为要在其下方开始标签的位置,旋转-90度并填充或strokeText,使每个标签沿旋转的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()时的状态-方便将内容恢复为“正常”状态。
context.rotate(angle * (Math.PI / 180));
-Math.PI / 2.0
上面的旋转代码使您的文本逆时针旋转...大概很多人都想这样做,以便在图形的左侧绘制垂直文本,所以...:移至底部在图形的左上角(不进行填充或其他操作),进行-Math.PI / 2.0
旋转,以X位置(旋转时为垂直)在图形中心Y处居中绘制,Y位置的文本大小为负一半。(您也可以事先翻译一个额外的正半个文本大小,但这更容易理解imo。)
虽然这是对上一个答案的跟进,但它(希望)有所增加。
我主要要澄清的是,通常我们会想到绘制类似 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
,除了我们稍微移动以使文本居中于该点附近
Funkodebat发布了一个很棒的解决方案,我已经引用了很多次。尽管如此,我发现自己每次需要时都编写自己的工作模型。所以,这是我的工作模型……更加清晰了。
首先,文字的高度等于像素字体大小。现在,这是我前一段时间阅读的内容,并且已经在我的计算中得出。我不确定这是否适用于所有字体,但似乎可以与无衬线Arial一起使用。
另外,要确保您适合画布中的所有文本(并且不修剪“ 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;">
这是HTML5替代自制软件的方法:http : //www.rgraph.net/ 您可能可以对它们的方法进行反向工程...。
您可能还会考虑使用Flot(http://code.google.com/p/flot/)或GCharts:(http://www.maxb.net/scripts/jgcharts/include/demo/#1)之类的东西相当酷,但是完全向后兼容并且易于实现。