Skip to content

Commit

Permalink
Merge pull request #1694 from VisActor/feat/richtext-ascentDescentMode
Browse files Browse the repository at this point in the history
feat: richtext support ascentDescentMode
  • Loading branch information
neuqzxy authored Jan 27, 2025
2 parents fd189da + f6ea83f commit c26530f
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 19 deletions.
1 change: 1 addition & 0 deletions packages/vrender-core/src/graphic/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ export const DefaultRichTextAttribute: Required<IRichTextGraphicAttribute> = {
...DefaultTextStyle,
editable: false,
editOptions: null,
ascentDescentMode: 'actual',
width: 300,
height: 300,
ellipsis: true,
Expand Down
7 changes: 4 additions & 3 deletions packages/vrender-core/src/graphic/richtext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,8 @@ export class RichText extends Graphic<IRichTextGraphicAttribute> implements IRic
layoutDirection,
singleLine,
disableAutoWrapLine,
editable
editable,
ascentDescentMode
} = this.attribute;

let { textConfig: _tc = [] } = this.attribute;
Expand Down Expand Up @@ -427,10 +428,10 @@ export class RichText extends Graphic<IRichTextGraphicAttribute> implements IRic
// 如果有文字内有换行符,将该段文字切为多段,并在后一段加入newLine标记
const textParts = richTextConfig.text.split('\n');
for (let j = 0; j < textParts.length; j++) {
paragraphs.push(new Paragraph(textParts[j], j !== 0, richTextConfig));
paragraphs.push(new Paragraph(textParts[j], j !== 0, richTextConfig, ascentDescentMode));
}
} else if (richTextConfig.text) {
paragraphs.push(new Paragraph(richTextConfig.text, false, richTextConfig));
paragraphs.push(new Paragraph(richTextConfig.text, false, richTextConfig, ascentDescentMode));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/vrender-core/src/graphic/richtext/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export default class Line {
const ellipsis = drawEllipsis === true ? '...' : drawEllipsis || '';
paragraph.ellipsisStr = ellipsis;
// const { width } = measureText('...', paragraph.style);
const { width } = measureTextCanvas(ellipsis, paragraph.character);
const { width } = measureTextCanvas(ellipsis, paragraph.character, paragraph.ascentDescentMode);
const ellipsisWidth = width || 0;
if (ellipsisWidth <= this.blankWidth + otherParagraphWidth) {
// 省略号可以直接接在后面paragraph
Expand Down Expand Up @@ -243,7 +243,7 @@ export default class Line {
break; // todo: 处理最后为图标,显示省略号的情况
}

const { width } = measureTextCanvas(ellipsis, paragraph.character);
const { width } = measureTextCanvas(ellipsis, paragraph.character, paragraph.ascentDescentMode);
const ellipsisWidth = width || 0;
if (ellipsisWidth <= this.blankWidth + otherParagraphWidth) {
// 省略号可以直接接在后面paragraph
Expand Down
23 changes: 15 additions & 8 deletions packages/vrender-core/src/graphic/richtext/paragraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export default class Paragraph {
widthOrigin?: number;
heightOrigin?: number;
textBaseline?: CanvasTextBaseline;
ascentDescentMode?: 'actual' | 'font';

ellipsis: 'normal' | 'add' | 'replace' | 'hide';
ellipsisStr: string;
Expand All @@ -74,10 +75,16 @@ export default class Paragraph {
verticalEllipsis?: boolean;
overflow?: boolean;

constructor(text: string, newLine: boolean, character: IRichTextParagraphCharacter) {
constructor(
text: string,
newLine: boolean,
character: IRichTextParagraphCharacter,
ascentDescentMode?: 'actual' | 'font'
) {
// 测量文字
this.fontSize = character.fontSize || 16;
this.textBaseline = character.textBaseline || 'alphabetic';
this.ascentDescentMode = ascentDescentMode;

// 处理行高:
// lineHeight为数字时,大于fontSize取lineHeight,小于fontSize时取fontSize
Expand All @@ -91,7 +98,7 @@ export default class Paragraph {

this.height = this.lineHeight;

const { ascent, height, descent, width } = measureTextCanvas(text, character);
const { ascent, height, descent, width } = measureTextCanvas(text, character, this.ascentDescentMode);

let halfDetaHeight = 0;
let deltaAscent = 0;
Expand Down Expand Up @@ -150,7 +157,7 @@ export default class Paragraph {
}

updateWidth() {
const { width } = measureTextCanvas(this.text, this.character);
const { width } = measureTextCanvas(this.text, this.character, this.ascentDescentMode);
this.width = width;
if (this.direction === 'vertical') {
this.widthOrigin = this.width;
Expand Down Expand Up @@ -202,7 +209,7 @@ export default class Paragraph {
text += this.ellipsisStr;

if (textAlign === 'right' || textAlign === 'end') {
const { width } = measureTextCanvas(this.text.slice(index), this.character);
const { width } = measureTextCanvas(this.text.slice(index), this.character, this.ascentDescentMode);
if (direction === 'vertical') {
// baseline -= this.ellipsisWidth - width;
} else {
Expand Down Expand Up @@ -286,7 +293,7 @@ export default class Paragraph {
text += this.ellipsisStr;

if (textAlign === 'right' || textAlign === 'end') {
const { width } = measureTextCanvas(this.text.slice(index), this.character);
const { width } = measureTextCanvas(this.text.slice(index), this.character, this.ascentDescentMode);
if (direction === 'vertical') {
// baseline -= this.ellipsisWidth - width;
} else {
Expand Down Expand Up @@ -407,7 +414,7 @@ export default class Paragraph {
text = text.slice(0, index);
text += this.ellipsisStr;

const { width: measureWidth } = measureTextCanvas(this.text.slice(index), this.character);
const { width: measureWidth } = measureTextCanvas(this.text.slice(index), this.character, this.ascentDescentMode);
return width + this.ellipsisWidth - measureWidth;
}
return width;
Expand All @@ -417,8 +424,8 @@ export default class Paragraph {
export function seperateParagraph(paragraph: Paragraph, index: number) {
const text1 = paragraph.text.slice(0, index);
const text2 = paragraph.text.slice(index);
const p1 = new Paragraph(text1, paragraph.newLine, paragraph.character);
const p2 = new Paragraph(text2, true, paragraph.character);
const p1 = new Paragraph(text1, paragraph.newLine, paragraph.character, paragraph.ascentDescentMode);
const p2 = new Paragraph(text2, true, paragraph.character, paragraph.ascentDescentMode);

return [p1, p2];
}
11 changes: 7 additions & 4 deletions packages/vrender-core/src/graphic/richtext/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,8 @@ export function measureTextDom(
// 测量文字详细信息
export function measureTextCanvas(
text: string,
character: IRichTextParagraphCharacter
character: IRichTextParagraphCharacter,
mode: 'actual' | 'font' = 'actual'
): { ascent: number; height: number; descent: number; width: number } {
const textMeasure = application.graphicUtil.textMeasure;
const measurement = textMeasure.measureText(text, character as any) as TextMetrics;
Expand All @@ -351,15 +352,17 @@ export function measureTextCanvas(
descent: 0,
width: 0
};
if (typeof measurement.fontBoundingBoxAscent !== 'number' || typeof measurement.fontBoundingBoxDescent !== 'number') {
const ascent = mode === 'actual' ? measurement.actualBoundingBoxAscent : measurement.fontBoundingBoxAscent;
const descent = mode === 'actual' ? measurement.actualBoundingBoxDescent : measurement.fontBoundingBoxDescent;
if (typeof ascent !== 'number' || typeof descent !== 'number') {
result.width = measurement.width;
result.height = character.fontSize || 0;
result.ascent = result.height;
result.descent = 0;
} else {
result.width = measurement.width;
result.height = Math.floor(measurement.fontBoundingBoxAscent + measurement.fontBoundingBoxDescent);
result.ascent = Math.floor(measurement.fontBoundingBoxAscent);
result.height = Math.floor(ascent + descent);
result.ascent = Math.floor(ascent);
result.descent = result.height - result.ascent;
}
return result;
Expand Down
4 changes: 4 additions & 0 deletions packages/vrender-core/src/interface/graphic/richText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export type IRichTextAttribute = {
* 是否可编辑
*/
editable: boolean;
/**
* 测量ascent和descent的模式,预览的时候actual比较合适,而如果需要编辑的话,font比较合适
*/
ascentDescentMode?: 'actual' | 'font';
/**
* 富文本的编辑配置
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,11 @@ export class EditModule {
this.composingConfigIdx = this.cursorIndex < 0 ? 0 : findConfigIndexByCursorIdx(textConfig, this.cursorIndex);
if (this.cursorIndex < 0) {
const config = textConfig[0];
textConfig.unshift({ ...getDefaultCharacterConfig(this.currRt.attribute), ...config, text: '' });
textConfig.unshift({ fill: 'black', ...getDefaultCharacterConfig(this.currRt.attribute), ...config, text: '' });
} else {
const configIdx = this.composingConfigIdx;
const lastConfig = textConfig[configIdx] || textConfig[configIdx - 1];
textConfig.splice(configIdx, 0, { ...lastConfig, text: '' });
textConfig.splice(configIdx, 0, { fill: 'black', ...lastConfig, text: '' });
}
};
handleCompositionEnd = () => {
Expand Down

0 comments on commit c26530f

Please sign in to comment.