So I'm trying to replace the text objects on the template with the data.(This is not achieved dynamically, I take the data from server (array of objects) and replace 'name' with dataObj[name]) I am adjusting the fontSize so that text fits its container. The problem I have is when text falls short, text BOX also shrinks even though I don't alter its width and height
I'm adjusting the fontSize with a helper function to make sure content fits. Is there any way to LOCK the height and width of the text 'CONTAINER' (To preserve the look on the design) Please observe the output below. Dimensions are not 'standardized'.
This is how I adjust the font size. Basically providing textObjWidth, textObjHeight, fontSize and text value
I can provide additional info on request.
function getTextWidth(text, fSize, font = 'Helvetica') {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = `${fSize}px ${font}`
return context.measureText(text).width;
}
export function adjustFontSize(maxTextWidth, maxTextHeight, fontSize, text){
let fSize = fontSize;
let currentTextWidth = getTextWidth(text, fSize);
//decrease font size until the text fits
while (currentTextWidth > maxTextWidth || fSize > maxTextHeight) {
fSize -= 1;
currentTextWidth = getTextWidth(text, fSize);
}
return fSize;
}
Text object properties - (used to create the template [image-1])
const textObj = new fabric.Text(formParameterText, {
textBackgroundColor: '#fff',
fill: '#000',
visible,
// scaleToWidth: 1,
textAlign: 'center',
fontFamily: 'Helvetica'
});
How I map values - No alteration on text object width and height whatsoever
for(let i = 0; i < dataToBePrinted.length; i++) {
const userData = dataToBePrinted[i];
const updatedSingleCanvas = {
...eventCard,
objects: eventCard.objects.map(obj => {
if(obj.type === 'image') {
return {...obj, visible: true}
}
if(obj.type === 'text' && userData[obj.text]) {
return { ...obj, selectAble: false, evented: false, text: userData[obj.text], fontSize: adjustFontSize(obj.width, obj.height, obj.fontSize, userData[obj.text]), width: obj.width, height: obj.height}
}
return obj
})
}
Here is the template - designed by the user
Here is the output after mapping data
If I remove fontSize: adjustFontSize(obj.width, obj.height, obj.fontSize, userData[obj.text])
I obtain this output. Which is unacceptable.
OK So I resolved the issue. First off big thanks to @ShaMan123 @fabricjs community on github for providing the solution.
https://github.com/fabricjs/fabric.js/discussions/8367#discussioncomment-3884600 https://github.com/fabricjs/fabric.js/pull/7981
Textbox
'minWidth
: number(px)Imposing minWidth helped me achieve the standardized output. If the content falls short, text is centered and min width is applied, If fontSize is too large, fontSize adjuster function does the work and content fits.In either cases, text fits and design persists.
However, height of the textbox cannot be locked like minWidth. I assume fontSize alters this and dictates its own height. A minHeight property could be useful.
Here are the changes in my code
const textObj = new fabric.Textbox(formParameterText, {
textBackgroundColor: '#fff',
fill: '#000',
visible,
backgroundColor: '#fff',
textAlign: 'center',
fontFamily: 'Helvetica',
editable: false,
});
Mapping - replacing keys with values
const updatedSingleCanvas = {
...eventCard,
objects: eventCard.objects.map(obj => {
if (obj.type === 'image') {
return { ...obj, visible: true }
}
if (obj.type === 'textbox' && userData[obj.text]) {
return {
...obj,
selectAble: false,
evented: false,
text: userData[obj.text],
fontSize: adjustFontSize(obj.width, obj.height, obj.fontSize, userData[obj.text]),
minWidth: obj.width,
//minHeight: obj.height,
//height: obj.height
}
}
return obj
})
}
--Results--
-Result2