Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/88.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何使用HTML5画布沿弧形路径绘制文本?_Javascript_Html_Canvas - Fatal编程技术网

Javascript 如何使用HTML5画布沿弧形路径绘制文本?

Javascript 如何使用HTML5画布沿弧形路径绘制文本?,javascript,html,canvas,Javascript,Html,Canvas,我想画一个画布图形,就像这个flash动画: 我画了六个弧,我想在这些弧里写六个字。有什么想法吗?你不能用任何固有的方式。请注意SVG原生地支持沿着路径的文本,所以您可能需要考虑SVG而不是! 但是您可以编写自定义代码以实现相同的效果,就像我们中的一些人在这里回答这个问题时所做的那样:您可以尝试以下代码,了解如何使用HTML5画布沿弧形路径编写文本 函数drawTextAlongArc(上下文、str、centerX、centerY、半径、角度){ var len=str.length, s

我想画一个画布图形,就像这个flash动画:


我画了六个弧,我想在这些弧里写六个字。有什么想法吗?

你不能用任何固有的方式。请注意SVG原生地支持沿着路径的文本,所以您可能需要考虑SVG而不是!
但是您可以编写自定义代码以实现相同的效果,就像我们中的一些人在这里回答这个问题时所做的那样:

您可以尝试以下代码,了解如何使用HTML5画布沿弧形路径编写文本

函数drawTextAlongArc(上下文、str、centerX、centerY、半径、角度){
var len=str.length,
s
context.save();
上下文。翻译(centerX、centerY);
旋转(-1*角度/2);
旋转(-1*(角度/透镜)/2);
对于(变量n=0;n

身体{
边际:0px;
填充:0px;
}

一个老问题。。。尽管如此,在我的博客上,我还是仔细研究了如何使用HTML5画布创建循环文本:

在该示例中,选项包括从给定角度进行的圆形文本对齐(左、中、右)、向内和向外文本、紧排(字符之间的可调间距)以及半径内外的文本

还有一个例子

详情如下:

document.body.appendChild(getCircularText("ROUNDED TEXT LOOKS BEST IN CAPS!", 250, 0, "center", true, true, "Arial", "18pt", 0));

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 draws 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.font = fSize + ' ' + fName;

    // Reverse letter order 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

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

        // draw char at "top" if inward facing or "bottom" if outward
        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);
}
document.body.appendChild(getCircularText(“圆形文本在大写字母中看起来最好!”,250,0,“居中”,true,true,“Arial”,“18pt”,0));
函数getCircularText(文本、直径、星形、对齐、文本内部、向内、fName、fSize、字距){
//文本:以循环方式显示的文本
//直径:文本将围绕的圆的直径
//显示(内部或外部)
//startAngle:以度为单位,显示文本的位置。0度
//如果圆的顶端
//对齐:将文本定位到startAngle的左右或中心
//text内径:true表示内径。False表示外径
//向内:对于向内的文本底部为true。对于向外的文本底部为false
//fName:字体系列的名称。请确保已加载
//字体系列的大小。别忘了包括单位
//卡恩:0表示字母之间的正常间隙。正或
//负数以像素为单位展开/压缩间距
//------------------------------------------------------------------------
//声明并初始化画布、引用和有用变量
align=align.toLowerCase();
var maincavas=document.createElement('canvas');
var ctxRef=maincavas.getContext('2d');
var顺时针=align==“right”?1:-1;//为对齐的右侧顺时针绘制。否则为逆时针绘制
startAngle=startAngle*(Math.PI/180);//转换为弧度
//计算字体的高度。有很多方法可以做到这一点
//你可以用你自己的来代替!
var div=document.createElement(“div”);
div.innerHTML=文本;
div.style.position='绝对';
div.style.top='-10000px';
div.style.left='-10000px';
div.style.fontFamily=fName;
div.style.fontSize=fSize;
文件.正文.附件(div);
var textHeight=div.offsetHeight;
文件.正文.删除文件(div);
//如果我们正在绘制外径,
//扩展直径来处理它
如果(!textInside)直径+=textHeight*2;
main.width=直径;
mainCanvas.height=直径;
//忽略透明背景的下一行
mainCanvas.style.backgroundColor='浅灰色';
ctxRef.font=fSize+''+fName;
//将字母顺序反转为向左向内对齐,向右向外对齐
//然后将中心向内对齐。
如果((([“左”、“中”].indexOf(align)>-1)和&向内)| |(align==“右”&&&向内))text=text.split(“”)。reverse().join(“”);
//设置字母和定位
ctxRef.translate(直径/2,直径/2);//移动到中心
startAngle+=(Math.PI*!向内);//向外旋转180
ctxRef.textBaseline='middle';//确保在精确的中心绘制
ctxRef.textAlign='center';//确保我们在精确的中心绘制
//旋转总角度的50%以进行中心对齐
如果(对齐=“中心”){
对于(var j=0;j
我有一个到ap的JSFIDLE
<table>
    <TR>
        <TH>Bezier Curve</TH>
        <TD>
            <input size="80" type="text" id="curve" name="curve" value="99.2,177.2,130.02,60.0,300.5,276.2,300.7,176.2">
        </TD>
    </TR>
    <TR>
        <TH>Text</TH>
        <TD>
            <input size="80" type="text" id="text" name="text" value="testing 1234567890">
        </TD>
    </TR>
    <TR>
        <TD colspan=2>
            <div id="canvasDiv"></div>
        </TD>
    </TR>
</table>

var first = true;
startIt();


function startIt() {
    canvasDiv = document.getElementById('canvasDiv');
    canvasDiv.innerHTML = '<canvas id="layer0" width="300" height="300"></canvas>'; //for IE
    canvas = document.getElementById('layer0');
    ctx = canvas.getContext('2d');
    ctx.fillStyle = "black";
    ctx.font = "18px arial black";
    curve = document.getElementById('curve');
    curveText = document.getElementById('text');
    $(curve).keyup(function (e) {
        changeCurve();
    });
    $(curveText).keyup(function (e) {
        changeCurve();
    });




    if (first) {
        changeCurve();
        first = false;
    }

}

function changeCurve() {
    points = curve.value.split(',');
    if (points.length == 8) drawStack();

}

function drawStack() {
    Ribbon = {
        maxChar: 50,
        startX: points[0],
        startY: points[1],
        control1X: points[2],
        control1Y: points[3],
        control2X: points[4],
        control2Y: points[5],
        endX: points[6],
        endY: points[7]
    };

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.beginPath();

    ctx.moveTo(Ribbon.startX, Ribbon.startY);
    ctx.bezierCurveTo(Ribbon.control1X, Ribbon.control1Y,
    Ribbon.control2X, Ribbon.control2Y,
    Ribbon.endX, Ribbon.endY);

    ctx.stroke();
    ctx.restore();

    FillRibbon(curveText.value, Ribbon);
}

function FillRibbon(text, Ribbon) {

    var textCurve = [];
    var ribbon = text.substring(0, Ribbon.maxChar);
    var curveSample = 1000;


    xDist = 0;
    var i = 0;
    for (i = 0; i < curveSample; i++) {
        a = new bezier2(i / curveSample, Ribbon.startX, Ribbon.startY, Ribbon.control1X, Ribbon.control1Y, Ribbon.control2X, Ribbon.control2Y, Ribbon.endX, Ribbon.endY);
        b = new bezier2((i + 1) / curveSample, Ribbon.startX, Ribbon.startY, Ribbon.control1X, Ribbon.control1Y, Ribbon.control2X, Ribbon.control2Y, Ribbon.endX, Ribbon.endY);
        c = new bezier(a, b);
        textCurve.push({
            bezier: a,
            curve: c.curve
        });
    }

    letterPadding = ctx.measureText(" ").width / 4;
    w = ribbon.length;
    ww = Math.round(ctx.measureText(ribbon).width);


    totalPadding = (w - 1) * letterPadding;
    totalLength = ww + totalPadding;
    p = 0;

    cDist = textCurve[curveSample - 1].curve.cDist;

    z = (cDist / 2) - (totalLength / 2);

    for (i = 0; i < curveSample; i++) {
        if (textCurve[i].curve.cDist >= z) {
            p = i;
            break;
        }
    }

    for (i = 0; i < w; i++) {
        ctx.save();
        ctx.translate(textCurve[p].bezier.point.x, textCurve[p].bezier.point.y);
        ctx.rotate(textCurve[p].curve.rad);
        ctx.fillText(ribbon[i], 0, 0);
        ctx.restore();

        x1 = ctx.measureText(ribbon[i]).width + letterPadding;
        x2 = 0;
        for (j = p; j < curveSample; j++) {
            x2 = x2 + textCurve[j].curve.dist;
            if (x2 >= x1) {
                p = j;
                break;
            }
        }




    }
} //end FillRibon

function bezier(b1, b2) {
    //Final stage which takes p, p+1 and calculates the rotation, distance on the path and accumulates the total distance
    this.rad = Math.atan(b1.point.mY / b1.point.mX);
    this.b2 = b2;
    this.b1 = b1;
    dx = (b2.x - b1.x);
    dx2 = (b2.x - b1.x) * (b2.x - b1.x);
    this.dist = Math.sqrt(((b2.x - b1.x) * (b2.x - b1.x)) + ((b2.y - b1.y) * (b2.y - b1.y)));
    xDist = xDist + this.dist;
    this.curve = {
        rad: this.rad,
        dist: this.dist,
        cDist: xDist
    };
}

function bezierT(t, startX, startY, control1X, control1Y, control2X, control2Y, endX, endY) {
    //calculates the tangent line to a point in the curve; later used to calculate the degrees of rotation at this point.
    this.mx = (3 * (1 - t) * (1 - t) * (control1X - startX)) + ((6 * (1 - t) * t) * (control2X - control1X)) + (3 * t * t * (endX - control2X));
    this.my = (3 * (1 - t) * (1 - t) * (control1Y - startY)) + ((6 * (1 - t) * t) * (control2Y - control1Y)) + (3 * t * t * (endY - control2Y));
}

function bezier2(t, startX, startY, control1X, control1Y, control2X, control2Y, endX, endY) {
    //Quadratic bezier curve plotter
    this.Bezier1 = new bezier1(t, startX, startY, control1X, control1Y, control2X, control2Y);
    this.Bezier2 = new bezier1(t, control1X, control1Y, control2X, control2Y, endX, endY);
    this.x = ((1 - t) * this.Bezier1.x) + (t * this.Bezier2.x);
    this.y = ((1 - t) * this.Bezier1.y) + (t * this.Bezier2.y);
    this.slope = new bezierT(t, startX, startY, control1X, control1Y, control2X, control2Y, endX, endY);

    this.point = {
        t: t,
        x: this.x,
        y: this.y,
        mX: this.slope.mx,
        mY: this.slope.my
    };
}

function bezier1(t, startX, startY, control1X, control1Y, control2X, control2Y) {
    //linear bezier curve plotter; used recursivly in the quadratic bezier curve calculation
    this.x = ((1 - t) * (1 - t) * startX) + (2 * (1 - t) * t * control1X) + (t * t * control2X);
    this.y = ((1 - t) * (1 - t) * startY) + (2 * (1 - t) * t * control1Y) + (t * t * control2Y);

}