diff --git a/blocksuite/playground/examples/renderer/animator.ts b/blocksuite/playground/examples/renderer/animator.ts index fe77a3329..ce650bc50 100644 --- a/blocksuite/playground/examples/renderer/animator.ts +++ b/blocksuite/playground/examples/renderer/animator.ts @@ -2,7 +2,7 @@ import { type AffineEditorContainer } from '@blocksuite/presets'; import { CanvasRenderer } from './canvas-renderer.js'; import { editor } from './editor.js'; -import type { ParagraphLayout } from './types.js'; +import type { SectionLayout } from './types.js'; async function wait(time: number = 100) { return new Promise(resolve => setTimeout(resolve, time)); @@ -34,8 +34,8 @@ export class SwitchModeAnimator { this.overlay.style.display = 'inherit'; await this.animate( - beginLayout.paragraphs, - endLayout.paragraphs, + beginLayout.section, + endLayout.section, beginLayout.hostRect, endLayout.hostRect ); @@ -43,8 +43,8 @@ export class SwitchModeAnimator { } async animate( - beginParagraphs: ParagraphLayout[], - endParagraphs: ParagraphLayout[], + beginSection: SectionLayout, + endSection: SectionLayout, beginHostRect: DOMRect, endHostRect: DOMRect ): Promise { @@ -58,8 +58,8 @@ export class SwitchModeAnimator { const progress = Math.min(elapsed / duration, 1); this.renderer.renderTransitionFrame( - beginParagraphs, - endParagraphs, + beginSection, + endSection, beginHostRect, endHostRect, progress diff --git a/blocksuite/playground/examples/renderer/canvas-renderer.ts b/blocksuite/playground/examples/renderer/canvas-renderer.ts index fad504e14..6835376cc 100644 --- a/blocksuite/playground/examples/renderer/canvas-renderer.ts +++ b/blocksuite/playground/examples/renderer/canvas-renderer.ts @@ -2,7 +2,7 @@ import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import type { AffineEditorContainer } from '@blocksuite/presets'; import { getSentenceRects, segmentSentences } from './text-utils.js'; -import { type ParagraphLayout } from './types.js'; +import { type ParagraphLayout, type SectionLayout } from './types.js'; export class CanvasRenderer { private readonly worker: Worker; @@ -35,17 +35,34 @@ export class CanvasRenderer { return this.editorContainer.std.get(GfxControllerIdentifier).viewport.zoom; } - get hostLayout() { + get hostLayout(): { + section: SectionLayout; + hostRect: DOMRect; + editorContainerRect: DOMRect; + } { const paragraphBlocks = this.editorContainer.host!.querySelectorAll( '.affine-paragraph-rich-text-wrapper [data-v-text="true"]' ); const zoom = this.hostZoom; + const hostRect = this.hostRect; + const editorContainerRect = this.editorContainer.getBoundingClientRect(); + + let sectionMinX = Infinity; + let sectionMinY = Infinity; + let sectionMaxX = -Infinity; + let sectionMaxY = -Infinity; const paragraphs: ParagraphLayout[] = Array.from(paragraphBlocks).map(p => { const sentences = segmentSentences(p.textContent || ''); const sentenceLayouts = sentences.map(sentence => { const rects = getSentenceRects(p, sentence); + rects.forEach(({ rect }) => { + sectionMinX = Math.min(sectionMinX, rect.x); + sectionMinY = Math.min(sectionMinY, rect.y); + sectionMaxX = Math.max(sectionMaxX, rect.x + rect.width); + sectionMaxY = Math.max(sectionMaxY, rect.y + rect.height); + }); return { text: sentence, rects, @@ -58,14 +75,22 @@ export class CanvasRenderer { }; }); - const hostRect = this.hostRect; - const editorContainerRect = this.editorContainer.getBoundingClientRect(); - return { paragraphs, hostRect, editorContainerRect }; + const section: SectionLayout = { + paragraphs, + rect: { + x: sectionMinX, + y: sectionMinY, + width: sectionMaxX - sectionMinX, + height: sectionMaxY - sectionMinY, + }, + }; + + return { section, hostRect, editorContainerRect }; } public async render(toScreen = true): Promise { - const { paragraphs, hostRect, editorContainerRect } = this.hostLayout; - this.initWorkerSize(hostRect.width, hostRect.height); + const { section, editorContainerRect } = this.hostLayout; + this.initWorkerSize(section.rect.width, section.rect.height); return new Promise(resolve => { if (!this.worker) return; @@ -73,8 +98,7 @@ export class CanvasRenderer { this.worker.postMessage({ type: 'draw', data: { - paragraphs, - hostRect, + section, }, }); @@ -94,8 +118,8 @@ export class CanvasRenderer { const ctx = this.canvas.getContext('2d'); const bitmapCanvas = new OffscreenCanvas( - hostRect.width * window.devicePixelRatio, - hostRect.height * window.devicePixelRatio + section.rect.width * window.devicePixelRatio, + section.rect.height * window.devicePixelRatio ); const bitmapCtx = bitmapCanvas.getContext('bitmaprenderer'); bitmapCtx?.transferFromImageBitmap(bitmap); @@ -107,10 +131,10 @@ export class CanvasRenderer { ctx?.drawImage( bitmapCanvas, - (hostRect.x - editorContainerRect.x) * window.devicePixelRatio, - (hostRect.y - editorContainerRect.y) * window.devicePixelRatio, - hostRect.width * window.devicePixelRatio, - hostRect.height * window.devicePixelRatio + (section.rect.x - editorContainerRect.x) * window.devicePixelRatio, + (section.rect.y - editorContainerRect.y) * window.devicePixelRatio, + section.rect.width * window.devicePixelRatio, + section.rect.height * window.devicePixelRatio ); resolve(); @@ -120,8 +144,8 @@ export class CanvasRenderer { } public renderTransitionFrame( - beginParagraphs: ParagraphLayout[], - endParagraphs: ParagraphLayout[], + beginSection: SectionLayout, + endSection: SectionLayout, beginHostRect: DOMRect, endHostRect: DOMRect, progress: number @@ -185,18 +209,23 @@ export class CanvasRenderer { // Draw paragraph rects const maxParagraphs = Math.max( - beginParagraphs.length, - endParagraphs.length + beginSection.paragraphs.length, + endSection.paragraphs.length ); + for (let i = 0; i < maxParagraphs; i++) { const beginRect = - i < beginParagraphs.length - ? getParagraphRect(beginParagraphs[i]) - : getParagraphRect(endParagraphs[endParagraphs.length - 1]); + i < beginSection.paragraphs.length + ? getParagraphRect(beginSection.paragraphs[i]) + : getParagraphRect( + endSection.paragraphs[endSection.paragraphs.length - 1] + ); const endRect = - i < endParagraphs.length - ? getParagraphRect(endParagraphs[i]) - : getParagraphRect(beginParagraphs[beginParagraphs.length - 1]); + i < endSection.paragraphs.length + ? getParagraphRect(endSection.paragraphs[i]) + : getParagraphRect( + beginSection.paragraphs[beginSection.paragraphs.length - 1] + ); const currentRect = interpolateRect(beginRect, endRect, progress); ctx.fillStyle = '#efefef'; diff --git a/blocksuite/playground/examples/renderer/canvas.worker.ts b/blocksuite/playground/examples/renderer/canvas.worker.ts index e89f8f978..b49769da8 100644 --- a/blocksuite/playground/examples/renderer/canvas.worker.ts +++ b/blocksuite/playground/examples/renderer/canvas.worker.ts @@ -1,4 +1,4 @@ -import { type ParagraphLayout } from './types.js'; +import { type SectionLayout } from './types.js'; const meta = { emSize: 2048, @@ -38,14 +38,14 @@ class CanvasWorkerManager { this.ctx.fillRect(0, 0, width, height); } - draw(paragraphs: ParagraphLayout[], hostRect: DOMRect) { + draw(section: SectionLayout) { const { canvas, ctx } = this; if (!canvas || !ctx) return; // Track rendered positions to avoid duplicate rendering across all paragraphs and sentences const renderedPositions = new Set(); - paragraphs.forEach(paragraph => { + section.paragraphs.forEach(paragraph => { const scale = paragraph.scale ?? 1; const fontSize = 15 * scale; ctx.font = `${fontSize}px Inter`; @@ -54,8 +54,8 @@ class CanvasWorkerManager { paragraph.sentences.forEach(sentence => { ctx.strokeStyle = 'yellow'; sentence.rects.forEach(textRect => { - const x = textRect.rect.left - hostRect.left; - const y = textRect.rect.top - hostRect.top; + const x = textRect.rect.left - section.rect.x; + const y = textRect.rect.top - section.rect.y; const posKey = `${x},${y}`; // Only render if we haven't rendered at this position before @@ -87,8 +87,8 @@ self.onmessage = async (e: MessageEvent) => { } case 'draw': { await font.load(); - const { paragraphs, hostRect } = data; - manager.draw(paragraphs, hostRect); + const { section } = data; + manager.draw(section); break; } } diff --git a/blocksuite/playground/examples/renderer/types.ts b/blocksuite/playground/examples/renderer/types.ts index 85b4505cc..ddde45b68 100644 --- a/blocksuite/playground/examples/renderer/types.ts +++ b/blocksuite/playground/examples/renderer/types.ts @@ -12,3 +12,13 @@ export interface TextRect { rect: DOMRect; text: string; } + +export interface SectionLayout { + paragraphs: ParagraphLayout[]; + rect: { + x: number; + y: number; + width: number; + height: number; + }; +}