HTML5画布圆形文本

18
如何使用canvas创建圆形文本(以圆形方式排列的文本)?

类似这样


将每个字母分开放置在一个圆形中是个不错的想法,但我能否真正地“弯曲”它呢? - seymar
我建议您使用SVG,它更强大,可以做这些事情。 - Jesufer Vn
可以使用图像。 - seymar
6个回答

23

现在字母应该被正确地定位:

CanvasRenderingContext2D.prototype.fillTextCircle = function(text,x,y,radius,startRotation){
   var numRadsPerLetter = 2*Math.PI / text.length;
   this.save();
   this.translate(x,y);
   this.rotate(startRotation);

   for(var i=0;i<text.length;i++){
      this.save();
      this.rotate(i*numRadsPerLetter);

      this.fillText(text[i],0,-radius);
      this.restore();
   }
   this.restore();
}

示例用法:

var ctx = document.getElementById('canvas').getContext('2d');
ctx.font = "bold 30px Serif";
ctx.fillTextCircle("Circle Text ",150,150,75,Math.PI / 2);

字符串末尾的额外空格会增加一些额外的填充。

示例输出:

示例输出


我已经考虑过制作这个了,谢谢你的开始。我看还需要一些改进 :P - seymar
当然可以。这只是一个快速的代码编写,用作概念证明 :) - cmptrgeekken
+1 给这个例子!我修改了 cmptrgeekken 的代码,使其能够旋转字母,现在我们有一个完整的工作示例了! - Simon Sarris
cmptrgeekken并没有提到,但他已经更新了他的代码,做出了与我的相同效果,但使用了更通用的方法。以他的代码为起点。还有,这里:http://jsfiddle.net/D5JWa/5/ 在你创建后记得调用init(),并且记住strokeStyle不是一个函数(已将其更改为'=')。 - Simon Sarris
是的,我意识到 ctx.fillText() 调用中的位置实际上决定了字母的方向。有了这个想法,您可以尝试各种定位来实现任何字母方向。 - cmptrgeekken

8
技术上可以做到,但没有内置的方法。您需要计算弧线,并沿着该弧线逐个绘制每个字母,自己找出角度和位置。
许多人最终会为文本制作自己的方法(例如上面的方法)。实际上,默认情况下甚至无法进行多行文本!
编辑:这是一个可行的示例,借鉴了cmptrgeekken的工作。如果您给我点赞,请也给他点赞 :P

http://jsfiddle.net/c3Y8M/1/

它的外观如下:

Sample


谢谢提供演示。如果我不想让字母在圆圈上分散,我只需要将numDegreesPerLetter乘以小于1的比率吗?我已经在这里改编了您的代码https://jsfiddle.net/thoakun/1zmL9rwd/ - bytrangle

6
在我的博客上,我详细介绍如何使用HTML5 Canvas创建圆形文本:

html5graphics.blogspot.com

在这个例子中,选项包括从给定角度进行的文本对齐(左、中、右),向内和向外面对的文本,字距调整(字符之间可调节的间隔)以及半径内或半径外的文本。
同时还有一个jsfiddle的可工作示例。
具体如下:
document.body.appendChild(getCircularText("ROUNDED TEXT LOOKS BEST IN CAPS!", 250, 0, "center", false, true, "Arial", "18pt", 2));

function getCircularText(text, diameter, startAngle, align, textInside, inwardFacing, fName, fSize, kerning) {
    // text:         The text to be displayed in circular fashion
    // diameter:     The diameter of the circle around which the text will
    //               be displayed (inside or outside)
    // startAngle:   In degrees, Where the text will be shown. 0 degrees
    //               if the top of the circle
    // align:        Positions text to left right or center of startAngle
    // textInside:   true to show inside the diameter. False to show outside
    // inwardFacing: true for base of text facing inward. false for outward
    // fName:        name of font family. Make sure it is loaded
    // fSize:        size of font family. Don't forget to include units
    // kearning:     0 for normal gap between letters. positive or
    //               negative number to expand/compact gap in pixels
 //------------------------------------------------------------------------

    // declare and intialize canvas, reference, and useful variables
    align = align.toLowerCase();
    var mainCanvas = document.createElement('canvas');
    var ctxRef = mainCanvas.getContext('2d');
    var clockwise = align == "right" ? 1 : -1; // draw clockwise for aligned right. Else Anticlockwise
    startAngle = startAngle * (Math.PI / 180); // convert to radians

    // calculate height of the font. Many ways to do this
    // you can replace with your own!
    var div = document.createElement("div");
    div.innerHTML = text;
    div.style.position = 'absolute';
    div.style.top = '-10000px';
    div.style.left = '-10000px';
    div.style.fontFamily = fName;
    div.style.fontSize = fSize;
    document.body.appendChild(div);
    var textHeight = div.offsetHeight;
    document.body.removeChild(div);

    // in cases where we are drawing outside diameter,
    // expand diameter to handle it
    if (!textInside) diameter += textHeight * 2;

    mainCanvas.width = diameter;
    mainCanvas.height = diameter;
    // omit next line for transparent background
    mainCanvas.style.backgroundColor = 'lightgray'; 
    ctxRef.fillStyle = 'black';
    ctxRef.font = fSize + ' ' + fName;

    // Reverse letters for align Left inward, align right outward 
    // and align center inward.
    if (((["left", "center"].indexOf(align) > -1) && inwardFacing) || (align == "right" && !inwardFacing)) text = text.split("").reverse().join(""); 

    // Setup letters and positioning
    ctxRef.translate(diameter / 2, diameter / 2); // Move to center
    startAngle += (Math.PI * !inwardFacing); // Rotate 180 if outward
    ctxRef.textBaseline = 'middle'; // Ensure we draw in exact center
    ctxRef.textAlign = 'center'; // Ensure we draw in exact center

    // rotate 50% of total angle for center alignment
    if (align == "center") {
        for (var j = 0; j < text.length; j++) {
            var charWid = ctxRef.measureText(text[j]).width;
            startAngle += ((charWid + (j == text.length-1 ? 0 : kerning)) / (diameter / 2 - textHeight)) / 2 * -clockwise;
        }
    }

    // Phew... now rotate into final start position
    ctxRef.rotate(startAngle);

    // Now for the fun bit: draw, rotate, and repeat
    for (var j = 0; j < text.length; j++) {
        var charWid = ctxRef.measureText(text[j]).width; // half letter
        // rotate half letter
        ctxRef.rotate((charWid/2) / (diameter / 2 - textHeight) * clockwise); 
        // draw the character at "top" or "bottom" 
        // depending on inward or outward facing
        ctxRef.fillText(text[j], 0, (inwardFacing ? 1 : -1) * (0 - diameter / 2 + textHeight / 2));

        ctxRef.rotate((charWid/2 + kerning) / (diameter / 2 - textHeight) * clockwise); // rotate half letter
    }

    // Return it
    return (mainCanvas);
}

4
这是我对http://jsfiddle.net/Brfp3/3/的改进。现在,它可以让文本顺时针和逆时针旋转显示。
function textCircle(text,x,y,radius,space,top){
           space = space || 0;
           var numRadsPerLetter = (Math.PI - space * 2) / text.length;
           ctx.save();
           ctx.translate(x,y);
           var k = (top) ? 1 : -1; 
           ctx.rotate(-k * ((Math.PI - numRadsPerLetter) / 2 - space));
           for(var i=0;i<text.length;i++){
              ctx.save();
              ctx.rotate(k*i*(numRadsPerLetter));
              ctx.textAlign = "center";
             ctx.textBaseline = (!top) ? "top" : "bottom";
             ctx.fillText(text[i],0,-k*(radius));
              ctx.restore();
           }
           ctx.restore();
        }

示例用法:

ctx.font = "bold 30px Courier";
textCircle("Half circle Text",150,150,75,Math.PI/12,1);
textCircle("Half circle Text",150,150,75,Math.PI/12);

谢谢。你的演示非常酷,帮助我解决了一个问题。 - bytrangle

4
一个版本,其中字符的大小被计算。因此字母之间的空格始终具有相同的大小。
function drawTextAlongArc(context, str, centerX, centerY, radius, angle) {
    var len = str.length, s, letterAngle;

    context.save();
    context.textAlign = 'center';
    context.translate(centerX, centerY);
    context.rotate(angle + Math.PI / 2);

    for (var n = 0; n < len; n++) {
        s = str[n];
        letterAngle = 0.5*(context.measureText(s).width / radius);

        context.rotate(letterAngle);
        context.save();

        context.translate(0, -radius);
        context.fillText(s, 0, 0);
        context.restore();

        context.rotate(letterAngle);
    }
    context.restore();
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接