Drawing rotated text on HTML5 canvas

The part of the web application that I am developing requires me to create histograms to display various information. I figured if a custom browser is capable, I would draw them using the HTML5 canvas element. I have no problem drawing lines and bars for my charts, but when it comes to marking axes, bars or lines, I run into an obstacle. How to draw rotated text on a canvas element so that it aligns with the element that it marks? Examples of steam include:

  • Rotate text 90 degrees clockwise to indicate y axis
  • Rotate the text 90 degrees clockwise to label the bars vertically.
  • Rotate text with an arbitrary sum of a line of labels on a line chart

Any pointers would be appreciated.

+53
javascript html5 canvas
Jul 02 '10 at 17:45
source share
5 answers

Like so many others, you'll probably want to take a look at reusing an existing graphical solution, but text rotation is not too complicated. A slightly confusing bit (for me) is that you rotate the whole context and then draw it:

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

The angle is in radians . The code is taken from this example , which, it seems to me, was made for the conversion part in the MDC canvas tutorial .

Please see the answer below for a more complete solution.

+33
Jul 02 '10 at 18:11
source share

By doing this to help others with similar problems. I solved this problem with a five-step approach - save the context, translate the context, rotate the context, draw the text, and then restore the context to its saved state.

I think of translations and transformations into context as manipulating a grid of coordinates superimposed on a canvas. By default, the beginning (0,0) starts in the upper left corner of the canvas. X increases from left to right, Y increases from top to bottom. If you make an โ€œLโ€ with the index finger and thumb of your left hand and hold it in front of you with your finger, the thumb will point in the direction of increase Y, and the index finger will point in the direction of increase X. I know that this is elementary, but I think it is useful when thinking about translations and turns. That's why:

When you translate the context, you move the origin of the grid to a new location on the canvas. When you rotate the context, think about the โ€œLโ€ rotation that you made with your left hand in a clockwise direction, the amount indicated by the angle indicated in radians relative to the origin. When you click Text or fillText, specify your coordinates relative to the newly aligned axes. To orient the text so that it is read from bottom to top, you would translate it to the position below where you want to start your marks, rotate -90 degrees and fill or pull the Text, moving each mark along the x axis. Something like this should work:

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

.restore () resets the context back to the state it had when you called .save () - convenient for returning returned data to "normal".




+106
Mar 23 2018-11-11T00:
source share

While this is similar to the previous answer, it adds a bit (hopefully).

Basically, I want to clarify that we usually think of drawing things like draw a rectangle at 10, 3 .

So, if we think about it this way: move origin to 10, 3 , then draw rectangle at 0, 0 . Then all we need to do is add a twist between them.

Another important point is the alignment of the text. The easiest way is to draw the text at 0, 0, so using the right alignment can allow us to do this without measuring the width of the text.

We still have to move the text a size to get it centered vertically, and unfortunately the canvas does not have much support for the line height, so guess and check the thing (correct me if something is better).

I created 3 examples that provide a dot and text with three alignments to show at which actual point the font will be displayed on the screen.

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); 

String this.context.fillText('right', 0, lineHeight / 2); basically 0, 0 , except that we move a bit so that the text is centered near the point

+21
May 7 '14 at 16:49
source share

Here's an alternative to HTML5 for homegrown: http://www.rgraph.net/ Perhaps you can deploy your methods ....

You can also consider something like Flot ( http://code.google.com/p/flot/ ) or GCharts: ( http://www.maxb.net/scripts/jgcharts/include/demo/#1 ) This is not quite so cool, but completely backward compatible and scary easy to implement.

0
Jul 02 '10 at 17:57
source share

Funkodebat posted a great solution that I referred to many times. However, I find that I write my own working model every time I need it. So here is my working model ... with some extra clarity.

First of all, the height of the text is equal to the size of the pixel . Now it was something that I read some time ago, and it worked out in my calculations. I'm not sure if this works with all fonts, but it seems to work with Arial, sans-serif.

In addition, to make sure that you have placed all the text in your canvas (and not trim the tails from your "p"), you need to set context.textBaseline * .

You will see in the code that we are turning the text about its center. To do this, we need to set context.textAlign = "center" and context.textBaseline at the bottom, otherwise we will trim parts of our text.

Why resize canvas? Usually I have a canvas that does not add to the page. I use it to draw all my rotated text, then draw it on another canvas, which I will show. For example, you can use this canvas to draw all the labels for the chart (one after another) and draw a hidden canvas on the chart canvas where you need the label ( context.drawImage(hiddenCanvas, 0, 0); ).

IMPORTANT NOTE! Set the font before measuring the text and reapply your whole style to the context after resizing the canvas. The canvas context is completely reset when the canvas is resized.

Hope this helps!

 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;"> 
0
Jul 27 '18 at 15:21
source share



All Articles