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 angleAnd finally
fillText
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
What Is "Context" in Jquery Selector
How to Delete Document from Firestore Using Where Clause
Angular2:Render a Component Without Its Wrapping Tag
Save File JavaScript with File Name
Keys in JavaScript Objects Can Only Be Strings
Style.Display='None' Doesn't Work on Option Tags in Chrome, But It Does in Firefox
Make Vuejs and Jquery Play Nice
Why Is It Object.Defineproperty() Rather Than This.Defineproperty() (For Objects)
What Does Three Dots Do in Reactjs
Angular2/Spring Boot Allow Cross Origin on Put
Convert Character to Ascii Code in JavaScript
Difference Between "Module.Exports" and "Exports" in the Commonjs Module System
How to Conditionally Add Attributes to React Components
How to Get Last Characters of a String
Fastest Way to Copy a File in Node.Js