mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
feat(editor): add basic image support in turbo renderer (#11620)
This PR adds basic support for image block: 
This commit is contained in:
@@ -7,5 +7,7 @@ export { ImageProxyService } from './image-proxy-service';
|
||||
export * from './image-service';
|
||||
export * from './image-spec';
|
||||
export * from './styles';
|
||||
export * from './turbo/image-layout-handler';
|
||||
export * from './turbo/image-painter.worker';
|
||||
export { addImages, downloadImageBlob, uploadBlobForImage } from './utils';
|
||||
export { ImageSelection } from '@blocksuite/affine-shared/selection';
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import type { Rect } from '@blocksuite/affine-gfx-turbo-renderer';
|
||||
import {
|
||||
BlockLayoutHandlerExtension,
|
||||
BlockLayoutHandlersIdentifier,
|
||||
} from '@blocksuite/affine-gfx-turbo-renderer';
|
||||
import type { Container } from '@blocksuite/global/di';
|
||||
import type { EditorHost, GfxBlockComponent } from '@blocksuite/std';
|
||||
import { clientToModelCoord, type ViewportRecord } from '@blocksuite/std/gfx';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { ImageLayout } from './image-painter.worker';
|
||||
|
||||
export class ImageLayoutHandlerExtension extends BlockLayoutHandlerExtension<ImageLayout> {
|
||||
readonly blockType = 'affine:image';
|
||||
|
||||
static override setup(di: Container) {
|
||||
di.addImpl(
|
||||
BlockLayoutHandlersIdentifier('image'),
|
||||
ImageLayoutHandlerExtension
|
||||
);
|
||||
}
|
||||
|
||||
override queryLayout(
|
||||
model: BlockModel,
|
||||
host: EditorHost,
|
||||
viewportRecord: ViewportRecord
|
||||
): ImageLayout | null {
|
||||
const component = host.std.view.getBlock(model.id) as GfxBlockComponent;
|
||||
if (!component) return null;
|
||||
|
||||
const imageContainer = component.querySelector('.affine-image-container');
|
||||
if (!imageContainer) return null;
|
||||
|
||||
const resizableImg = component.querySelector(
|
||||
'.resizable-img'
|
||||
) as HTMLElement;
|
||||
if (!resizableImg) return null;
|
||||
|
||||
const { zoom, viewScale } = viewportRecord;
|
||||
const rect = resizableImg.getBoundingClientRect();
|
||||
|
||||
const [modelX, modelY] = clientToModelCoord(viewportRecord, [
|
||||
rect.x,
|
||||
rect.y,
|
||||
]);
|
||||
|
||||
const imageLayout: ImageLayout = {
|
||||
type: 'affine:image',
|
||||
blockId: model.id,
|
||||
rect: {
|
||||
x: modelX,
|
||||
y: modelY,
|
||||
w: rect.width / zoom / viewScale,
|
||||
h: rect.height / zoom / viewScale,
|
||||
},
|
||||
};
|
||||
|
||||
return imageLayout;
|
||||
}
|
||||
|
||||
calculateBound(layout: ImageLayout) {
|
||||
const rect: Rect = layout.rect;
|
||||
|
||||
return {
|
||||
rect,
|
||||
subRects: [rect],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import type {
|
||||
BlockLayout,
|
||||
BlockLayoutPainter,
|
||||
} from '@blocksuite/affine-gfx-turbo-renderer';
|
||||
import { BlockLayoutPainterExtension } from '@blocksuite/affine-gfx-turbo-renderer/painter';
|
||||
|
||||
export interface ImageLayout extends BlockLayout {
|
||||
type: 'affine:image';
|
||||
rect: {
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
};
|
||||
}
|
||||
|
||||
function isImageLayout(layout: BlockLayout): layout is ImageLayout {
|
||||
return layout.type === 'affine:image';
|
||||
}
|
||||
|
||||
class ImageLayoutPainter implements BlockLayoutPainter {
|
||||
paint(
|
||||
ctx: OffscreenCanvasRenderingContext2D,
|
||||
layout: BlockLayout,
|
||||
layoutBaseX: number,
|
||||
layoutBaseY: number
|
||||
): void {
|
||||
if (!isImageLayout(layout)) {
|
||||
console.warn(
|
||||
'Expected image layout but received different format:',
|
||||
layout
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// For now, just paint a white rectangle
|
||||
const x = layout.rect.x - layoutBaseX;
|
||||
const y = layout.rect.y - layoutBaseY;
|
||||
const width = layout.rect.w;
|
||||
const height = layout.rect.h;
|
||||
|
||||
// Draw a white rectangle with border
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.fillRect(x, y, width, height);
|
||||
|
||||
// Add a border
|
||||
ctx.strokeStyle = '#e0e0e0';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeRect(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
export const ImageLayoutPainterExtension = BlockLayoutPainterExtension(
|
||||
'affine:image',
|
||||
ImageLayoutPainter
|
||||
);
|
||||
Reference in New Issue
Block a user