From 40267e0d44aa37e2ece8088b3f1f5500c8065108 Mon Sep 17 00:00:00 2001 From: gloryyin Date: Mon, 1 Aug 2022 02:09:00 +0800 Subject: [PATCH] fix: add ellipsis for last line --- src/shapes/Text.ts | 81 +++++++++++++++++++++++++++++++----------- test/unit/Text-test.ts | 33 +++++++++++++++++ 2 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/shapes/Text.ts b/src/shapes/Text.ts index e2260ee1..b4781923 100644 --- a/src/shapes/Text.ts +++ b/src/shapes/Text.ts @@ -492,27 +492,10 @@ export class Text extends Shape { this._addTextLine(match); textWidth = Math.max(textWidth, matchWidth); currentHeightPx += lineHeightPx; - if ( - !shouldWrap || - (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx) - ) { - var lastLine = this.textArr[this.textArr.length - 1]; - if (lastLine) { - if (shouldAddEllipsis) { - var haveSpace = - this._getTextWidth(lastLine.text + ELLIPSIS) < maxWidth; - if (!haveSpace) { - lastLine.text = lastLine.text.slice( - 0, - lastLine.text.length - 3 - ); - } - - this.textArr.splice(this.textArr.length - 1, 1); - this._addTextLine(lastLine.text + ELLIPSIS); - } - } + var shouldHandleEllipsis = this._shouldHandleEllipsis(currentHeightPx); + if (shouldHandleEllipsis) { + this._addEllipsisIfNecessary(shouldHandleEllipsis); /* * stop wrapping if wrapping is disabled or if adding * one more line would overflow the fixed height @@ -542,6 +525,8 @@ export class Text extends Shape { this._addTextLine(line); currentHeightPx += lineHeightPx; textWidth = Math.max(textWidth, lineWidth); + + this._addEllipsisIfNecessary(this._shouldHandleEllipsis(currentHeightPx)); } // if element height is fixed, abort if adding one more line would overflow if (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx) { @@ -559,6 +544,62 @@ export class Text extends Shape { this.textWidth = textWidth; } + /** + * whether to handle ellipsis, there are two cases: + * 1. the current line is the last line + * 2. wrap is NONE + * @param {Number} currentHeightPx + * @returns + */ + _shouldHandleEllipsis(currentHeightPx: number): boolean { + var fontSize = +this.fontSize(), + lineHeightPx = this.lineHeight() * fontSize, + height = this.attrs.height, + fixedHeight = height !== AUTO && height !== undefined, + padding = this.padding(), + maxHeightPx = height - padding * 2, + wrap = this.wrap(), + shouldWrap = wrap !== NONE; + + return (!shouldWrap || (fixedHeight && currentHeightPx + lineHeightPx > maxHeightPx)); + } + + /** + * add ellipses at the end of the line if necessary + * @param {Boolean} shouldHandleEllipsis + * @returns + */ + _addEllipsisIfNecessary(shouldHandleEllipsis: boolean): void { + var width = this.attrs.width, + fixedWidth = width !== AUTO && width !== undefined, + padding = this.padding(), + maxWidth = width - padding * 2, + shouldAddEllipsis = this.ellipsis(); + + if (!shouldHandleEllipsis) { + return; + } + + var lastLine = this.textArr[this.textArr.length - 1]; + if (!lastLine || !shouldAddEllipsis) { + return; + } + + if (fixedWidth) { + var haveSpace = + this._getTextWidth(lastLine.text + ELLIPSIS) < maxWidth; + if (!haveSpace) { + lastLine.text = lastLine.text.slice( + 0, + lastLine.text.length - 3 + ); + } + } + + this.textArr.splice(this.textArr.length - 1, 1); + this._addTextLine(lastLine.text + ELLIPSIS); + } + // for text we can't disable stroke scaling // if we do, the result will be unexpected getStrokeScaleEnabled() { diff --git a/test/unit/Text-test.ts b/test/unit/Text-test.ts index 42bb8a87..77c88016 100644 --- a/test/unit/Text-test.ts +++ b/test/unit/Text-test.ts @@ -487,6 +487,39 @@ describe('Text', function () { } }); + // ====================================================== + it('multiline with ellipsis and lineWidth less than maxWidth', function () { + var stage = addStage(); + var layer = new Konva.Layer(); + + var text = new Konva.Text({ + x: 10, + y: 10, + text: "HEADING\nAll the\n world's a stage, merely players. They have theirrrrrrr exits and theirrrrr entrances; And one man in his time plays many parts.", + fontSize: 14, + fontFamily: 'Arial', + fontStyle: 'normal', + width: 100, + padding: 0, + align: 'center', + height: 30, + ellipsis: true, + }); + + layer.add(text); + stage.add(layer); + + assert.equal(text.textArr.length, 2); + assert.equal(text.textArr[1].text.slice(-1), '…'); + + if (isBrowser) { + assert.equal( + layer.getContext().getTrace(false, true), + "clearRect(0,0,578,200);save();transform(1,0,0,1,10,10);font=normal normal 14px Arial;textBaseline=middle;textAlign=left;translate(0,0);save();fillStyle=black;fillText(HEADING,18,7);restore();save();fillStyle=black;fillText(All the…,23,21);restore();restore();" + ); + } + }); + // ====================================================== it('make sure we respect false for ellipsis', function () { var stage = addStage();