mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 14:27:02 +08:00
refactor(editor): extensionalize surface canvas renderer (#11456)
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import {
|
||||
createIdentifier,
|
||||
type ServiceIdentifier,
|
||||
} from '@blocksuite/global/di';
|
||||
import type {
|
||||
GfxLocalElementModel,
|
||||
GfxPrimitiveElementModel,
|
||||
} from '@blocksuite/std/gfx';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import type { ElementRenderer } from '../renderer/elements';
|
||||
|
||||
export const ElementRendererIdentifier =
|
||||
createIdentifier<unknown>('element-renderer');
|
||||
|
||||
export const ElementRendererExtension = <
|
||||
T extends GfxPrimitiveElementModel | GfxLocalElementModel,
|
||||
>(
|
||||
id: string,
|
||||
renderer: ElementRenderer<T>
|
||||
): ExtensionType & {
|
||||
identifier: ServiceIdentifier<ElementRenderer<T>>;
|
||||
} => {
|
||||
const identifier = ElementRendererIdentifier<ElementRenderer<T>>(id);
|
||||
return {
|
||||
setup: di => {
|
||||
di.addImpl(identifier, () => renderer);
|
||||
},
|
||||
identifier,
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './clipboard-config';
|
||||
export * from './crud-extension';
|
||||
export * from './element-renderer';
|
||||
export * from './export-manager';
|
||||
export * from './legacy-slot-extension';
|
||||
export * from './query';
|
||||
|
||||
@@ -22,10 +22,7 @@ export {
|
||||
export { CanvasRenderer } from './renderer/canvas-renderer.js';
|
||||
export * from './renderer/elements/group/consts.js';
|
||||
export type { ElementRenderer } from './renderer/elements/index.js';
|
||||
export {
|
||||
elementRenderers,
|
||||
normalizeShapeBound,
|
||||
} from './renderer/elements/index.js';
|
||||
export { normalizeShapeBound } from './renderer/elements/index.js';
|
||||
export { fitContent } from './renderer/elements/shape/utils.js';
|
||||
export * from './renderer/elements/type.js';
|
||||
export { Overlay, OverlayIdentifier } from './renderer/overlay.js';
|
||||
|
||||
@@ -3,6 +3,7 @@ import { requestConnectedFrame } from '@blocksuite/affine-shared/utils';
|
||||
import { DisposableGroup } from '@blocksuite/global/disposable';
|
||||
import type { IBound } from '@blocksuite/global/gfx';
|
||||
import { getBoundWithRotation, intersects } from '@blocksuite/global/gfx';
|
||||
import type { BlockStdScope } from '@blocksuite/std';
|
||||
import type {
|
||||
GridManager,
|
||||
LayerManager,
|
||||
@@ -13,6 +14,7 @@ import last from 'lodash-es/last';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import type { SurfaceElementModel } from '../element-model/base.js';
|
||||
import { ElementRendererIdentifier } from '../extensions/element-renderer.js';
|
||||
import { RoughCanvas } from '../utils/rough/canvas.js';
|
||||
import type { ElementRenderer } from './elements/index.js';
|
||||
import type { Overlay } from './overlay.js';
|
||||
@@ -26,12 +28,12 @@ type EnvProvider = {
|
||||
};
|
||||
|
||||
type RendererOptions = {
|
||||
std: BlockStdScope;
|
||||
viewport: Viewport;
|
||||
layerManager: LayerManager;
|
||||
provider?: Partial<EnvProvider>;
|
||||
enableStackingCanvas?: boolean;
|
||||
onStackingCanvasCreated?: (canvas: HTMLCanvasElement) => void;
|
||||
elementRenderers: Record<string, ElementRenderer>;
|
||||
gridManager: GridManager;
|
||||
surfaceModel: SurfaceBlockModel;
|
||||
};
|
||||
@@ -51,7 +53,7 @@ export class CanvasRenderer {
|
||||
|
||||
ctx: CanvasRenderingContext2D;
|
||||
|
||||
elementRenderers: Record<string, ElementRenderer>;
|
||||
std: BlockStdScope;
|
||||
|
||||
grid: GridManager;
|
||||
|
||||
@@ -76,11 +78,11 @@ export class CanvasRenderer {
|
||||
|
||||
this.canvas = canvas;
|
||||
this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
this.std = options.std;
|
||||
this.viewport = options.viewport;
|
||||
this.layerManager = options.layerManager;
|
||||
this.grid = options.gridManager;
|
||||
this.provider = options.provider ?? {};
|
||||
this.elementRenderers = options.elementRenderers;
|
||||
this._initViewport();
|
||||
|
||||
options.enableStackingCanvas = options.enableStackingCanvas ?? false;
|
||||
@@ -277,10 +279,9 @@ export class CanvasRenderer {
|
||||
for (const element of elements) {
|
||||
const display = (element.display ?? true) && !element.hidden;
|
||||
if (display && intersects(getBoundWithRotation(element), bound)) {
|
||||
const renderFn =
|
||||
this.elementRenderers[
|
||||
element.type as keyof typeof this.elementRenderers
|
||||
];
|
||||
const renderFn = this.std.getOptional<ElementRenderer>(
|
||||
ElementRendererIdentifier(element.type)
|
||||
);
|
||||
|
||||
if (!renderFn) {
|
||||
console.warn(`Cannot find renderer for ${element.type}`);
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import type { IBound } from '@blocksuite/global/gfx';
|
||||
import type { GfxPrimitiveElementModel } from '@blocksuite/std/gfx';
|
||||
import type {
|
||||
GfxLocalElementModel,
|
||||
GfxPrimitiveElementModel,
|
||||
} from '@blocksuite/std/gfx';
|
||||
|
||||
import { ElementRendererExtension } from '../../extensions/element-renderer.js';
|
||||
import type { RoughCanvas } from '../../index.js';
|
||||
import type { CanvasRenderer } from '../canvas-renderer.js';
|
||||
import { brush } from './brush/index.js';
|
||||
@@ -13,7 +17,9 @@ import { text } from './text/index.js';
|
||||
export { normalizeShapeBound } from './shape/utils.js';
|
||||
|
||||
export type ElementRenderer<
|
||||
T extends GfxPrimitiveElementModel = GfxPrimitiveElementModel,
|
||||
T extends
|
||||
| GfxPrimitiveElementModel
|
||||
| GfxLocalElementModel = GfxPrimitiveElementModel,
|
||||
> = (
|
||||
model: T,
|
||||
ctx: CanvasRenderingContext2D,
|
||||
@@ -23,12 +29,47 @@ export type ElementRenderer<
|
||||
viewportBound: IBound
|
||||
) => void;
|
||||
|
||||
export const elementRenderers = {
|
||||
brush,
|
||||
highlighter,
|
||||
connector,
|
||||
group,
|
||||
shape,
|
||||
text,
|
||||
mindmap,
|
||||
} as Record<string, ElementRenderer<any>>;
|
||||
export const BrushElementRendererExtension = ElementRendererExtension(
|
||||
'brush',
|
||||
brush
|
||||
);
|
||||
|
||||
export const HighlighterElementRendererExtension = ElementRendererExtension(
|
||||
'highlighter',
|
||||
highlighter
|
||||
);
|
||||
|
||||
export const ConnectorElementRendererExtension = ElementRendererExtension(
|
||||
'connector',
|
||||
connector
|
||||
);
|
||||
|
||||
export const GroupElementRendererExtension = ElementRendererExtension(
|
||||
'group',
|
||||
group
|
||||
);
|
||||
|
||||
export const ShapeElementRendererExtension = ElementRendererExtension(
|
||||
'shape',
|
||||
shape
|
||||
);
|
||||
|
||||
export const TextElementRendererExtension = ElementRendererExtension(
|
||||
'text',
|
||||
text
|
||||
);
|
||||
|
||||
export const MindmapElementRendererExtension = ElementRendererExtension(
|
||||
'mindmap',
|
||||
mindmap
|
||||
);
|
||||
|
||||
export const elementRendererExtensions = [
|
||||
BrushElementRendererExtension,
|
||||
HighlighterElementRendererExtension,
|
||||
ConnectorElementRendererExtension,
|
||||
GroupElementRendererExtension,
|
||||
ShapeElementRendererExtension,
|
||||
TextElementRendererExtension,
|
||||
MindmapElementRendererExtension,
|
||||
];
|
||||
|
||||
@@ -11,17 +11,12 @@ import type { Subject } from 'rxjs';
|
||||
|
||||
import { ConnectorElementModel } from './element-model/index.js';
|
||||
import { CanvasRenderer } from './renderer/canvas-renderer.js';
|
||||
import {
|
||||
type ElementRenderer,
|
||||
elementRenderers,
|
||||
} from './renderer/elements/index.js';
|
||||
import { OverlayIdentifier } from './renderer/overlay.js';
|
||||
import type { SurfaceBlockModel } from './surface-model.js';
|
||||
|
||||
export interface SurfaceContext {
|
||||
viewport: Viewport;
|
||||
host: EditorHost;
|
||||
elementRenderers: Record<string, ElementRenderer>;
|
||||
selection: {
|
||||
selectedIds: string[];
|
||||
slots: {
|
||||
@@ -148,6 +143,7 @@ export class SurfaceBlockComponent extends BlockComponent<SurfaceBlockModel> {
|
||||
const themeService = this.std.get(ThemeProvider);
|
||||
|
||||
this._renderer = new CanvasRenderer({
|
||||
std: this.std,
|
||||
viewport: gfx.viewport,
|
||||
layerManager: gfx.layer,
|
||||
gridManager: gfx.grid,
|
||||
@@ -177,7 +173,6 @@ export class SurfaceBlockComponent extends BlockComponent<SurfaceBlockModel> {
|
||||
onStackingCanvasCreated(canvas) {
|
||||
canvas.className = 'indexable-canvas';
|
||||
},
|
||||
elementRenderers,
|
||||
surfaceModel: this.model,
|
||||
});
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ import {
|
||||
EdgelessLegacySlotExtension,
|
||||
} from './extensions';
|
||||
import { ExportManagerExtension } from './extensions/export-manager/export-manager';
|
||||
import { elementRendererExtensions } from './renderer/elements';
|
||||
|
||||
const CommonSurfaceBlockSpec: ExtensionType[] = [
|
||||
FlavourExtension('affine:surface'),
|
||||
EdgelessCRUDExtension,
|
||||
EdgelessLegacySlotExtension,
|
||||
ExportManagerExtension,
|
||||
...elementRendererExtensions,
|
||||
];
|
||||
|
||||
export const PageSurfaceBlockSpec: ExtensionType[] = [
|
||||
|
||||
Reference in New Issue
Block a user