From 6d57c01dd436f080a42599475fd59552a8d232db Mon Sep 17 00:00:00 2001 From: Yifeng Wang Date: Mon, 26 May 2025 01:08:31 +0800 Subject: [PATCH] feat(editor): support brush dom renderer --- .../brush/src/element-renderer/brush-dom.ts | 11 ++++ .../src/element-renderer/brush-dom/index.ts | 63 +++++++++++++++++++ blocksuite/affine/gfx/brush/src/index.ts | 1 + blocksuite/affine/gfx/brush/src/view.ts | 2 + 4 files changed, 77 insertions(+) create mode 100644 blocksuite/affine/gfx/brush/src/element-renderer/brush-dom.ts create mode 100644 blocksuite/affine/gfx/brush/src/element-renderer/brush-dom/index.ts diff --git a/blocksuite/affine/gfx/brush/src/element-renderer/brush-dom.ts b/blocksuite/affine/gfx/brush/src/element-renderer/brush-dom.ts new file mode 100644 index 0000000000..293410373c --- /dev/null +++ b/blocksuite/affine/gfx/brush/src/element-renderer/brush-dom.ts @@ -0,0 +1,11 @@ +import { DomElementRendererExtension } from '@blocksuite/affine-block-surface'; + +import { brushDomRenderer } from './brush-dom/index.js'; + +/** + * Extension to register the DOM-based renderer for 'brush' elements. + */ +export const BrushDomRendererExtension = DomElementRendererExtension( + 'brush', + brushDomRenderer +); diff --git a/blocksuite/affine/gfx/brush/src/element-renderer/brush-dom/index.ts b/blocksuite/affine/gfx/brush/src/element-renderer/brush-dom/index.ts new file mode 100644 index 0000000000..2932ebe80a --- /dev/null +++ b/blocksuite/affine/gfx/brush/src/element-renderer/brush-dom/index.ts @@ -0,0 +1,63 @@ +import type { DomRenderer } from '@blocksuite/affine-block-surface'; +import type { BrushElementModel } from '@blocksuite/affine-model'; +import { DefaultTheme } from '@blocksuite/affine-model'; + +/** + * Renders a BrushElementModel to a given HTMLElement using DOM properties. + * This function is intended to be registered via the DomElementRendererExtension. + * + * @param model - The brush element model containing rendering properties. + * @param element - The HTMLElement to apply the brush's styles to. + * @param renderer - The main DOMRenderer instance, providing access to viewport and color utilities. + */ +export const brushDomRenderer = ( + model: BrushElementModel, + element: HTMLElement, + renderer: DomRenderer +): void => { + const { zoom } = renderer.viewport; + const unscaledWidth = model.w; + const unscaledHeight = model.h; + + const color = renderer.getColorValue(model.color, DefaultTheme.black, true); + + element.style.width = `${unscaledWidth * zoom}px`; + element.style.height = `${unscaledHeight * zoom}px`; + element.style.boxSizing = 'border-box'; + element.style.overflow = 'hidden'; + + // Clear any existing content + element.replaceChildren(); + + // Create SVG element to render the brush stroke + const SVG_NS = 'http://www.w3.org/2000/svg'; + const svg = document.createElementNS(SVG_NS, 'svg'); + svg.setAttribute('width', '100%'); + svg.setAttribute('height', '100%'); + svg.setAttribute('viewBox', `0 0 ${unscaledWidth} ${unscaledHeight}`); + svg.setAttribute('preserveAspectRatio', 'none'); + + // Create path element for the brush stroke + const path = document.createElementNS(SVG_NS, 'path'); + path.setAttribute('d', model.commands); + path.setAttribute('fill', color); + path.setAttribute('stroke', 'none'); + + svg.append(path); + element.append(svg); + + // Apply rotation if needed + if (model.rotate) { + element.style.transform = `rotate(${model.rotate}deg)`; + element.style.transformOrigin = 'center'; + } + + // Apply opacity + element.style.opacity = `${model.opacity ?? 1}`; + + // Set z-index + element.style.zIndex = renderer.layerManager.getZIndex(model).toString(); + + // Add brush-specific class for styling + element.classList.add('brush-element'); +}; diff --git a/blocksuite/affine/gfx/brush/src/index.ts b/blocksuite/affine/gfx/brush/src/index.ts index ba45147853..105b60aa05 100644 --- a/blocksuite/affine/gfx/brush/src/index.ts +++ b/blocksuite/affine/gfx/brush/src/index.ts @@ -1,6 +1,7 @@ export * from './adapter'; export * from './brush-tool'; export * from './element-renderer'; +export * from './element-renderer/brush-dom'; export * from './eraser-tool'; export * from './highlighter-tool'; export * from './toolbar/configs'; diff --git a/blocksuite/affine/gfx/brush/src/view.ts b/blocksuite/affine/gfx/brush/src/view.ts index e0c61c5ee4..b85af6f69a 100644 --- a/blocksuite/affine/gfx/brush/src/view.ts +++ b/blocksuite/affine/gfx/brush/src/view.ts @@ -6,6 +6,7 @@ import { import { BrushTool } from './brush-tool'; import { effects } from './effects'; import { BrushElementRendererExtension } from './element-renderer'; +import { BrushDomRendererExtension } from './element-renderer/brush-dom'; import { EraserTool } from './eraser-tool'; import { HighlighterTool } from './highlighter-tool'; import { @@ -30,6 +31,7 @@ export class BrushViewExtension extends ViewExtensionProvider { context.register(HighlighterTool); context.register(BrushElementRendererExtension); + context.register(BrushDomRendererExtension); context.register(brushToolbarExtension); context.register(highlighterToolbarExtension);