如何在 HTML5(或 Fabric.js)中制作屋顶文字效果和山谷文字效果

Posted

技术标签:

【中文标题】如何在 HTML5(或 Fabric.js)中制作屋顶文字效果和山谷文字效果【英文标题】:How to make rooftext effect and valley text effect in HTML5 (or Fabric.js) 【发布时间】:2013-11-01 21:49:16 【问题描述】:

我正在使用以下代码:

<script type='text/javascript'>//<![CDATA[ 
window.onload=function()
/// (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,
    angleSteps = 255/h,
    i = h,
    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);

    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, w * 0.5, 0);

    /// slide and dice
    i = w;
    while (i--) 
        y = bottom + curve * Math.sin(i / angleSteps * Math.PI /160);
        ctx.drawImage(os, i, offsetY, 1, textHeight,i,offsetY, 1, y);
    

iCurve.onchange = iOffset.onchange = iHeight.onchange = iBottom.onchange = iText.onkeyup = renderBridgeText;
renderBridgeText()
//]]>  
</script>
</head>
<body>
  <canvas id=demo width=600 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>Text:</span>
<input id="iText" type="text" value="BRIDGE TEXT">
</body>

我需要像下图这样的文字效果,我做了很多尝试,但我做不到。

谁能帮帮我?

我们还可以使用带有上下文的 fabric.js 中的活动对象吗?

【问题讨论】:

查看 3D 变换属性,使用 perspective-origin() 可能会得到这种效果。没时间展示 jsFiddle ;P 一些信息:24ways.org/2010/intro-to-css-3d-transforms @Ken-AbdiasSoftware 我只是要求一些指导如何将这些上下文属性与 fabric.js 的活动对象一起使用 @Ken-AbdiasSoftware 好的,我将为 fabric.js 添加另一个问题。感谢您的帮助 【参考方案1】:

这是原始代码的修改版本(所提供的代码与我的原始代码相比已更改了值..-)),只需使用参数即可生成所有这些形状:

屋顶不是超级好,但我会把它留给你来添加缩放支持,因为这只是一个例子。

ONLINE DEMO HERE

初始化

var ctx = demo.getContext('2d'), /// context
    font = '64px impact',        /// font
    w = demo.width,              /// cache canvas width and height
    h = demo.height,
    curve,                       /// radius
    offsetY,                     /// offset for text
    bottom,                      /// bottom of text
    textHeight,                  /// text height (region of text)
    isTri = false,               /// is triangle shaped (roof)
    dltY,                        /// delta for triangle
    angleSteps = 180 / w,        /// angle steps for curved text
    i = w,                       /// "x" backwards
    y,                           /// top of text

    /// offscreen canvas that holds original text
    os = document.createElement('canvas'),
    octx = os.getContext('2d');

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

/// set font on off-screen canvas where we draw it
octx.font = font;
octx.textBaseline = 'top';
octx.textAlign = 'center';

主要功能

/// render
function renderBridgeText() 

    /// demo stuff snipped (see link)

    /// clear canvases    
    octx.clearRect(0, 0, w, h);
    ctx.clearRect(0, 0, w, h);

    /// draw text (text may change)
    octx.fillText(iText.value.toUpperCase(), w * 0.5, 0);

    /// slide and dice
    dltY = curve / textHeight;  /// calculate delta for roof/triangle
    y = 0;                      /// reset y in case we do roof
    i = w;                      /// init "x"

    while (i--) 

        if (isTri) 
            /// bounce delta value mid-way for triangle
            y += dltY;
            if (i === (w * 0.5)|0) dltY = -dltY;

         else 
            /// calc length based on radius+angle for curve
            y = bottom - curve * Math.sin(i * angleSteps * Math.PI / 180);
        

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

【讨论】:

很棒的答案。谢谢你帮助我.. :) :) 使用上面相同的属性你能告诉我如何将它们用于fabric.js的活动对象吗? @Rash 抱歉,我对织物不熟悉(您的问题也没有用 fabric.js 标记)。如果答案有帮助,请不要忘记投票/接受。 你是怎么想到这个的? ... 并将这个漂亮的效果与 FabricJS 一起使用:创建一个新的 Fabric.Image(myNativeCanvasWithCurvedText) 来显示您的拱形文本。【参考方案2】:

谢谢,

以上答案对我帮助很大。 但是在使用打字稿时。我在“drawImage”函数中传递简单的文本图像时遇到了问题。

所以,下面是根据 typescript/angular 对上述代码的修改。

HTML:

   <canvas #simpleText id="simpleText" width=220 height=80></canvas>
   <canvas #myCanvas id="myCanvas" width=800 height=400></canvas>

初始化:

     @ViewChild('myCanvas', static: false) myCanvas: ElementRef<HTMLCanvasElement>;
    context: CanvasRenderingContext2D;

    @ViewChild('simpleText', static: false) simpleText: ElementRef<HTMLCanvasElement>;
    simpleTextContext: CanvasRenderingContext2D;
    
    // default values
    shapeConfigure:any=
        w : null,
        h : null,
        curve: 10 ,
        offsetY: 50,
        bottom: 200,
        textHeight: 64,
        isTri : false,
        angleSteps : 0
    ;

    // canvas width height
    shapeCanvas=
        w: 800,
        h: 400
            
    iText:string = 'check text';
    sampleImage = new Image();
    dataURL:any='';

    ngAfterViewInit(): void 
        this.context = this.myCanvas.nativeElement.getContext('2d');
        var font = '60px impact';

        this.simpleTextContext = this.simpleText.nativeElement.getContext('2d');
        this.simpleText.nativeElement.height=60;
        this.simpleText.nativeElement.width=400;
        this.simpleTextContext.font = font;
        this.simpleTextContext.textBaseline = 'top';
        this.simpleTextContext.textAlign = 'left';
        this.simpleTextContext.fillText(this.iText.toUpperCase(), 200* 0.5, 0);

        this.dataURL = this.simpleText.nativeElement.toDataURL();
        console.log(this.dataURL);
        this.sampleImage.src = this.dataURL;    

        this.shapeConfigure=
            w : this.myCanvas.nativeElement.width,
            h : this.myCanvas.nativeElement.height,
            curve: 10 ,
            offsetY: 50,
            bottom: 200,
            textHeight: 64,
            isTri : false,
            angleSteps : 180 /this.shapeCanvas.w
        

        this.renderBridgeText(false);
    

主要功能:

        renderBridgeText(textChange)      

        var curve = parseInt(this.shapeConfigure.curve, 10);
        var offsetY = parseInt(this.shapeConfigure.offsetY, 10);
        var textHeight = parseInt(this.shapeConfigure.textHeight, 10);
        var bottom = parseInt(this.shapeConfigure.bottom, 10);
        var isTri = this.shapeConfigure.isTri;

        this.context.clearRect(0, 0, this.shapeCanvas.w , this.shapeCanvas.h );

        if(textChange)
        this.simpleTextContext.clearRect(0, 0, this.shapeCanvas.w , this.shapeCanvas.h );
        this.simpleTextContext.fillText(this.iText.toUpperCase(), 200* 0.5, 0);
        this.dataURL = this.simpleText.nativeElement.toDataURL();
        
        this.sampleImage.src = this.dataURL;


        this.sampleImage.onload = () => 
        /// slide and dice
        var i:number = this.shapeCanvas.w;
        var dltY:number = curve / textHeight;
        var y = 0;
        while (i--) 
            if (isTri) 
                y += dltY;
                if (i === (this.shapeCanvas.w * 0.5))
                    dltY = -dltY;
             else 
                y = bottom - curve * Math.sin(i * this.shapeConfigure.angleSteps * Math.PI / 180);
            
            
            this.context.drawImage(this.sampleImage, i, 0, 1, textHeight, i, this.shapeCanvas.h * 0.5 - offsetY / textHeight * y, 1, y);
        
        
    

【讨论】:

以上是关于如何在 HTML5(或 Fabric.js)中制作屋顶文字效果和山谷文字效果的主要内容,如果未能解决你的问题,请参考以下文章

Fabric.js 将画布(或对象组)剪辑到多边形

fabric.js:如何制作带有描边阴影等的椭圆形图像?

在 html5 中的 fabric.js 画布上一次删除多个对象

Html5 Canvas + fabric.js 的独立堆肥

如何将 Fabric js 与 React Native 集成?

Fabric.js:如何取消选择画布上的一个或多个对象?