使用Fabric.js创建交互式文本字段

33

在过去的几周里,我一直在大量使用Fabric.js,但关于文本字段,我只发现可以在创建时设置文本。

是否有可能创建一个交互式文字字段,或者我必须找到解决方法来实现这一点?(通过交互式文本字段,我指的是单击画布上的某个区域并直接在其中编写的区域。)


1
什么是交互式文本字段? - hjpotter92
@TheJumpingFrog:他的意思是将文本添加到画布上,并稍后编辑其内容。 - Marcel
马塞尔说的话没错。 - Kappei
当一个答案过时了,这里的协议是什么?创建一个新问题,回答它,并从原始问题链接到该问题?基本上,被接受的答案不再正确,而在其下面的答案才是人们寻找解决方案的正确答案。 - teewuane
@teewuane,您可以简单地对问题进行评论(就像您所做的那样),并通知作者有一个更新的答案。更改接受的答案只是一个点击的问题 :) - Kappei
7个回答

90

fabric.js 的最新版本包含一个 IText 类,它将文本的编辑和选择交互动态地结合在一起。请使用最新版本的 fabric.js 尝试以下代码:

canvas.add(new fabric.IText('Tap and Type', { 
  fontFamily: 'arial black',
  left: 100, 
  top: 100 ,
}));

点赞以表示提供更好、更及时的答案。 - Pherrymason
3
值得注意的是,此功能是在fabric.js 1.4中引入的。我最近使用所有内容进行了自定义构建,但IText没有包含在其中,因此出现了类似于“function is undefined”的错误。我将脚本源更改为指向CDN的http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js而不是我的本地副本,这解决了我的问题。然而,我仍然不确定为什么自定义构建没有包含IText。 - teewuane
谢谢。我该如何向文本或IText对象添加新控件?当用户单击文本字段时,我想显示颜色选择器、加粗、斜体、下划线、字体选择器等。是否有任何插件可用于此? - Ashit Vora
你可以通过引用创建的对象并更改其颜色属性来添加颜色选择器。如果您从工具箱中单击文本工具,则会创建一个文本框以及一个可以与文本对象相关联的引用层,请查看http://www.letztroll.com/#!/create/。 - melwyn pawar
你能建议如何开始在特定坐标编写文本吗?@melwynpawar - Amanjot Kaur
@Ku Hye Sun 在上述代码中,"left:100"和"top:100"表示画布上的坐标位置。 - melwyn pawar

15
我最近使用fabric.js构建了一个思维导图工具,也遇到了同样的问题。
为了达到您所描述的效果(在画布上创建文本元素后更改文本),我使用jQuery检测keydown事件。假设您已经选择了fabric画布中所需的文本元素,则以下代码片段将更改文本内容。
$(document).keydown(function(e){
    var keyPressed = String.fromCharCode(e.which);
    var text = canvas.getActiveObject();
    if (text)
    {
        var newText = '';
        var stillTyping = true;
        if (e.which == 27) //esc
        {
            if (!text.originalText) return; //if there is no original text, there is nothing to undo
            newText = text.originalText;
            stillTyping = false;
        }
        //if the user wants to make a correction
        else
        {
            //Store the original text before beginning to type
            if (!text.originalText)
            {
                text.originalText = text.text;
            }
            //if the user wants to remove all text, or the element entirely
            if (e.which == 46) //delete
            {
                activeObject.element.remove(true);
                return;
            }
            else if (e.which == 16) { //shift
                newText = text.text;
            }
            else if (e.which == 8) //backspace
            {
                e.preventDefault();
                newText = text.text.substr(0, text.text.length - 1);
            }
            else if (e.which == 13) //enter
            {
                //canvas clear selection
                canvas.discardActiveObject();
                canvas.renderAll();
                canvasBeforeSelectionCleared({ memo: { target: text} });

                newText = text.text;
                stillTyping = false;
            }
            //if the user is typing alphanumeric characters
            else if (
                (e.which > 64 && e.which < 91) || //A-Z
                (e.which > 47 && e.which < 58) || //0-9
                (e.which == 32) || //Space
                (keyPressed.match(/[!&()"'?-]/)) //Accepted special characters
            )
            {
                if (text.text == text.originalText) text.text = '';
                if (keyPressed.match(/[A-Z]/) && !e.shiftKey)
                    keyPressed = keyPressed.toLowerCase();
                newText = text.text + keyPressed;
            }
        }
        text.set({ text: newText }); //Change the text
        canvas.renderAll(); //Update the canvas

        if (!stillTyping)
        {
            this.text.originalText = null;
        }
    }
});
使用这种技术,我可以在fabric画布中选择文本元素,开始输入,然后该文本将被替换。您可以更改它以使其不会每次选择元素时都清除文本。但这种方法存在一些妥协。例如,您不能像正常的HTML输入文本元素一样选择文本,也没有闪烁的光标,因此“虚拟”光标始终位于文本末尾。如果您真的想要,您可以在文本末尾绘制一个闪烁的光标。

非常感谢。 正如我所想,似乎在fabricjs中没有内置的技术来实现这一点。 这正是我考虑的解决方法。 - Kappei
很棒的代码,Tyson。我刚刚修复了一个小错误,当用户单独按下Shift键时(它会清除文本)。我只是添加了一个else if来使它什么也不做。 - Brett Gregson
我无法输入特殊字符。有没有解决方法? 此外,“canvasBeforeSelectionCleared()”函数未定义。 - Siddhant
我使用了这段代码,它的工作很好,但在编辑文本字段时画布没有显示光标。@Kappei - Sanjay Nakate

5

4
    text.set({ text: newText }); //Change the text
    canvas.renderAll(); //Update the canvas

这正是我一直在寻找的 :) 非常感谢!


0
假设您在脚本中有画布和上下文作为变量:
// write text
context.fillText("text1",0,0);


// refresh canvas and write new text
context.clearRect(0,0,canvas.width,canvas.height);
context.fillText("text2",0,0);

这不是我要找的。我知道如何在画布中设置文本,我所问的是使用fabricjs获取一个交互式文本字段的方法,如果可能的话:通过交互式文本字段,我指的是可以单击并直接在其中编写的画布区域。(为了清晰起见修改了原始问题) - Kappei

0

试试这个(这是来自我的应用程序):

Text Color: <input id="text-color" type="text" value = "#FF0000" name="textColor" />


textColor.onchange = function() {
            canvas.getActiveObject().setColor(this.value);
            canvas.renderAll();
        };

function updateControls() {         
            textControl.value = canvas.getActiveObject().getText();
        }

        canvas.on({
            'object:selected': updateControls,
        });

0

布料具有交互式文本对象。

const sample = "lorem ipsum";
const itext = fabric.IText(sample, {left: 0, top: 0});

注意

要编辑文本,请双击文本字段进入编辑模式


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