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 of circle text


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. If false 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 default setTransform(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 the fillCircleText and strokeCircleText functions. Depending on the current state of the 2d context this may be somewhat slower so multiplyCurrentTransform = false




williamsyoutims.blogspot.com

Source: https://riptutorial.com/html5-canvas/example/18742/rendering-text-along-an-arc-

0 Response to "Canvas Draw Circle With Text"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel