33

I've been playing with Fabric.js a lot in the last few weeks, but regarding text fields I've only found it possible to set the text on creation.

Is there any possible way to make an interactive text field, or do I have to find a workaround to achieve that? (With interactive text field I mean an area of the canvas I can click on and write directly into it.)

kangax
  • 38,898
  • 13
  • 99
  • 135
Kappei
  • 714
  • 2
  • 15
  • 34
  • 1
    what do you mean by interactive text field? – hjpotter92 Apr 04 '12 at 10:13
  • @TheJumpingFrog: He means add text to the canvas and edit it's content later on. – Marcel Apr 04 '12 at 10:19
  • Exactly what Marcel said – Kappei Apr 04 '12 at 10:24
  • What is the protocol here when an answer is out of date? Create a new question, answer it, and link to that question from the original question? Basically the accepted answer is no longer correct and the answer below it is the correct answer for people searching for a solution. – teewuane Jun 18 '14 at 19:04
  • @teewuane you can simply put a comment to the question (like you did) and notify the author that there's a more up-to-date answer. Changing the accepted answer is just a matter of a click :) – Kappei Jun 19 '14 at 09:08

7 Answers7

89

The latest version of fabric.js includes a class IText which incorporates the interaction for editing and selection of text dynamically. try the code below with the latest version of fabric.js

canvas.add(new fabric.IText('Tap and Type', { 
  fontFamily: 'arial black',
  left: 100, 
  top: 100 ,
}));
melwyn pawar
  • 1,766
  • 2
  • 16
  • 21
  • Upvote as offering a better and more up to date answer. – Pherrymason May 27 '14 at 11:39
  • 3
    It is worth noting that this was introduced in fabric.js 1.4. I recently did a custom build with everything and IText was not in that build so I was getting `function is undefined`-like errors. I changed my script source to point at the cdn, `http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js` instead of my own local copy and that fixed my problem. I'm still not sure why IText is not in the custom build though. – teewuane Jun 18 '14 at 19:02
  • Thanks for this. How can I add new controls to Text or IText object? I want to show Color Picker, Bold, Italic, Underline, Font Selector etc when user clicks on text field. Are there any plugins our there for this? – Ashit Vora Feb 22 '15 at 05:52
  • Hi you can add a color picker by referencing the created object and chaging its color property check out http://www.letztroll.com/#!/create/ if you click onto the text tool from the tool box it creates a text box as well as a referencing layer that can relate do the text object – melwyn pawar Feb 23 '15 at 18:42
  • can u suggest how to start writing text at a particular coordinate?? @melwynpawar – Amanjot Kaur Nov 02 '15 at 10:48
  • @Ku Hye Sun in the above code the "left:100" & "top:100" indicate the coordinate positions on the canvas. – melwyn pawar Nov 08 '15 at 20:24
15

I recently built a mind mapping tool using fabric.js and I encountered the same problem.

To achieve what you have described (changing the text on and after creation of textual elements in the canvas), I used jquery to detect the keydown event. Assuming you have selected the desired textual element in the fabric canvas the following snippet will change the text.

$(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;
        }
    }
});

Using this technique, I can select a text element in the fabric canvas, begin typing and the text is replaced. You could change it so it didn't erase the text each time you select the element.

There are some compromises with this method. For example you cannot select text as if it were in a regular HTML input text element and there is no blinking cursor, therefore the "virtual" cursor is always at the end of the text.

If you really wanted to you could draw a blinking cursor at the end of the text.

Brett Gregson
  • 5,867
  • 3
  • 42
  • 60
Tyson
  • 681
  • 7
  • 10
  • Thanks a lot. As I thought, seems there's no built-in technique to do this natively in fabricjs. This is exactly the kind of workaround I was thinking about. – Kappei Apr 10 '12 at 07:44
  • Awesome piece of code Tyson, I just fixed a small bug for when a user pressed the shift key by itself (it was clearing the text). I just added an else if to make it do nothing – Brett Gregson Nov 11 '12 at 22:16
  • I am not able to enter special characters though. Is there a fix for that? Also, the function "canvasBeforeSelectionCleared()" is not defined. – Siddhant Dec 26 '12 at 07:12
  • i used this code it working fine but in the edit text field canvas not showing the cursor ? @Kappei – Sanjay Nakate Oct 19 '13 at 10:19
5

I guess its too late, but this might be of help to others.

There is a demo on fabricjs to do the exact same thing.

anonymoose
  • 1,169
  • 2
  • 21
  • 62
pawan jain
  • 139
  • 2
  • 6
4
    text.set({ text: newText }); //Change the text
    canvas.renderAll(); //Update the canvas

That was what I was looking for :) Thanks alot!

Kim Jansson
  • 150
  • 1
  • 6
0

assuming you have both the canvas and the context as variables in your script:

// 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);
Saturnix
  • 10,130
  • 17
  • 64
  • 120
  • This is not what I'm looking for. I know how to set a text in a canvas, what I asked for was a way to get an _interactive_ text field with fabricjs, if possible: with interactive text field I mean an area of the canvas I can click on and write directly into it. (Modified the original question for clarity) – Kappei Apr 05 '12 at 08:07
0

Try this(this is from my application):

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,
        });
Kalvin Klien
  • 911
  • 1
  • 12
  • 32
0

Fabric has an interactive text object.

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

Note

to edit text double click the text field to enter edit mode

Xraybrain
  • 9
  • 1