Skip to content

Commit

Permalink
feat: support output the state isTruncated in Text element, which…
Browse files Browse the repository at this point in the history
… can be used in the upper program like echarts tooltip, as required by apache/echarts#16315 .
  • Loading branch information
100pah committed Nov 18, 2024
1 parent e4766d8 commit 92dbb39
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 74 deletions.
10 changes: 10 additions & 0 deletions src/graphic/Text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ class ZRText extends Displayable<TextProps> 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
Expand Down Expand Up @@ -497,6 +503,8 @@ class ZRText extends Displayable<TextProps> 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';
Expand Down Expand Up @@ -635,6 +643,8 @@ class ZRText extends Displayable<TextProps> 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;
Expand Down
72 changes: 61 additions & 11 deletions src/graphic/helper/parseText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,42 @@ export function truncateText(
ellipsis?: string,
options?: InnerTruncateOption
): string {
const out = {} as Parameters<typeof truncateText2>[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');
options = prepareTruncateOptions(containerWidth, font, ellipsis, options);

// FIXME
// It is not appropriate that every line has '...' when truncate multiple lines.
let isTruncated = false;
const truncateOut = {} as Parameters<typeof truncateSingleLine>[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(
Expand Down Expand Up @@ -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++) {
Expand All @@ -139,7 +169,8 @@ function truncateSingleLine(textLine: string, options: InnerPreparedTruncateOpti
textLine = options.placeholder;
}

return textLine;
out.textLine = textLine;
out.isTruncated = true;
}

function estimateLength(
Expand Down Expand Up @@ -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(
Expand All @@ -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[];
Expand All @@ -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
Expand All @@ -228,8 +265,11 @@ export function parsePlainText(
placeholder: style.placeholder
});
// Having every line has '...' when truncate multiple lines.
const singleOut = {} as Parameters<typeof truncateSingleLine>[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;
}
}

Expand Down Expand Up @@ -265,7 +305,8 @@ export function parsePlainText(
calculatedLineHeight: calculatedLineHeight,
contentWidth: contentWidth,
contentHeight: contentHeight,
width: width
width: width,
isTruncated: isTruncated
};
}

Expand Down Expand Up @@ -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 = {
Expand All @@ -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 += '');
Expand Down Expand Up @@ -366,6 +410,7 @@ export function parseRichText(text: string, style: TextStyleProps) {

const truncate = overflow === 'truncate';
const truncateLine = style.lineOverflow === 'truncate';
const tmpTruncateOut = {} as Parameters<typeof truncateText2>[0];

// let prevToken: RichTextToken;

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
}
}
Expand Down
Loading

0 comments on commit 92dbb39

Please sign in to comment.