Drawing Rotated Text on a HTML5 Canvas

Drawing rotated text on a HTML5 canvas

Like others have mentioned, you probably want to look at reusing an existing graphing solution, but rotating text isn't too difficult. The somewhat confusing bit (to me) is that you rotate the whole context and then draw on it:

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

The angle is in radians. The code is taken from this example, which I believe was made for the transformations part of the MDC canvas tutorial.

Please see the answer below for a more complete solution.

HTML5 rotate text around it's centre point

Here's one way:

  • Use textAlign & textBaseline to draw the text at it's horizontal and vertical center:

  • translate to the x,y where you want the text centered.

  • rotate by the desired angle

  • And finally fillText

Sample Image

Example code and a Demo: http://jsfiddle.net/m1erickson/uL62et9y/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var cw=canvas.width;
var ch=canvas.height;

ctx.beginPath();
ctx.moveTo(cw/2,0);
ctx.lineTo(cw/2,ch);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0,ch/2);
ctx.lineTo(cw,ch/2);
ctx.stroke();

ctx.save();

ctx.textAlign="center";
ctx.textBaseline="middle";

ctx.translate(150,150);
ctx.rotate(Math.PI/2);
ctx.fillText("Hello World!",0,0);

ctx.restore();

}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

How can I rotate this text in canvas html5?

When measuring text, you need to set font before measuring text.

When rotating around point (ex. middle of text) that is not origin, you need to translate, rotate, translate.

In your code, try replacing...

  if (i * sa > Math.PI / 2 && i * sa < 1.5 * Math.PI) {
//here's the edited part where I tried to rotate the text in place
ctx.translate(-ctx.measureText(l).width,d.width*(18/1000)/2);
ctx.rotate(Math.PI);
//end of edited part
ctx.translate(d.cX, d.cY);
ctx.rotate((10 - i) * sa);
ctx.font = font;
ctx.fillStyle = orange;
ctx.fillText(l, 10.5 * d.radius, 5);
} else {

with...

  if (i * sa > Math.PI / 2 && i * sa < 1.5 * Math.PI) {
ctx.translate(d.cX, d.cY);
ctx.rotate((10 - i) * sa);
ctx.font = font;
ctx.translate(10.5 * d.radius + ctx.measureText(l).width / 2, 0);
ctx.rotate(Math.PI);
ctx.translate(-10.5 * d.radius - ctx.measureText(l).width / 2, 0);
ctx.fillStyle = orange;
ctx.fillText(l, 10.5 * d.radius, 5);
} else {

Rotate text in a canvas with javascript

Have made some changes in your code, it should help:

<html>
<canvas id="myCanvas" width="300" height="300" style="border:1px solid

#d3d3d3;"></canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var x = new Array("Day1","Day2","Day3","Day4","Day5");
for(var i = 0; i < x.length; i++){
var size = ctx.measureText(x[i]);
ctx.save();
var tx = (i*50+20) + (size.width/2);
var ty = (50);
ctx.translate(tx,ty);
ctx.rotate(Math.PI / 10);
ctx.translate(-tx,-ty);
ctx.fillText(x[i],i*50+20,50);
ctx.restore();
}
</script>
</html>

HTML5 canvas - text on rotated rectangle

You're drawing the text first, then the rectangle, and then wondering why the text is behind the rectangle?

Firstly, you only need to getContext once, not twice.

Second, draw things in the right order: background first, then foreground.

Text Rotation HTML 5 Canvas

A simple code to rotate text could look like this - adopt as needed:

var ctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
cx = w * 0.5, // center of canvas
cy = h * 0.5,
angleStep = 0.1,
txt = 'PINWHEEL TEXT';

ctx.font = 'bold 30px sans-serif'; // set font
ctx.textAlign = 'center'; // align text in center
ctx.textBaseline = 'middle';

(function rotate() {
ctx.clearRect(0, 0, w, h); // clear canvas
ctx.translate(cx, cy); // translate to center of rotation
ctx.rotate(angleStep); // rotate (accumulative)
ctx.translate(-cx, -cy); // translate back
ctx.fillText(txt, cx, cy); // draw text at rotated center

requestAnimationFrame(rotate); // loop
})();

Live demo

Update

Generic function for it (keep canvas and context outside):

function rotateText(ctx, txt, font, angleStep, cx, cy) {

var w = ctx.canvas.width,
h = ctx.canvas.height;

cx = cx || w * 0.5; // defaults to center if cx/cy isn't given
cy = cy || h * 0.5;

ctx.font = font;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

(function rotate() {
ctx.clearRect(0, 0, w, h); // clear canvas
ctx.translate(cx, cy); // translate to center of rotation
ctx.rotate(angleStep); // rotate (accumulative)
ctx.translate(-cx, -cy); // translate back
ctx.fillText(txt, cx, cy); // draw text at rotated center

requestAnimationFrame(rotate); // loop
})();
}

Now just call:

rotateText(ctx, 'MyText', '32px myfont', 0.1);

or

rotateText(ctx, 'MyText', '32px myfont', 0.1, centerX, centerY);

html5 canvas: auto font size for drawn wrapped rotated text

You do not have to find the font point size to make it fit. The font will smoothly scale up and down according to the current transformation scale.

All you do is measureText to find its textWidth, get the pointSize from the context.font attribute then if you have the width and height of the box you need to fit then find the minimum of the width / textWidth and height / pointSize and you have the scale that you need to render the font at.

As a function

var scale2FitCurrentFont = function(ctx, text, width, height){
var points, fontWidth;
points = Number(ctx.font.split("px")[0]); // get current point size
points += points * 0.2; // As point size does not include hanging tails and
// other top and bottom extras add 20% to the height
// to accommodate the extra bits
var fontWidth = ctx.measureText(text).width;
// get the max scale that will allow the text to fi the current font
return Math.min(width / fontWidth, height / points);
}

The arguments are

  • ctx is current context to draw to
  • text the text to draw
  • width the width to fit the text to
  • height the height to fit the text to

Returns the scale to fit the text within the width and height.

The demo has it all integrated and it draws random boxes and fills with random text from your question. It keeps the font selection and point size separate from the font scaling so you can see it will work for any font and any point size.

var demo = function(){        /** fullScreenCanvas.js begin **/    var canvas = (function(){        var canvas = document.getElementById("canv");        if(canvas !== null){            document.body.removeChild(canvas);        }        // creates a blank image with 2d context        canvas = document.createElement("canvas");         canvas.id = "canv";            canvas.width = window.innerWidth;        canvas.height = window.innerHeight;         canvas.style.position = "absolute";        canvas.style.top = "0px";        canvas.style.left = "0px";        canvas.style.zIndex = 1000;        canvas.ctx = canvas.getContext("2d");         document.body.appendChild(canvas);        return canvas;    })();    var ctx = canvas.ctx;        /** fullScreenCanvas.js end **/    /** FrameUpdate.js begin **/    var w = canvas.width;    var h = canvas.height;    var cw = w / 2;    var ch = h / 2;        var PI2 = Math.PI * 2; // 360 to save typing     var PIh = Math.PI / 2; // 90                 // draws a rounded rectangle path    function roundedRect(ctx,x, y, w, h, r){
ctx.beginPath(); ctx.arc(x + r, y + r, r, PIh * 2, PIh * 3); ctx.arc(x + w - r, y + r, r, PIh * 3, PI2); ctx.arc(x + w - r, y + h - r, r, 0, PIh); ctx.arc(x + r, y + h - r, r, PIh, PIh * 2); ctx.closePath(); } // random words var question = "Suppose that there is a text to be drawn inside a rotated bounding rectangle (not aligned to normal axes x-y), and that text can be also rotated, given the max width of the bounding box, how to select the best font size to use to draw a wrapped text inside that bounding box in html5 canvas and javascript? I know that method: measureText() can measure dimensions of give font size, but I need the inverse of that: using a known width to get the problem font size. thanks."; question = question.split(" "); var getRandomWords= function(){ var wordCount, firstWord, s, i, text; wordCount = Math.floor(rand(4)+1); firstWord = Math.floor(rand(question.length - wordCount)); text = ""; s = ""; for(i = 0; i < wordCount; i++){ text += s + question[i + firstWord]; s = " "; } return text; }
// fonts to use?? Not sure if these are all safe for all OS's var fonts = "Arial,Arial Black,Verdanna,Comic Sans MS,Courier New,Lucida Console,Times New Roman".split(","); // creates a random font with random points size in pixels var setRandomFont = function(ctx){ var size, font; size = Math.floor(rand(10, 40)); font = fonts[Math.floor(rand(fonts.length))]; ctx.font = size + "px " + font; } var scale2FitCurrentFont = function(ctx, text, width, height){ var points, fontWidth; var points = Number(ctx.font.split("px")[0]); // get current point size points += points * 0.2; var fontWidth = ctx.measureText(text).width; // get the max scale that will allow the text to fi the current font return Math.min(width / fontWidth, height / points); }

var rand = function(min, max){ if(max === undefined){ max = min; min = 0; } return Math.random() * (max - min)+min; } var randomBox = function(ctx){ "use strict"; var width, height, rot, dist, x, y, xx, yy,cx, cy, text, fontScale; // get random box width = rand(40, 400); height = rand(10, width * 0.4); rot = rand(-PIh,PIh); dist = Math.sqrt(width * width + height * height) x = rand(0, ctx.canvas.width - dist); y = rand(0, ctx.canvas.height - dist); xx = Math.cos(rot); yy = Math.sin(rot); ctx.fillStyle = "white"; ctx.strokeStyle = "black"; ctx.lineWidth = 2; // rotate the box ctx.setTransform(xx, yy, -yy, xx, x, y); // draw the box roundedRect(ctx, 0, 0, width, height, Math.min(width / 3, height / 3)); ctx.fill(); ctx.stroke(); // get some random text text = getRandomWords(); // get the scale that will fit the font fontScale = scale2FitCurrentFont(ctx, text, width - textMarginLeftRigth * 2, height - textMarginTopBottom * 2); // get center of rotated box cx = x + width / 2 * xx + height / 2 * -yy; cy = y + width / 2 * yy + height / 2 * xx; // scale the transform xx *= fontScale; yy *= fontScale; // set the font transformation to fit the box ctx.setTransform(xx, yy, -yy, xx, cx, cy); // set up the font render ctx.fillStyle = "Black"; ctx.textAlign = "center"; ctx.textBaseline = "middle" // draw the text to fit the box ctx.fillText(text, 0, 0); } var textMarginLeftRigth = 8; // margin for fitted text in pixels var textMarginTopBottom = 4; // margin for fitted text in pixels var drawBoxEveryFrame = 60; // frames between drawing new box var countDown = 1; // update function will try 60fps but setting will slow this down. function update(){ // restore transform ctx.setTransform(1, 0, 0, 1, 0, 0); // fade clears the screen ctx.fillStyle = "white" ctx.globalAlpha = 1/ (drawBoxEveryFrame * 1.5); ctx.fillRect(0, 0, w, h); // reset the alpha ctx.globalAlpha = 1; // count frames countDown -= 1; if(countDown <= 0){ // if frame count 0 the draw another text box countDown = drawBoxEveryFrame; setRandomFont(ctx); randomBox(ctx); } if(!STOP){ // do until told to stop. requestAnimationFrame(update); }else{ STOP = false; } } update();}
// demo code to restart on resizevar STOP = false; // flag to tell demo app to stop function resizeEvent(){ var waitForStopped = function(){ if(!STOP){ // wait for stop to return to false demo(); return; } setTimeout(waitForStopped,200); } STOP = true; setTimeout(waitForStopped,100);}window.addEventListener("resize",resizeEvent);demo();/** FrameUpdate.js end **/


Related Topics



Leave a reply



Submit