Canvas 圆弧方向的文字,但字母应保持垂直

Text with arc direction in Canvas, but letters should keep vertical

这就是我想要做的:

我得到的更近的是像这个例子一样的桥梁文本,但它使用了桥梁的顶级基线,我不确定如何根据我的需要添加它:

Bridge Text Effect in HTML5 Canvas

Fiddle: https://jsfiddle.net/0btz7a1g/

/// (c) Ken Fyrstenberg Nilsen, Abidas Software .com
/// License: CC-Attribute

var ctx = demo.getContext('2d'),
    font = '64px impact',
    w = demo.width,
    h = demo.height,
    curve,
    offsetY,
    bottom,
    textHeight,
    isTri = false,
    dltY,
    angleSteps = 180 / w,
    i = w,
    y,
    os = document.createElement('canvas'),
    octx = os.getContext('2d');

os.width = w;
os.height = h;

octx.font = font;
octx.textBaseline = 'top';
octx.textAlign = 'center';

function renderBridgeText() {

    curve = parseInt(iCurve.value, 10);
    offsetY = parseInt(iOffset.value, 10);
    textHeight = parseInt(iHeight.value, 10);
    bottom = parseInt(iBottom.value, 10);
    isTri = iTriangle.checked;

    vCurve.innerHTML = curve;
    vOffset.innerHTML = offsetY;
    vHeight.innerHTML = textHeight;
    vBottom.innerHTML = bottom;

    octx.clearRect(0, 0, w, h);
    ctx.clearRect(0, 0, w, h);

    octx.fillText(iText.value.toUpperCase(), w * 0.5, 0);

    /// slide and dice
    i = w;
    dltY = curve / textHeight;
    y = 0;
    while (i--) {
        if (isTri) {
            y += dltY;
            if (i === (w * 0.5)|0) dltY = -dltY;
        } else {
            y = bottom - curve * Math.sin(i * angleSteps * Math.PI / 180);
        }
        ctx.drawImage(os, i, 0, 1, textHeight,
        i, h * 0.5 - offsetY / textHeight * y, 1, y);
    }
}

iCurve.onchange = iOffset.onchange = iHeight.onchange = iBottom.onchange = iText.onkeyup = iTriangle.onchange = renderBridgeText;

renderBridgeText()
span {
    display:inline-block;
    width:70px;
    text-align:right;
    font:12px sans-serif;
}
<canvas id=demo width=400 height=300></canvas>
<br>
    <span>Curve:</span>
<input id="iCurve" type="range" min=0 max=200 value=110>
<span id="vCurve">110</span>
    <br><span>OffsetY:</span>
<input id="iOffset" type="range" min=0 max=100 value=4>
<span id="vOffset">0</span>
    <br><span>Text height:</span>
<input id="iHeight" type="range" min=0 max=200 value=64>
<span id="vHeight">64</span>
    <br><span>Bottom:</span>
<input id="iBottom" type="range" min=0 max=200 value=200>
<span id="vBottom">200</span>
    <br><span>Triangle:</span>
    <input id="iTriangle" type="checkbox">
<br><span>Text:</span>
<input id="iText" type="text" value="BRIDGE TEXT">
 

有没有什么方法可以像图片中那样在保持每个字母垂直的同时弧形文本?

该工具的工作原理是正常绘制文本,将其切成 1 像素宽的垂直条带,然后使用垂直缩放和偏移重新绘制这些条带。了解 .drawImage() 功能如何帮助实现这一目标。根据您的需要更改此算法就是更改缩放和偏移的计算方式。

为每个条带计算两个参数:偏移量和高度。 y 控制圆弧但直接用于设置目标高度。 h * 0.5 - offsetY / textHeight * y 缩放和偏移 y 以产生偏移。

由于 y 几乎直接来自 sin(),我们可以使用它作为偏移量。高度将保持固定,因此我们为此使用 textHeight

改变

ctx.drawImage(os, i, 0, 1, textHeight,
                  i, h * 0.5 - offsetY / textHeight * y, 1, y);

ctx.drawImage(os, i, 0, 1, textHeight,
                  i, y, 1, textHeight);

成功了。

这是最低限度的更改。关于如何进一步清理代码,我将把它留给你自己练习。