Reputation: 675
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.
Upvotes: 30
Views: 23807
Reputation: 1
A solution could be to create a new Fabric class that extends the Fabric.Textbox class. Here's an example:
const LimitedTextbox = fabric.util.createClass(fabric.Textbox, {
onInput: function (e: any) {
const oldText = this.text;
/**
* Sometimes, when you insert a line break, it doesn't appear to Fabric as an 'insertLineBreak' but simply sets the date to null.
* Therefore, it's important to check that it's not deleting any characters, and if the date is null, it means that a new line is being inserted
*/
if (e.inputType === 'insertLineBreak' || (e.inputType !== 'deleteContentBackward' && !e.data)) {
this._textBeforeEdit = oldText;
this.hiddenTextarea.value = oldText;
this.text = oldText;
return;
} else if (e.inputType !== 'deleteContentBackward') {
if (this.width > this.maxWidth) {
this._textBeforeEdit = oldText;
this.hiddenTextarea.value = oldText;
this.text = oldText;
// If you want to enable scaling to keep writing, there are issues when you delete a portion of text and not just a single character
//
// this.fontSizeList = [...(this.fontSizeList || []), this.fontSize];
// this.fontSize *= this.maxWidth / (this.width + 1);
// this.width = this.maxWidth;
return;
}
if (this._textLines.length > this.maxLines) {
this._textBeforeEdit = oldText;
this.hiddenTextarea.value = oldText;
this.text = oldText;
return;
}
} else {
// If you want to enable scaling to keep writing, there are issues when you delete a portion of text and not just a single character
//
// const lastFontSize = this.fontSizeList?.pop();
// if (lastFontSize) {
// this.fontSize = lastFontSize;
// }
/**
* It's needed because otherwise, if I write many characters, he automatically adjusts the width even if the visible text doesn't change.
* So, every time I delete something, I reset the width.
* I do it during deletion; otherwise, if I do it in the maxWidth check, I never block it, and it would keep writing
*/
this.width = this.maxWidth;
}
this.callSuper('onInput', e);
},
});
...
textbox = new LimitedTextbox('custom text', {
maxLines: 1,
maxWidth: 100,
});
Upvotes: 0
Reputation: 1219
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>
Upvotes: 3
Reputation: 14741
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>
Upvotes: 31