interactive text box with fabricjs - javascript

I am working fabricjs textbox. I wrote the following code to change text options like font-size, font-weight, line-height.
My code is working but the problem is When I select a textbox object and change font-size or font weight or line height it does not work unless I click on canvas outside textbox.
But I want to change these value when I make change on input fields. My code are as following:
canvas = new fabric.Canvas('canvas');
// Add Text to Canvas
$('#canvasAddText').on('click', function(){
var _text = $('#canvasText').val();
var _color = $('#textColor').val();
var _fontSize = $('#fontSize').val();
var _fontWeight = $('#fontWeight').val();
var _lineHeight = $('#lineHeight').val();
var TextBox = new fabric.Textbox( _text, {
top: 30,
left: 30,
width: 200,
fill: _color,
fontSize: _fontSize,
fontWeight: _fontWeight,
lineHeight: _lineHeight,
fontFamily: 'Comic Sans',
textDecoration: 'none',
textAlign: 'left',
});
canvas.add(TextBox);
});
// Change Font Size
$('#fontSize').on('change', function (){
canvas.getActiveObject().setFontSize($(this).val());
});
// Change Font Weight
$('#fontWeight').on('change', function (){
canvas.getActiveObject().setFontWeight($(this).val());
});
// Change Line Height
$('#lineHeight').on('change', function (){
canvas.getActiveObject().setLineHeight($(this).val());
});

You should trigger object modified event and then renderAll() function to make sure changes reflect. Below is example code which you need to have for on change event of font size.
// Change Font Size
$('#fontSize').on('change', function (){
canvas.getActiveObject().setFontSize($(this).val());
canvas.trigger("object:modified",{target: canvas.getActiveObject()});
canvas.renderAll();
});

Related

fabricjs how to double-click a picture(or rect) to edit text and name it

How to combine images and text with fabricjs and edit text when double clicking the combined object,
Still combine after editing text,
Please tell me how to edit text when rendering image and text combinations
const canvas = new fabric.Canvas("canvas");
// a rect
const rect = new fabric.Rect({
stroke: "#000",
strokeWidth: 1,
fill: "#ccc",
left: 170,
top: 80,
width: 50,
height: 50
});
// a text for describe rect
const text = new fabric.IText("describe rect", {
fontFamily: "Comic Sans",
fontSize: 14,
stroke: "#000",
strokeWidth: 1,
fill: "#000",
left: 170,
top: 80
});
// 1 Combine the above two things but can not edit text
// 2 use LabeledRect also
Based on your requirements, you can
Create a subclass of Image class (or whatever object that you need to attach a label to)
Make it create an instance of IText or Textbox and save an internal reference to it
By hooking into the event handlers on the image (e.g. double click), manually manage the events of the text. Make sure to keep the position and dimensions of the text updated when the image is modified.
Take a look at this answer: Resize Fabric Rect without resizing Textbox. It does something very similar to what you've described.

Fabric.js iText : How to do text selection on iText while not allowing text modification?

I have been reading docs and forums to solve this problem, but could not find an answer.
var t1 = canvas.t1 = _t1 = new fabric.IText(text1, {
left: 100,
top: 50,
editable: true,
selectable: false,
width: 300,
height: 150,
fontFamily: 'Helvetica',
fontSize: 20,
fill: '#f4b642',
} );
var t2 = canvas.t2 = _t1 = new fabric.IText(text2, {
left: 200,
top: 150,
editable: false,
selectable: true,
width: 300,
height: 150,
fontFamily: 'Helvetica',
fontSize: 20,
fill: '#333',
} );
canvas.add(t1,t2);
t1.enterEditing();
https://jsfiddle.net/qgeryu9o/2/
As shown on the fiddle by the upper iText element , I would like to
access directly to the text at page load , this just to select
some words or sentences.
Using itext.enterEditing(), as on the upper itext box, this works fine except
that it allows also what I do not want : to delete, add, or modify the text.
In setting itext.editable to false ( as on fiddle lower iText element)
the text cannot be modified , but there is no way to show selection.
I tried to catch keydown events on the container div as suggested on this thread.
fabric.js canvas listen for keyboard events?
But it does not work for me (tried on Chrome, Firefox), the event is not fired on itext in editing mode.
Thanks for your help.
Mike
Since I could not find a Fabric.js parameter allowing selection but no editing, I used a work-around.
At first I wanted to remove listeners set on the hidden textarea.
But, as bind() is used , there is no way to remove these listeners
without modifying fabric.js :
fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));
fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this));
So, I just have overwritten the onInput() and onKeydown methods.
t1.onInput = function() {
console.log("no input on t1") ;
return false } ;
t1.onKeyDown = function() {
console.log("no onKeyDown on t1") ;
return false } ;
It works fine as shown on the corrected fiddle:
https://jsfiddle.net/qgeryu9o/4/
If there is a more direct way to get the same result (selection but no edition), I would be happy to hear about it.
Thanks

fabric.js cannot get the text aligned witht the textAlign

I cannot get the textAlign working in fabric.js The fontSize, fontBackground work properly, but not textAlign. Am I missing something?
var canvas = new fabric.Canvas('myCanvas');
$('button.addText').click(function() {
var text = new fabric.Text($(this).siblings().val(), {
textAlign: 'center',
fontSize: 40
});
canvas.add(text);
});
var canvas = new fabric.Canvas('myCanvas');
var align = ["left", "center", "right" , "justify"];
var el = document.getElementById('res');
var txt = 'FabricJS \n is \nAwsome';
var text = new fabric.Text(txt, {
textAlign: 'left', //"left", "center", "right" or "justify".
width:450,
fontSize: 40
});
canvas.add(text);
changeAlign();
function changeAlign(){
var val = align[Math.floor(Math.random() * align.length)];
text.set('textAlign',val);
el.innerHTML = 'Text Alignment : ' +val;
canvas.setActiveObject(text);
canvas.renderAll();
}
canvas {
border : 2px dotted blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
<canvas id="myCanvas" width="600" height="300"></canvas><br>
<button onclick='changeAlign()'>Change align</button><p id='res'></p>
#AndreaBogazzi He is right. In Text, box depends on the width of first line, if you want then it will work for multi line texts . Check Snippet.
I guess the main point is that if the text is one line only, fabric will size the text bounding box to the necessary length and there will not be any alignment to do.
If the text is multiline the alignment should work.
The alignment is INSIDE the box and is not the direction where the box grows when the text grows.
It depends on the type of the object. If you have for example IText or Text the alignment will work only in the area of the canvas itself.
For example if you want to align an IText type on the center of the canvas you would use:
canvas.getActiveObject().centerV();
canvas.getActiveObject().setCoords();
canvas.renderAll();
If you want to center the text itself it would apply only to Textbox type, you would then be able to use:
canvas.getActiveObject().textAlign = "center";

Fabricjs Textbox make the text shrink to fit

I would define a text box (single-line)
By default, with a character size of 16 (for example)
When the text gets bigger than the text box, I do not want it to wrap or the text box gets bigger, I want the text size to fit the maximum size of the text box. text. When the text returns to a smaller size, it can resume its initial size (in our example 16). Possibly manage a minimum size
If you have an idea, I take :)
thanks in advance
Test Case : http://jsfiddle.net/Da7SP/273/
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');
// ADD YOUR CODE HERE
var canvas = window._canvas = new fabric.Canvas('c');
var t1 = new fabric.Textbox('My Text', {
width: 200,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center'
});
var t2 = new fabric.Textbox('My text is longer, but I do not want the box to grow, or the text to wrap. I only want the text to fit the available size', {
width: 200,
height: 200,
top: 250,
left: 5,
fontSize: 16,
textAlign: 'center'
});
canvas.add(t1);
canvas.add(t2);
A small video to explain what I want :
When the text gets bigger than the text box, I want the text size fit the maximum size of the text box.
This is a basic fiddle that can replicate your idea.
The point is that you have an event that fires on every text change and that can be used to do something before the textbox is rendered.
In this case i m shrinking font size based on a non standard parameter i added to textbox called fixedWidth
// ADD YOUR CODE HERE
var canvas = new fabric.Canvas('c');
var t1 = new fabric.Textbox('MyText', {
width: 150,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center',
fixedWidth: 150
});
canvas.on('text:changed', function(opt) {
var t1 = opt.target;
if (t1.width > t1.fixedWidth) {
t1.fontSize *= t1.fixedWidth / (t1.width + 1);
t1.width = t1.fixedWidth;
}
});
canvas.add(t1);
canvas {
border: 1px solid #999;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
Here's a similar answer to https://stackoverflow.com/a/41335051/1469525 but this example modifies the fontSize up to a maxFontSize (the initial fontSize). This allows the text to shrink and then grow back to the original size, as well as preventing line wraps.
(Note, if you use this, you'll have to find a way to prevent the user from using the enter key. I put in a check that basically cancels it if an enter key is detected. My app actually has a separate form to enter the text, so I can control prevention through normal javascript. I'm not quite sure how to do that directly on a canvas element when it is editable like here...)
var canvas = new fabric.Canvas('c');
var t1 = new fabric.Textbox('MyText', {
width: 150,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center',
maxFontSize: 16,
});
canvas.on('text:changed', function(opt) {
var t1 = opt.target;
if (t1.text.match(/[\r\n]/)) return;
t1.set({
fontSize: t1.maxFontSize,
});
while (t1._textLines.length > 1) {
t1.set({
fontSize: t1.fontSize - 1,
});
}
});
canvas.add(t1);
canvas {
border: 1px solid #999;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

In raphaeljs, is there a way to place text within an object to keep rollover state

In creating a svg map using raphael js where I have hover states. How ever I am trying to write the country names onto the map. The problem I am facing is the names become their own object and block the country so I loose hover and click when the cursor is directly over the text. Is there a way where I can draw the text and not have it block the map. I've tried set() but with no sucess.
Thanks,
What I have below doesn't have the text() or print() included:
var r = Raphael('map', 1450, 2180);
arr = new Array();
for (var country in paths) {
var obj = r.path(paths[country].path);
countryName = paths[country].name;
color = paths[country].color;
scolor = paths[country].stroke;
obj.attr({fill:color,stroke:scolor,
'stroke-width': 1,
'stroke-linejoin': 'round'});
arr[obj.id] = country;
obj
.hover(function(){
console.log(arr[this.id]);
this.animate({
fill: paths[arr[this.id]].hover
}, 300);
}, function(){
this.animate({
fill: paths[arr[this.id]].color
}, 300);
})
});
Try setting the pointer-events attribute to none for the text elements.
Documentation:
http://www.w3.org/TR/SVG/interact.html#PointerEventsProperty

Categories