Canvas Draw Circle With Text
Instance
This instance shows how to return text along an arc. It includes how you can add functionality to the CanvasRenderingContext2D
past extending its prototype.
This examples is derived from the stackoverflow answer Circular Text.
Example rendering
Example code
The case adds 3 new text rendering functions to the 2d context prototype.
- ctx.fillCircleText(text, ten, y, radius, offset, end, forward);
- ctx.strokeCircleText(text, x, y, radius, offset, cease, forward);
- ctx.measureCircleText(text, radius);
(function(){ const FILL = 0; // const to indicate filltext render const STROKE = i; var renderType = FILL; // used internal to prepare make full or stroke text const multiplyCurrentTransform = true; // if true Employ current transform when rendering // if faux apply absolute coordinates which is a piddling quicker // later on render the currentTransform is restored to default transform // measure circle text // ctx: canvas context // text: string of text to measure // r: radius in pixels // // returns the size metrics of the text // // width: Pixel width of text // angularWidth : angular width of text in radians // pixelAngularSize : angular width of a pixel in radians var mensurate = function(ctx, text, radius){ var textWidth = ctx.measureText(text).width; // go the width of all the text return { width : textWidth, angularWidth : (1 / radius) * textWidth, pixelAngularSize : i / radius }; } // displays text along a circle // ctx: sheet context // text: string of text to measure // x,y: position of circle center // r: radius of circle in pixels // start: angle in radians to start. // [end]: optional. If included text marshal is ignored and the text is // scaled to fit between start and end; // [forward]: optional default true. if true text direction is forward, if fake management is backward var circleText = function (ctx, text, x, y, radius, start, end, forward) { var i, textWidth, pA, pAS, a, aw, wScale, aligned, dir, fontSize; if(text.trim() === "" || ctx.globalAlpha === 0){ // dont render empty string or transparent return; } if(isNaN(x) || isNaN(y) || isNaN(radius) || isNaN(first) || (end !== undefined && stop !== zippo && isNaN(end))){ // throw TypeError("circle text arguments requires a number for x,y, radius, get-go, and finish.") } aligned = ctx.textAlign; // salvage the electric current textAlign and so that it tin can exist restored at end dir = forwards ? 1 : forrad === false ? -ane : 1; // gear up dir if not truthful or simulated set forward as true pAS = 1 / radius; // become the angular size of a pixel in radians textWidth = ctx.measureText(text).width; // get the width of all the text if (end !== undefined && terminate !== zilch) { // if stop is supplied and then fit text betwixt kickoff and end pA = ((terminate - kickoff) / textWidth) * dir; wScale = (pA / pAS) * dir; } else { // if no cease is supplied right start and stop for alignment // if forward is non given then bandy top of circle text to read the correct management if(forward === goose egg || forward === undefined){ if(((start % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2) > Math.PI){ dir = -1; } } pA = -pAS * dir ; wScale = -ane * dir; switch (aligned) { instance "eye": // if centered move effectually half width kickoff -= (pA * textWidth )/two; terminate = start + pA * textWidth; intermission; example "correct":// intentionally falls through to case "cease" instance "end": end = outset; start -= pA * textWidth; break; case "left": // intentionally falls through to case "start" case "start": terminate = kickoff + pA * textWidth; } } ctx.textAlign = "center"; // align for rendering a = start; // set the start angle for (var i = 0; i < text.length; i += one) { // for each graphic symbol aw = ctx.measureText(text[i]).width * pA; // become the angular width of the text var xDx = Math.cos(a + aw / two); // get the yAxies vector from the center ten,y out var xDy = Math.sin(a + aw / 2); if(multiplyCurrentTransform){ // transform multiplying current transform ctx.save(); if (xDy < 0) { // is the text upside down. If it is flip information technology ctx.transform(-xDy * wScale, xDx * wScale, -xDx, -xDy, xDx * radius + x, xDy * radius + y); } else { ctx.transform(-xDy * wScale, xDx * wScale, xDx, xDy, xDx * radius + x, xDy * radius + y); } }else{ if (xDy < 0) { // is the text upside down. If it is flip information technology ctx.setTransform(-xDy * wScale, xDx * wScale, -xDx, -xDy, xDx * radius + 10, xDy * radius + y); } else { ctx.setTransform(-xDy * wScale, xDx * wScale, xDx, xDy, xDx * radius + x, xDy * radius + y); } } if(renderType === FILL){ ctx.fillText(text[i], 0, 0); // render the character }else{ ctx.strokeText(text[i], 0, 0); // render the character } if(multiplyCurrentTransform){ // restore current transform ctx.restore(); } a += aw; // pace to the side by side angle } // all done clean up. if(!multiplyCurrentTransform){ ctx.setTransform(ane, 0, 0, i, 0, 0); // restore the transform } ctx.textAlign = aligned; // restore the text alignment } // define fill text var fillCircleText = function(text, x, y, radius, start, end, forrad){ renderType = FILL; circleText(this, text, ten, y, radius, kickoff, stop, forward); } // define stroke text var strokeCircleText = role(text, x, y, radius, start, finish, forrard){ renderType = STROKE; circleText(this, text, x, y, radius, start, terminate, forrard); } // define measure out text var measureCircleTextExt = function(text,radius){ return measure(this, text, radius); } // ready the prototypes CanvasRenderingContext2D.prototype.fillCircleText = fillCircleText; CanvasRenderingContext2D.prototype.strokeCircleText = strokeCircleText; CanvasRenderingContext2D.prototype.measureCircleText = measureCircleTextExt; })();
Function descriptions
This example adds 3 functions to the CanvasRenderingContext2D prototype
. fillCircleText
, strokeCircleText
, and measureCircleText
CanvasRenderingContext2D.fillCircleText(text, x, y, radius, outset, [end, [frontwards]]);
CanvasRenderingContext2D.strokeCircleText(text, x, y, radius, start, [stop, [forward]]);
- text: Text to render as Cord.
- x,y: Position of circumvolve center as Numbers.
- radius: radius of circle in pixels
- commencement: angle in radians to start.
- [end]: optional. If included
ctx.textAlign
is ignored and the text is scaled to fit between commencement and end. - [forward]: optional default 'true'. if true text direction is forwards, if 'imitation' management is backward.
Both functions use the textBaseline to position the text vertically around the radius. For the best results utilize ctx.TextBaseline
.
Functions volition throw a TypeError
is any of the numerical arguments as NaN.
If the text
argument trims to an empty string or ctx.globalAlpha = 0
the function just drops through and does cipher.
CanvasRenderingContext2D.measureCircleText(text, radius);
- **text:** String of text to measure. - **radius:** radius of circle in pixels.
Returns a Object containing various size metrics for rendering circular text
- **width:** Pixel width of text as it would normaly be rendered - **angularWidth:** athwart width of text in radians. - **pixelAngularSize:** athwart width of a pixel in radians.
Usage examples
const rad = sheet.height * 0.iv; const text = "Hello circumvolve TEXT!"; const fontSize = 40; const centX = canvas.width / two; const centY = canvas.height / 2; ctx.clearRect(0,0,canvas.width,canvas.height) ctx.font = fontSize + "px verdana"; ctx.textAlign = "center"; ctx.textBaseline = "bottom"; ctx.fillStyle = "#000"; ctx.strokeStyle = "#666"; // Text under stretched from Math.PI to 0 (180 - 0 deg) ctx.fillCircleText(text, centX, centY, rad, Math.PI, 0); // text over meridian centered at Math.PI * 1.five ( 270 deg) ctx.fillCircleText(text, centX, centY, rad, Math.PI * 1.five); // text under top centered at Math.PI * 1.5 ( 270 deg) ctx.textBaseline = "pinnacle"; ctx.fillCircleText(text, centX, centY, rad, Math.PI * ane.5); // text over top centered at Math.PI * i.v ( 270 deg) ctx.textBaseline = "middle"; ctx.fillCircleText(text, centX, centY, rad, Math.PI * 1.5); // Use measureCircleText to get angular size var circleTextMetric = ctx.measureCircleText("Text to measure", rad); panel.log(circleTextMetric.width); // width of text if rendered normally panel.log(circleTextMetric.angularWidth); // angular width of text console.log(circleTextMetric.pixelAngularSize); // athwart size of a pixel // Use measure text to depict a arc effectually the text ctx.textBaseline = "middle"; var width = ctx.measureCircleText(text, rad).angularWidth; ctx.fillCircleText(text, centX, centY, rad, Math.PI * one.5); // render the arc around the text ctx.strokeStyle= "red"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(centX, centY, rad + fontSize / two,Math.PI * 1.5 - width/2,Math.PI*one.5 + width/ii); ctx.arc(centX, centY, rad - fontSize / two,Math.PI * ane.5 + width/ii,Math.PI*i.v - width/2,true); ctx.closePath(); ctx.stroke();
NOTE: The text rendered is simply an approximation of circular text. For example if ii 50's are rendered the two lines will not be parallel, just if you return a "H" the ii edges will be parallel. This is because each character is rendered as close as possible to the required direction, rather than each pixel being correctly transformed to create circular text.
NOTE:
const multiplyCurrentTransform = true;
defined in this example is used to ready the transformation method used. Iffalse
the transformation for circular text rendering is absolute and does non depend on the current transformation country. The text will non be effected by any previous scale, rotate, or translate transforms. This volition increment the functioning of the render function, after the part is called the transform will be set to the defaultsetTransform(1,0,0,1,0,0)
If
multiplyCurrentTransform = true
(set up equally default in this example) the text volition use the current transform so that the text can be scaled translated, skewed, rotated, etc merely modifying the electric current transform befor calling thefillCircleText
andstrokeCircleText
functions. Depending on the current state of the 2d context this may be somewhat slower somultiplyCurrentTransform = false
Source: https://riptutorial.com/html5-canvas/example/18742/rendering-text-along-an-arc-
0 Response to "Canvas Draw Circle With Text"
Post a Comment