From e36638a604117169fbdeb25d5648d55763cb6fc2 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Tue, 21 Jan 2025 17:16:14 +0800 Subject: [PATCH 1/6] feat: group support emptyBounds --- packages/vrender-core/src/graphic/group.ts | 4 ++ .../builtin-plugin/richtext-edit-plugin.ts | 46 ++++++++++++++----- .../contributions/render/draw-contribution.ts | 6 ++- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/packages/vrender-core/src/graphic/group.ts b/packages/vrender-core/src/graphic/group.ts index 021300b93..742d607ea 100644 --- a/packages/vrender-core/src/graphic/group.ts +++ b/packages/vrender-core/src/graphic/group.ts @@ -147,6 +147,10 @@ export class Group extends Graphic implements IGroup { const bounds = this.doUpdateAABBBounds(); this.addUpdateLayoutTag(); application.graphicService.afterUpdateAABBBounds(this, this.stage, this._AABBBounds, this, selfChange); + // 直接返回空Bounds,但是前面的流程还是要走 + if (this.attribute.boundsMode === 'empty') { + bounds.clear(); + } return bounds; } diff --git a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts index af40248a1..9c290b473 100644 --- a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts +++ b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts @@ -32,7 +32,15 @@ import { application } from '../../application'; import { getWordStartEndIdx } from '../../graphic/richtext/utils'; // import { testLetter, testLetter2 } from '../../graphic/richtext/utils'; -type UpdateType = 'input' | 'change' | 'onfocus' | 'defocus' | 'selection' | 'dispatch'; +type UpdateType = + | 'input' + | 'change' + | 'onfocus' + | 'beforeOnfocus' + | 'defocus' + | 'beforeDefocus' + | 'selection' + | 'dispatch'; class Selection { selectionStartCursorIdx: number; @@ -150,7 +158,7 @@ export class RichTextEditPlugin implements IPlugin { editModule: EditModule; protected commandCbs: Map void>>; - protected updateCbs: Array<(type: UpdateType, p: RichTextEditPlugin) => void>; + protected updateCbs: Array<(type: UpdateType, p: RichTextEditPlugin, params?: any) => void>; // 富文本外部有align或者baseline的时候,需要对光标做偏移 protected declare deltaX: number; @@ -543,16 +551,25 @@ export class RichTextEditPlugin implements IPlugin { placeholderFontFamily, placeholderFontSize } = editOptions; - const shadow = this.currRt.shadowRoot || this.currRt.attachShadow(); + const shadow = this.getShadow(this.currRt); + const textConfigItem = { ...getDefaultCharacterConfig(this.currRt.attribute), text: placeholder }; + if (placeholderColor) { + textConfigItem.fill = placeholderColor; + } + if (placeholderFontFamily) { + textConfigItem.fontFamily = placeholderFontFamily; + } + if (placeholderFontSize) { + textConfigItem.fontSize = placeholderFontSize; + } + this.shadowPlaceHolder = createRichText({ ...this.currRt.attribute, x: 0, y: 0, angle: 0, _debug_bounds: false, - textConfig: [ - { text: placeholder, fill: placeholderColor, fontFamily: placeholderFontFamily, fontSize: placeholderFontSize } - ] + textConfig: [textConfigItem] }); shadow.add(this.shadowPlaceHolder); } @@ -583,10 +600,9 @@ export class RichTextEditPlugin implements IPlugin { fill: false, stroke: boundsStrokeWhenInput, lineWidth: 1, - boundsMode: 'empty', zIndex: -1 }); - const shadow = this.currRt.shadowRoot || this.currRt.attachShadow(); + const shadow = this.getShadow(this.currRt); shadow.add(this.shadowBounds); this.offsetLineBgAndShadowBounds(); @@ -685,6 +701,7 @@ export class RichTextEditPlugin implements IPlugin { }; onFocus(e: PointerEvent, data?: any) { + this.updateCbs && this.updateCbs.forEach(cb => cb('beforeOnfocus', this)); this.deFocus(false); this.focusing = true; const target = e.target as IRichText; @@ -696,7 +713,7 @@ export class RichTextEditPlugin implements IPlugin { // 创建shadowGraphic RichTextEditPlugin.tryUpdateRichtext(target); - const shadowRoot = target.shadowRoot || target.attachShadow(); + const shadowRoot = this.getShadow(target); const cache = target.getFrameCache(); if (!cache) { return; @@ -707,13 +724,13 @@ export class RichTextEditPlugin implements IPlugin { // 添加cursor节点,shadowRoot在上面 shadowRoot.setAttributes({ shadowRootIdx: 1, pickable: false, x: this.deltaX, y: this.deltaY }); if (!this.editLine) { - const line = createLine({ x: 0, y: 0, lineWidth: 1, stroke: 'black', boundsMode: 'empty' }); + const line = createLine({ x: 0, y: 0, lineWidth: 1, stroke: 'black' }); // 不使用stage的Ticker,避免影响其他的动画以及受到其他动画影响 this.addAnimateToLine(line); this.editLine = line; this.ticker.start(true); - const g = createGroup({ x: 0, y: 0, width: 0, height: 0, boundsMode: 'empty' }); + const g = createGroup({ x: 0, y: 0, width: 0, height: 0 }); this.editBg = g; shadowRoot.add(this.editLine); shadowRoot.add(this.editBg); @@ -771,6 +788,7 @@ export class RichTextEditPlugin implements IPlugin { } protected deFocus(trulyDeFocus = false) { + this.updateCbs && this.updateCbs.forEach(cb => cb('beforeDefocus', this, { trulyDeFocus })); const target = this.currRt as IRichText; if (!target) { return; @@ -972,6 +990,12 @@ export class RichTextEditPlugin implements IPlugin { } } + protected getShadow(rt: IRichText) { + const sr = rt.shadowRoot || rt.attachShadow(); + sr.setAttributes({ boundsMode: 'empty' }); + return sr; + } + protected getLineByPoint(cache: IRichTextFrame, p1: IPointLike): IRichTextLine { let lineInfo = cache.lines[0]; for (let i = 0; i < cache.lines.length; i++) { diff --git a/packages/vrender-core/src/render/contributions/render/draw-contribution.ts b/packages/vrender-core/src/render/contributions/render/draw-contribution.ts index 3e7d0f056..be6acc9ee 100644 --- a/packages/vrender-core/src/render/contributions/render/draw-contribution.ts +++ b/packages/vrender-core/src/render/contributions/render/draw-contribution.ts @@ -205,7 +205,11 @@ export class DefaultDrawContribution implements IDrawContribution { return; } - if (this.useDirtyBounds && !isRectIntersect(group.AABBBounds, this.dirtyBounds, false)) { + if ( + this.useDirtyBounds && + !isRectIntersect(group.AABBBounds, this.dirtyBounds, false) && + group.attribute.boundsMode !== 'empty' + ) { return; } From 611bc6deda714a0e1783231f1b627e594dad9aa5 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Tue, 21 Jan 2025 17:31:26 +0800 Subject: [PATCH 2/6] fix: fix issue with richtext bg overlap --- .../src/graphic/richtext/paragraph.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/vrender-core/src/graphic/richtext/paragraph.ts b/packages/vrender-core/src/graphic/richtext/paragraph.ts index d8d690619..92e0a1fec 100644 --- a/packages/vrender-core/src/graphic/richtext/paragraph.ts +++ b/packages/vrender-core/src/graphic/richtext/paragraph.ts @@ -7,15 +7,16 @@ function getFixedLRTB(left: number, right: number, top: number, bottom: number) const topInt = Math.round(top); const rightInt = Math.round(right); const bottomInt = Math.round(bottom); - const _left = left > leftInt ? leftInt : leftInt - 0.5; - const _top = top > topInt ? topInt : topInt - 0.5; - const _right = rightInt > right ? rightInt : rightInt + 0.5; - const _bottom = bottomInt > bottom ? bottomInt : bottomInt + 0.5; + // 会导致背景色重叠 + // const _left = left > leftInt ? leftInt : leftInt - 0.5; + // const _top = top > topInt ? topInt : topInt - 0.5; + // const _right = rightInt > right ? rightInt : rightInt + 0.5; + // const _bottom = bottomInt > bottom ? bottomInt : bottomInt + 0.5; return { - left: _left, - top: _top, - right: _right, - bottom: _bottom + left: leftInt, + top: topInt, + right: rightInt, + bottom: bottomInt }; } From d6957e017fcfb32e89504a77fe826d1fa00923c2 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Tue, 21 Jan 2025 20:54:42 +0800 Subject: [PATCH 3/6] feat: support syncPlaceHolderToTextConfig --- .../src/interface/graphic/richText.ts | 1 + .../builtin-plugin/richtext-edit-plugin.ts | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/vrender-core/src/interface/graphic/richText.ts b/packages/vrender-core/src/interface/graphic/richText.ts index 399d36997..b23813cc5 100644 --- a/packages/vrender-core/src/interface/graphic/richText.ts +++ b/packages/vrender-core/src/interface/graphic/richText.ts @@ -6,6 +6,7 @@ import type { ITextGraphicAttribute } from './text'; export type IRichTextEditOptionsType = { placeholder?: string; + syncPlaceHolderToTextConfig?: boolean; placeholderColor?: string; placeholderFontSize?: number; placeholderFontFamily?: string; diff --git a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts index 9c290b473..7b54c9214 100644 --- a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts +++ b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts @@ -373,6 +373,12 @@ export class RichTextEditPlugin implements IPlugin { return; } const { lines } = cache; + if (lines.length === 0) { + return; + } + if (!lines[0].paragraphs || lines[0].paragraphs.length === 0) { + return; + } const totalCursorCount = lines.reduce((total, line) => total + line.paragraphs.length, 0) - 1; this.selectionRange(-0.1, totalCursorCount + 0.1); @@ -567,6 +573,9 @@ export class RichTextEditPlugin implements IPlugin { ...this.currRt.attribute, x: 0, y: 0, + pickable: false, + editable: false, + editOptions: null, angle: 0, _debug_bounds: false, textConfig: [textConfigItem] @@ -616,7 +625,7 @@ export class RichTextEditPlugin implements IPlugin { if (textConfig && textConfig.length) { return; } - if (!(editOptions && editOptions.placeholder)) { + if (!(editOptions && editOptions.placeholder && editOptions.syncPlaceHolderToTextConfig)) { return; } const { placeholder } = editOptions; @@ -788,11 +797,11 @@ export class RichTextEditPlugin implements IPlugin { } protected deFocus(trulyDeFocus = false) { - this.updateCbs && this.updateCbs.forEach(cb => cb('beforeDefocus', this, { trulyDeFocus })); const target = this.currRt as IRichText; if (!target) { return; } + this.updateCbs && this.updateCbs.forEach(cb => cb('beforeDefocus', this, { trulyDeFocus })); if (trulyDeFocus) { this.trySyncPlaceholderToTextConfig(); target.detachShadow(); @@ -908,6 +917,9 @@ export class RichTextEditPlugin implements IPlugin { }; let line0Info = this.getLineByPoint(cache, startCursorPos); let line1Info = this.getLineByPoint(cache, endCursorPos); + if (!line0Info || !line1Info) { + return; + } if ( startCursorPos.y > endCursorPos.y || From e1bf93bb9e6189ef0ac3d955726176ecb3d55da5 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Tue, 21 Jan 2025 20:58:18 +0800 Subject: [PATCH 4/6] fix: fix issue with shadow bounds size when empty --- .../src/plugins/builtin-plugin/richtext-edit-plugin.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts index 7b54c9214..076773004 100644 --- a/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts +++ b/packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts @@ -594,11 +594,12 @@ export class RichTextEditPlugin implements IPlugin { return; } const { attribute } = this.currRt; - const b = this.currRt.AABBBounds; + let b = this.currRt.AABBBounds; let h = b.height(); if (!attribute.textConfig.length && this.editLine) { const { points } = this.editLine.attribute; h = points[1].y - points[0].y; + b = getRichTextBounds({ ...this.shadowPlaceHolder.attribute }); } this.shadowBounds = this.shadowBounds || createRect({}); this.shadowBounds.setAttributes({ From 43bb37bfee61eec9ecae967077e7a065daca1906 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Tue, 21 Jan 2025 21:25:08 +0800 Subject: [PATCH 5/6] fix: fix issue with input style --- packages/vrender-core/src/plugins/builtin-plugin/edit-module.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vrender-core/src/plugins/builtin-plugin/edit-module.ts b/packages/vrender-core/src/plugins/builtin-plugin/edit-module.ts index 769a912d2..db872d655 100644 --- a/packages/vrender-core/src/plugins/builtin-plugin/edit-module.ts +++ b/packages/vrender-core/src/plugins/builtin-plugin/edit-module.ts @@ -267,6 +267,7 @@ export class EditModule { const textList: string[] = text ? Array.from(text.toString()) : []; for (let i = 0; i < textList.length; i++) { textConfig.splice(i + configIdx, 0, { + ...getDefaultCharacterConfig(this.currRt.attribute), fill: 'black', ...lastConfig, isComposing: false, From 610827eb991f7b356d7ca930ce8469af3479efca Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Tue, 21 Jan 2025 21:36:40 +0800 Subject: [PATCH 6/6] fix: fix issue with split text to array --- packages/vrender-core/src/graphic/richtext.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/vrender-core/src/graphic/richtext.ts b/packages/vrender-core/src/graphic/richtext.ts index bad0b7cc3..271c28b4b 100644 --- a/packages/vrender-core/src/graphic/richtext.ts +++ b/packages/vrender-core/src/graphic/richtext.ts @@ -205,8 +205,19 @@ export class RichText extends Graphic implements IRic ); } + static splitEmoji(text: string) { + // 👈🏻这种emoji用Array.from还处理不了,所以得兼容一下 + return [...new (Intl as any).Segmenter().segment(text)].map(x => x.segment); + } + static splitText(text: string) { // 😁这种emoji长度算两个,所以得处理一下 + try { + const arr = this.splitEmoji(text); + return arr; + } catch (e) { + // do nothing + } return Array.from(text); }