From 5f0427c26915be2d3c52306a986e84ea94d027e5 Mon Sep 17 00:00:00 2001 From: plainheart Date: Wed, 8 May 2024 09:50:37 +0800 Subject: [PATCH 01/13] fix(svg): set `pointer-events` as `visible` when fill/stroke color is `none` in SSR mode & fix invalid `transparent` color issue See apache/echarts#15029 --- src/svg/Painter.ts | 1 + src/svg/core.ts | 2 ++ src/svg/graphic.ts | 10 ++++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/svg/Painter.ts b/src/svg/Painter.ts index 243b3ce50..5d1981c77 100644 --- a/src/svg/Painter.ts +++ b/src/svg/Painter.ts @@ -142,6 +142,7 @@ class SVGPainter implements PainterBase { scope.willUpdate = opts.willUpdate; scope.compress = opts.compress; scope.emphasis = opts.emphasis; + scope.ssr = this._opts.ssr; const children: SVGVNode[] = []; diff --git a/src/svg/core.ts b/src/svg/core.ts index f29cf532d..109282c7e 100644 --- a/src/svg/core.ts +++ b/src/svg/core.ts @@ -159,6 +159,8 @@ export interface BrushScope { * If compress the output string. */ compress?: boolean + + ssr?: boolean } export function createBrushScope(zrId: string): BrushScope { diff --git a/src/svg/graphic.ts b/src/svg/graphic.ts index 096014967..da81eb41a 100644 --- a/src/svg/graphic.ts +++ b/src/svg/graphic.ts @@ -63,13 +63,15 @@ function setStyleAttrs(attrs: SVGVNodeAttrs, style: AllStyleOption, el: Path | T else if (isFillStroke && isPattern(val)) { setPattern(el, attrs, key, scope); } - else if (isFillStroke && val === 'none') { - // When is none, it cannot be interacted when ssr - attrs[key] = 'transparent'; - } else { attrs[key] = val; } + if (isFillStroke && scope.ssr && val === 'none') { + // When is none, it cannot be interacted when ssr + // Setting `pointer-events` as `visible` to make it responding + // See also https://www.w3.org/TR/SVG/interact.html#PointerEventsProperty + attrs['pointer-events'] = 'visible'; + } }, style, el, false); setShadow(el, attrs, scope); From 71bde87710c7484a50d94133e9641e666adf6ebc Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Fri, 28 Jun 2024 09:09:40 +0200 Subject: [PATCH 02/13] fix(env): fix env detection compatibility for node, bun, and deno * fix(env): fix env detection compatibility for node, bun, and deno * bugfix running without navigator.userAgent --------- Co-authored-by: yunyin Co-authored-by: plainheart --- src/core/env.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/env.ts b/src/core/env.ts index cadec6688..a9c7b1926 100644 --- a/src/core/env.ts +++ b/src/core/env.ts @@ -38,8 +38,9 @@ else if (typeof document === 'undefined' && typeof self !== 'undefined') { env.worker = true; } else if ( - typeof navigator === 'undefined' - || navigator.userAgent.indexOf('Node.js') === 0 + (typeof process !== 'undefined' && typeof process.version === 'string') + || (typeof navigator === 'undefined' || typeof navigator.userAgent === 'undefined') + || (env.hasGlobalWindow && 'Deno' in window) ) { // In node env.node = true; From 7e6db609fbc0e950049469aeeeee35f9ab0d2a29 Mon Sep 17 00:00:00 2001 From: plainheart Date: Mon, 1 Jul 2024 16:56:46 +0800 Subject: [PATCH 03/13] chore: exclude some unused dirs and files when publishing to npm --- .npmignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.npmignore b/.npmignore index df8d8f4d5..05c3be8c8 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,8 @@ /doc /test /benchmark +/build +/tsconfig.json .github .vscode @@ -8,3 +10,6 @@ npm-debug.log .DS_Store Thumbs.db Desktop.ini + +.eslintignore +.eslintrc.yaml \ No newline at end of file From c0d7a35b79f8b4d34787bbefaab388ff62f46d33 Mon Sep 17 00:00:00 2001 From: plainheart Date: Tue, 2 Jul 2024 09:35:35 +0800 Subject: [PATCH 04/13] fix(env): try fixing detection for node environment (#1037) --- src/core/env.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/core/env.ts b/src/core/env.ts index a9c7b1926..52e3699ae 100644 --- a/src/core/env.ts +++ b/src/core/env.ts @@ -37,11 +37,7 @@ else if (typeof document === 'undefined' && typeof self !== 'undefined') { // In worker env.worker = true; } -else if ( - (typeof process !== 'undefined' && typeof process.version === 'string') - || (typeof navigator === 'undefined' || typeof navigator.userAgent === 'undefined') - || (env.hasGlobalWindow && 'Deno' in window) -) { +else if (!env.hasGlobalWindow || 'Deno' in window) { // In node env.node = true; env.svgSupported = true; From 6fd084da1d2a3bbfae00109deeaff7113ad9f1e9 Mon Sep 17 00:00:00 2001 From: Zhongxiang Wang Date: Wed, 17 Jul 2024 17:21:12 +0800 Subject: [PATCH 05/13] chore: still publish `build` folder to npm as echarts needs it --- .npmignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.npmignore b/.npmignore index 05c3be8c8..d285b50c4 100644 --- a/.npmignore +++ b/.npmignore @@ -1,7 +1,6 @@ /doc /test /benchmark -/build /tsconfig.json .github .vscode @@ -12,4 +11,4 @@ Thumbs.db Desktop.ini .eslintignore -.eslintrc.yaml \ No newline at end of file +.eslintrc.yaml From e7427159b91b533e001f4be29dd568b3f339cc4a Mon Sep 17 00:00:00 2001 From: Ovilia Date: Thu, 10 Oct 2024 15:57:24 +0800 Subject: [PATCH 06/13] fix(path): using appendData instead of setData for path --- src/tool/path.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tool/path.ts b/src/tool/path.ts index 76c4d099b..a85694947 100644 --- a/src/tool/path.ts +++ b/src/tool/path.ts @@ -389,7 +389,7 @@ function createPathOptions(str: string, opts: SVGPathOption): InnerSVGPathOption const innerOpts: InnerSVGPathOption = extend({}, opts); innerOpts.buildPath = function (path: PathProxy | CanvasRenderingContext2D) { if (isPathProxy(path)) { - path.setData(pathProxy.data); + path.appendPath(pathProxy); // Svg and vml renderer don't have context const ctx = path.getContext(); if (ctx) { From de10c1039e1b461b28078031d91ee36a48909b92 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Thu, 10 Oct 2024 16:38:16 +0800 Subject: [PATCH 07/13] fix(path): init data in appendData when is null --- src/core/PathProxy.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/PathProxy.ts b/src/core/PathProxy.ts index 08c789e62..5044ad2c8 100644 --- a/src/core/PathProxy.ts +++ b/src/core/PathProxy.ts @@ -392,6 +392,9 @@ export default class PathProxy { if (hasTypedArray && (this.data instanceof Float32Array)) { this.data = new Float32Array(offset + appendSize); } + else if (this.data == null) { + this.data = []; + } for (let i = 0; i < len; i++) { const appendPathData = path[i].data; for (let k = 0; k < appendPathData.length; k++) { From 55b9232a58ad6882db5eaf8920aa7ae2b3760cb8 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Fri, 11 Oct 2024 10:19:50 +0800 Subject: [PATCH 08/13] fix(path): init data in appendData when is null --- src/core/PathProxy.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/PathProxy.ts b/src/core/PathProxy.ts index 5044ad2c8..5511473a7 100644 --- a/src/core/PathProxy.ts +++ b/src/core/PathProxy.ts @@ -389,12 +389,9 @@ export default class PathProxy { for (let i = 0; i < len; i++) { appendSize += path[i].len(); } - if (hasTypedArray && (this.data instanceof Float32Array)) { + if (hasTypedArray && (this.data instanceof Float32Array || !this.data)) { this.data = new Float32Array(offset + appendSize); } - else if (this.data == null) { - this.data = []; - } for (let i = 0; i < len; i++) { const appendPathData = path[i].data; for (let k = 0; k < appendPathData.length; k++) { From a6dde173583630cbbf4c5ceeff92644915be51de Mon Sep 17 00:00:00 2001 From: Bill Collins Date: Thu, 7 Nov 2024 09:37:26 +0000 Subject: [PATCH 09/13] Relax tslib requirement specifier --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e7b0167b1..022dfcd8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "5.6.0", "license": "BSD-3-Clause", "dependencies": { - "tslib": "2.3.0" + "tslib": "^2.3.0" }, "devDependencies": { "@microsoft/api-extractor": "^7.7.2", diff --git a/package.json b/package.json index 91553bc3c..cbe82a86c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "module": "index.js", "main": "dist/zrender.js", "dependencies": { - "tslib": "2.3.0" + "tslib": "^2.3.0" }, "sideEffects": [ "lib/canvas/canvas.js", From 0e01b016cc073e8ff4f06c869b4fd6bd738e46ee Mon Sep 17 00:00:00 2001 From: Ovilia Date: Wed, 13 Nov 2024 14:06:36 +0800 Subject: [PATCH 10/13] chore: revert tslib version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cbe82a86c..91553bc3c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "module": "index.js", "main": "dist/zrender.js", "dependencies": { - "tslib": "^2.3.0" + "tslib": "2.3.0" }, "sideEffects": [ "lib/canvas/canvas.js", From 8aeb055bcf46b04b91b831f65dad5b77aef2d5ca Mon Sep 17 00:00:00 2001 From: Ovilia Date: Wed, 13 Nov 2024 15:59:55 +0800 Subject: [PATCH 11/13] chore: revert tslib package-lock.json --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 022dfcd8f..e7b0167b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "5.6.0", "license": "BSD-3-Clause", "dependencies": { - "tslib": "^2.3.0" + "tslib": "2.3.0" }, "devDependencies": { "@microsoft/api-extractor": "^7.7.2", From f7cf14f31ea2c35e84e3b2fa8d01503ec1156e27 Mon Sep 17 00:00:00 2001 From: 100pah Date: Sat, 16 Nov 2024 19:12:56 +0800 Subject: [PATCH 12/13] fix: `boundingRect.x` of text is incorrect when overflow: 'truncate'. Close apache/echarts#18306 . And ecomfe/zrender#1091 located the problematic code successfully but the fix was not entirely correct. --- src/graphic/Text.ts | 2 +- test/text-overflow.html | 128 ++++++++++++++++++++-------------------- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/graphic/Text.ts b/src/graphic/Text.ts index d7fd9f27e..9dfe1fbf1 100644 --- a/src/graphic/Text.ts +++ b/src/graphic/Text.ts @@ -602,7 +602,7 @@ class ZRText extends Displayable implements GroupLike { if (fixedBoundingRect) { el.setBoundingRect(new BoundingRect( - adjustTextX(subElStyle.x, style.width, subElStyle.textAlign as TextAlign), + adjustTextX(subElStyle.x, contentWidth, subElStyle.textAlign as TextAlign), adjustTextY(subElStyle.y, calculatedLineHeight, subElStyle.textBaseline as TextVerticalAlign), /** * Text boundary should be the real text width. diff --git a/test/text-overflow.html b/test/text-overflow.html index ac9191f52..898b9b151 100644 --- a/test/text-overflow.html +++ b/test/text-overflow.html @@ -24,79 +24,90 @@ var zr = zrender.init(document.getElementById('main'), { renderer: window.__ZRENDER__DEFAULT__RENDERER__ }); + const config = { search: '', - width: 400, + width: 200, height: 400, fontSize: 13, fixedLineHeight: false, lineHeight: 14, rich: true, - breakAll: false + overflow: 'break', + lineOverflow: 'truncate', + align: null } - - var enText = new zrender.Text({ - style: { - text: LARGE_TEXT_EN, - fontSize: config.fontSize, - width: config.width, - padding: 10, - borderColor: '#000', - borderWidth: 1, - - overflow: 'break', - lineOverflow: 'truncate', - ellipsis: '…' - } - }); - zr.add(enText); - - var cnText = new zrender.Text({ - style: { - text: LARGE_TEXT_ZH, - fontSize: config.fontSize, - width: config.width, - padding: 10, - borderColor: '#000', - borderWidth: 1, - - overflow: 'break', - lineOverflow: 'truncate', - ellipsis: '…', - - x: config.width + 100 - } + const gui = new dat.GUI(); + gui.add(config, 'search').onChange(update); + gui.add(config, 'width', 10, 300).onChange(update); + gui.add(config, 'height', 10, 1600).onChange(update); + gui.add(config, 'fontSize', 1, 30).onChange(update); + gui.add(config, 'fixedLineHeight').onChange(update); + gui.add(config, 'lineHeight', 12, 50).onChange(update); + gui.add(config, 'rich').onChange(update); + gui.add(config, 'overflow', ['break', 'breakAll', 'truncate', 'none']).onChange(update); + gui.add(config, 'lineOverflow', ['truncate', null]).onChange(update); + gui.add(config, 'align', [null, 'left', 'center', 'right']).onChange(update); + + const texts = [ + LARGE_TEXT_EN, + LARGE_TEXT_ZH, + 'abcde', + '红黄蓝' + ]; + const textElementList = []; + texts.forEach(text => { + var el = new zrender.Text({ + style: { + text: text, + } + }); + zr.add(el); + textElementList.push(el); }); - zr.add(cnText); - const TEXTS = [LARGE_TEXT_EN, LARGE_TEXT_ZH]; function update() { - enText.style.width = cnText.style.width = config.width; - enText.style.height = cnText.style.height = config.height; - - enText.style.overflow = config.breakAll ? 'breakAll' : 'break'; - - cnText.style.x = config.width + 100; - - enText.style.rich = cnText.style.rich = config.rich ? { - highlight: { - // padding: 4, - backgroundColor: 'yellow', - fontSize: 20 + let lastTextElement = null; + + textElementList.forEach((text, idx) => { + + text.style.padding = 10; + text.style.borderColor = '#000'; + text.style.borderWidth = 1; + text.style.ellipsis = '…'; + + text.style.fontSize = config.fontSize; + text.style.width = config.width; + text.style.height = config.height; + text.style.overflow = config.overflow; + text.style.lineOverflow = config.lineOverflow; + text.style.align = config.align; + + text.style.rich = config.rich ? { + highlight: { + // padding: 4, + backgroundColor: 'yellow', + fontSize: 20 + } + } : null; + + text.style.x = lastTextElement + ? lastTextElement.style.x + lastTextElement.style.width + 50 + : 0; + lastTextElement = text; + + if (text.style.__originalText == null) { + text.style.__originalText = text.style.text; } - } : null; - - [enText, cnText].forEach((text, idx) => { - text.style.fontSize = cnText.style.fontSize = config.fontSize; if (config.search) { - text.style.text = TEXTS[idx].replace( + text.style.text = text.style.__originalText.replace( new RegExp(config.search, 'g'), `{highlight|${config.search}}` ); } else { - text.style.text = TEXTS[idx]; + text.style.text = text.style.__originalText; } if (!config.fixedLineHeight) { @@ -113,15 +124,6 @@ zr.refreshImmediately(); console.timeEnd('render'); } - const gui = new dat.GUI(); - gui.add(config, 'search').onChange(update); - gui.add(config, 'width', 100, 700).onChange(update); - gui.add(config, 'height', 10, 1600).onChange(update); - gui.add(config, 'fontSize', 1, 30).onChange(update); - gui.add(config, 'fixedLineHeight').onChange(update); - gui.add(config, 'lineHeight', 12, 50).onChange(update); - gui.add(config, 'rich').onChange(update); - gui.add(config, 'breakAll').onChange(update); update(); From 92dbb390b93e3eed25d91c1da3af105251b24aed Mon Sep 17 00:00:00 2001 From: 100pah Date: Mon, 18 Nov 2024 19:34:45 +0800 Subject: [PATCH 13/13] feat: support output the state `isTruncated` in `Text` element, which can be used in the upper program like echarts tooltip, as required by apache/echarts#16315 . --- src/graphic/Text.ts | 10 +++ src/graphic/helper/parseText.ts | 72 +++++++++++++--- test/text-overflow.html | 144 ++++++++++++++++++-------------- 3 files changed, 152 insertions(+), 74 deletions(-) diff --git a/src/graphic/Text.ts b/src/graphic/Text.ts index d7fd9f27e..4bb77d714 100644 --- a/src/graphic/Text.ts +++ b/src/graphic/Text.ts @@ -275,6 +275,12 @@ class ZRText extends Displayable implements GroupLike { */ innerTransformable: Transformable + // Be `true` if and only if the result text is modified due to overflow, due to + // settings on either `overflow` or `lineOverflow`. Based on this the caller can + // take some action like showing the original text in a particular tip. + // Only take effect after rendering. So do not visit it before it. + isTruncated: boolean + private _children: (ZRImage | Rect | TSpan)[] = [] private _childCursor: 0 @@ -497,6 +503,8 @@ class ZRText extends Displayable implements GroupLike { const defaultStyle = this._defaultStyle; + this.isTruncated = !!contentBlock.isTruncated; + const baseX = style.x || 0; const baseY = style.y || 0; const textAlign = style.align || defaultStyle.align || 'left'; @@ -635,6 +643,8 @@ class ZRText extends Displayable implements GroupLike { const textAlign = style.align || defaultStyle.align; const verticalAlign = style.verticalAlign || defaultStyle.verticalAlign; + this.isTruncated = !!contentBlock.isTruncated; + const boxX = adjustTextX(baseX, outerWidth, textAlign); const boxY = adjustTextY(baseY, outerHeight, verticalAlign); let xLeft = boxX; diff --git a/src/graphic/helper/parseText.ts b/src/graphic/helper/parseText.ts index 275e36b0d..87a0bd1fa 100644 --- a/src/graphic/helper/parseText.ts +++ b/src/graphic/helper/parseText.ts @@ -44,8 +44,25 @@ export function truncateText( ellipsis?: string, options?: InnerTruncateOption ): string { + const out = {} as Parameters[0]; + truncateText2(out, text, containerWidth, font, ellipsis, options); + return out.text; +} + +// PENDING: not sure whether `truncateText` is used outside zrender, since it has an `export` +// specifier. So keep it and perform the interface modification in `truncateText2`. +function truncateText2( + out: {text: string, isTruncated: boolean}, + text: string, + containerWidth: number, + font: string, + ellipsis?: string, + options?: InnerTruncateOption +): void { if (!containerWidth) { - return ''; + out.text = ''; + out.isTruncated = false; + return; } const textLines = (text + '').split('\n'); @@ -53,11 +70,16 @@ export function truncateText( // FIXME // It is not appropriate that every line has '...' when truncate multiple lines. + let isTruncated = false; + const truncateOut = {} as Parameters[0]; for (let i = 0, len = textLines.length; i < len; i++) { - textLines[i] = truncateSingleLine(textLines[i], options as InnerPreparedTruncateOption); + truncateSingleLine(truncateOut, textLines[i], options as InnerPreparedTruncateOption); + textLines[i] = truncateOut.textLine; + isTruncated = isTruncated || truncateOut.isTruncated; } - return textLines.join('\n'); + out.text = textLines.join('\n'); + out.isTruncated = isTruncated; } function prepareTruncateOptions( @@ -104,19 +126,27 @@ function prepareTruncateOptions( return preparedOpts; } -function truncateSingleLine(textLine: string, options: InnerPreparedTruncateOption): string { +function truncateSingleLine( + out: {textLine: string, isTruncated: boolean}, + textLine: string, + options: InnerPreparedTruncateOption +): void { const containerWidth = options.containerWidth; const font = options.font; const contentWidth = options.contentWidth; if (!containerWidth) { - return ''; + out.textLine = ''; + out.isTruncated = false; + return; } let lineWidth = getWidth(textLine, font); if (lineWidth <= containerWidth) { - return textLine; + out.textLine = textLine; + out.isTruncated = false; + return; } for (let j = 0; ; j++) { @@ -139,7 +169,8 @@ function truncateSingleLine(textLine: string, options: InnerPreparedTruncateOpti textLine = options.placeholder; } - return textLine; + out.textLine = textLine; + out.isTruncated = true; } function estimateLength( @@ -174,6 +205,10 @@ export interface PlainTextContentBlock { outerHeight: number lines: string[] + + // Be `true` if and only if the result text is modified due to overflow, due to + // settings on either `overflow` or `lineOverflow` + isTruncated: boolean } export function parsePlainText( @@ -192,6 +227,7 @@ export function parsePlainText( const bgColorDrawn = !!(style.backgroundColor); const truncateLineOverflow = style.lineOverflow === 'truncate'; + let isTruncated = false; let width = style.width; let lines: string[]; @@ -210,6 +246,7 @@ export function parsePlainText( if (contentHeight > height && truncateLineOverflow) { const lineCount = Math.floor(height / lineHeight); + isTruncated = isTruncated || (lines.length > lineCount); lines = lines.slice(0, lineCount); // TODO If show ellipse for line truncate @@ -228,8 +265,11 @@ export function parsePlainText( placeholder: style.placeholder }); // Having every line has '...' when truncate multiple lines. + const singleOut = {} as Parameters[0]; for (let i = 0; i < lines.length; i++) { - lines[i] = truncateSingleLine(lines[i], options); + truncateSingleLine(singleOut, lines[i], options); + lines[i] = singleOut.textLine; + isTruncated = isTruncated || singleOut.isTruncated; } } @@ -265,7 +305,8 @@ export function parsePlainText( calculatedLineHeight: calculatedLineHeight, contentWidth: contentWidth, contentHeight: contentHeight, - width: width + width: width, + isTruncated: isTruncated }; } @@ -314,6 +355,9 @@ export class RichTextContentBlock { outerWidth: number = 0 outerHeight: number = 0 lines: RichTextLine[] = [] + // Be `true` if and only if the result text is modified due to overflow, due to + // settings on either `overflow` or `lineOverflow` + isTruncated: boolean = false } type WrapInfo = { @@ -326,7 +370,7 @@ type WrapInfo = { * Also consider 'bbbb{a|xxx\nzzz}xxxx\naaaa'. * If styleName is undefined, it is plain text. */ -export function parseRichText(text: string, style: TextStyleProps) { +export function parseRichText(text: string, style: TextStyleProps): RichTextContentBlock { const contentBlock = new RichTextContentBlock(); text != null && (text += ''); @@ -366,6 +410,7 @@ export function parseRichText(text: string, style: TextStyleProps) { const truncate = overflow === 'truncate'; const truncateLine = style.lineOverflow === 'truncate'; + const tmpTruncateOut = {} as Parameters[0]; // let prevToken: RichTextToken; @@ -412,6 +457,7 @@ export function parseRichText(text: string, style: TextStyleProps) { if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) { // TODO Add ellipsis on the previous token. // prevToken.text = + const originalLength = contentBlock.lines.length; if (j > 0) { line.tokens = line.tokens.slice(0, j); finishLine(line, lineWidth, lineHeight); @@ -420,6 +466,7 @@ export function parseRichText(text: string, style: TextStyleProps) { else { contentBlock.lines = contentBlock.lines.slice(0, i); } + contentBlock.isTruncated = contentBlock.isTruncated || (contentBlock.lines.length < originalLength); break outer; } @@ -461,10 +508,13 @@ export function parseRichText(text: string, style: TextStyleProps) { token.width = token.contentWidth = 0; } else { - token.text = truncateText( + truncateText2( + tmpTruncateOut, token.text, remainTruncWidth - paddingH, font, style.ellipsis, {minChar: style.truncateMinChar} ); + token.text = tmpTruncateOut.text; + contentBlock.isTruncated = contentBlock.isTruncated || tmpTruncateOut.isTruncated; token.width = token.contentWidth = getWidth(token.text, font); } } diff --git a/test/text-overflow.html b/test/text-overflow.html index ac9191f52..5e8b9f08d 100644 --- a/test/text-overflow.html +++ b/test/text-overflow.html @@ -17,86 +17,102 @@ height: 100%; margin: 0; } + #message { + position: relative; + padding: 20px 0; + } +