Sometime in 2012 I was looking for a solution to wrapping text in fabric.js. To my dismay nothing existed, so I wrote a quick pure function that will do it. Thanks to charalampos for adding text adjustment capability.
Someone requested a fiddle, so here it is, full code included below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
function wrapCanvasText(t, canvas, maxW, maxH, justify) { if (typeof maxH === "undefined") { maxH = 0; } var words = t.text.split(" "); var formatted = ''; // This works only with monospace fonts justify = justify || 'left'; // clear newlines var sansBreaks = t.text.replace(/(\r\n|\n|\r)/gm, ""); // calc line height var lineHeight = new fabric.Text(sansBreaks, { fontFamily: t.fontFamily, fontSize: t.fontSize }).height; // adjust for vertical offset var maxHAdjusted = maxH > 0 ? maxH - lineHeight : 0; var context = canvas.getContext("2d"); context.font = t.fontSize + "px " + t.fontFamily; var currentLine = ''; var breakLineCount = 0; n = 0; while (n < words.length) { var isNewLine = currentLine == ""; var testOverlap = currentLine + ' ' + words[n]; // are we over width? var w = context.measureText(testOverlap).width; if (w < maxW) { // if not, keep adding words if (currentLine != '') currentLine += ' '; currentLine += words[n]; // formatted += words[n] + ' '; } else { // if this hits, we got a word that need to be hypenated if (isNewLine) { var wordOverlap = ""; // test word length until its over maxW for (var i = 0; i < words[n].length; ++i) { wordOverlap += words[n].charAt(i); var withHypeh = wordOverlap + "-"; if (context.measureText(withHypeh).width >= maxW) { // add hyphen when splitting a word withHypeh = wordOverlap.substr(0, wordOverlap.length - 2) + "-"; // update current word with remainder words[n] = words[n].substr(wordOverlap.length - 1, words[n].length); formatted += withHypeh; // add hypenated word break; } } } while (justify == 'right' && context.measureText(' ' + currentLine).width < maxW) currentLine = ' ' + currentLine; while (justify == 'center' && context.measureText(' ' + currentLine + ' ').width < maxW) currentLine = ' ' + currentLine + ' '; formatted += currentLine + '\n'; breakLineCount++; currentLine = ""; continue; // restart cycle } if (maxHAdjusted > 0 && (breakLineCount * lineHeight) > maxHAdjusted) { // add ... at the end indicating text was cutoff formatted = formatted.substr(0, formatted.length - 3) + "...\n"; currentLine = ""; break; } n++; } if (currentLine != '') { while (justify == 'right' && context.measureText(' ' + currentLine).width < maxW) currentLine = ' ' + currentLine; while (justify == 'center' && context.measureText(' ' + currentLine + ' ').width < maxW) currentLine = ' ' + currentLine + ' '; formatted += currentLine + '\n'; breakLineCount++; currentLine = ""; } // get rid of empy newline at the end formatted = formatted.substr(0, formatted.length - 1); var ret = new fabric.Text(formatted, { // return new text-wrapped text obj left: t.left, top: t.top, fill: t.fill, fontFamily: t.fontFamily, fontSize: t.fontSize, originX: t.originX, originY: t.originY, angle: t.angle, }); return ret; } |
You are amazing! Thanks!