2012-04-04 17 views
23

Ich habe in den letzten Wochen viel mit Fabric.js gespielt, aber in Bezug auf Textfelder habe ich es nur als möglich gefunden, den Text bei der Erstellung festzulegen.Interaktive Textfelder mit Fabric.js

Gibt es eine Möglichkeit, ein interaktives Textfeld zu erstellen, oder muss ich einen Workaround finden, um das zu erreichen? (Mit interaktivem Textfeld meine ich einen Bereich der Leinwand ich auf und schreiben kann direkt hinein.)

+1

was meinst du mit interaktivem Textfeld? – hjpotter92

+0

@TheJumpingFrog: Er bedeutet, Text auf der Leinwand hinzuzufügen und den Inhalt später zu bearbeiten. – Marcel

+0

Genau das, was Marcel sagte – Kappei

Antwort

59

Die neueste Version von Fabric.js enthält eine Klasse IText, die die Interaktion für die dynamische Bearbeitung und Auswahl von Text enthält. versuchen Sie den Code unten mit der neuesten Version von fabric.js

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

Upvote als eine bessere und aktuellere Antwort anzubieten. –

+3

Es ist erwähnenswert, dass dies in fabric.js 1.4 eingeführt wurde. Ich habe kürzlich einen Custom Build mit allem gemacht und IText war nicht in diesem Build, also bekam ich "Funktion ist undefiniert" - wie Fehler. Ich änderte meine Skriptquelle, um auf die cdn, "http: // cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js" anstelle meiner eigenen lokalen Kopie zu zeigen und das reparierte meinen Problem. Ich bin mir immer noch nicht sicher, warum IText nicht im benutzerdefinierten Build ist. – teewuane

+0

Dies ist ein Lebensretter –

0

vorausgesetzt, Sie haben sowohl die Leinwand und den Kontext als Variablen in Ihrem Skript:

// 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); 
+0

Dies ist nicht das, was ich suche. Ich weiß, wie man einen Text in einer Leinwand einstellt, was ich wollte, war eine Möglichkeit, ein _interaktives_ Textfeld mit fabricjs zu bekommen, wenn möglich: Mit interaktivem Textfeld meine ich einen Bereich der Leinwand, auf den ich klicken und direkt hinein schreiben kann . (Geändert die ursprüngliche Frage für Klarheit) – Kappei

14

I Ich habe kürzlich ein Mind-Mapping-Tool mit fabric.js erstellt, und ich stieß auf das gleiche Problem.

Um das zu erreichen, was Sie beschrieben haben (den Text beim und nach der Erstellung von Textelementen im Canvas ändern), verwendete ich jquery, um das Keydown-Ereignis zu erkennen. Angenommen, Sie haben das gewünschte Textelement in der Fabric-Zeichenfläche ausgewählt, wird das folgende Snippet den Text ändern.

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

Mit dieser Technik kann ich ein Textelement in das Gewebe Leinwand wählen, beginnen die Eingabe und der Text ersetzt wird. Sie können es ändern, damit es den Text nicht jedes Mal löscht, wenn Sie das Element auswählen.

Es gibt einige Kompromisse mit dieser Methode. Beispielsweise können Sie Text nicht wie in einem normalen HTML-Eingabetextelement auswählen und es gibt keinen blinkenden Cursor. Daher befindet sich der "virtuelle" Cursor immer am Ende des Textes.

Wenn Sie wirklich wollten, könnten Sie einen blinkenden Cursor am Ende des Textes zeichnen.

+0

Vielen Dank. Wie ich dachte, scheint es keine eingebaute Technik zu geben, um dies nativ in Fabricjs zu tun. Dies ist genau die Art von Workaround, über die ich nachgedacht habe. – Kappei

+0

Tolles Stück Code Tyson, ich habe gerade einen kleinen Fehler behoben, wenn ein Benutzer die Shift-Taste gedrückt hat (es löschte den Text). Ich habe gerade ein anderes hinzugefügt, wenn es nichts machen soll –

+0

Ich kann jedoch keine Sonderzeichen eingeben. Gibt es dafür eine Lösung? Auch die Funktion "canvasBeforeSelectionCleared()" ist nicht definiert. – Siddhant

0

Versuchen Sie dies (aus meiner Anwendung ist):

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, 
     }); 
2
text.set({ text: newText }); //Change the text 
    canvas.renderAll(); //Update the canvas 

das war, was ich gesucht :) vielen Dank!