fix(editor): limit max width when uploading or pasting image into edgeless (#9273)
[BS-2180](https://linear.app/affine-design/issue/BS-2180/白板中粘贴图片,限定一下最大宽度)
This commit is contained in:
1
blocksuite/affine/model/src/consts/image.ts
Normal file
1
blocksuite/affine/model/src/consts/image.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const MAX_IMAGE_WIDTH = 460;
|
||||||
@@ -2,6 +2,7 @@ export * from './brush.js';
|
|||||||
export * from './connector.js';
|
export * from './connector.js';
|
||||||
export * from './doc.js';
|
export * from './doc.js';
|
||||||
export * from './frame.js';
|
export * from './frame.js';
|
||||||
|
export * from './image.js';
|
||||||
export * from './line.js';
|
export * from './line.js';
|
||||||
export * from './mindmap.js';
|
export * from './mindmap.js';
|
||||||
export * from './note.js';
|
export * from './note.js';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FileDropConfigExtension } from '@blocksuite/affine-components/drag-indicator';
|
import { FileDropConfigExtension } from '@blocksuite/affine-components/drag-indicator';
|
||||||
import { ImageBlockSchema } from '@blocksuite/affine-model';
|
import { ImageBlockSchema, MAX_IMAGE_WIDTH } from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
DragHandleConfigExtension,
|
DragHandleConfigExtension,
|
||||||
TelemetryProvider,
|
TelemetryProvider,
|
||||||
@@ -52,7 +52,9 @@ export const ImageDropOption = FileDropConfigExtension({
|
|||||||
if (isInsideEdgelessEditor(std.host)) {
|
if (isInsideEdgelessEditor(std.host)) {
|
||||||
const gfx = std.get(GfxControllerIdentifier);
|
const gfx = std.get(GfxControllerIdentifier);
|
||||||
point = gfx.viewport.toViewCoordFromClientCoord(point);
|
point = gfx.viewport.toViewCoordFromClientCoord(point);
|
||||||
addImages(std, files, point).catch(console.error);
|
addImages(std, files, { point, maxWidth: MAX_IMAGE_WIDTH }).catch(
|
||||||
|
console.error
|
||||||
|
);
|
||||||
|
|
||||||
std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||||
control: 'canvas:drop',
|
control: 'canvas:drop',
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
||||||
import {
|
import {
|
||||||
CanvasElementType,
|
CanvasElementType,
|
||||||
SurfaceGroupLikeModel,
|
SurfaceGroupLikeModel,
|
||||||
@@ -9,6 +8,7 @@ import {
|
|||||||
BookmarkStyles,
|
BookmarkStyles,
|
||||||
DEFAULT_NOTE_HEIGHT,
|
DEFAULT_NOTE_HEIGHT,
|
||||||
DEFAULT_NOTE_WIDTH,
|
DEFAULT_NOTE_WIDTH,
|
||||||
|
MAX_IMAGE_WIDTH,
|
||||||
ReferenceInfoSchema,
|
ReferenceInfoSchema,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
@@ -256,7 +256,10 @@ export class EdgelessClipboardController extends PageClipboard {
|
|||||||
|
|
||||||
// when only images in clipboard, add image-blocks else add all files as attachments
|
// when only images in clipboard, add image-blocks else add all files as attachments
|
||||||
if (attachmentFiles.length === 0) {
|
if (attachmentFiles.length === 0) {
|
||||||
await addImages(this.std, imageFiles, point);
|
await addImages(this.std, imageFiles, {
|
||||||
|
point,
|
||||||
|
maxWidth: MAX_IMAGE_WIDTH,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await addAttachments(this.std, [...files], point);
|
await addAttachments(this.std, [...files], point);
|
||||||
}
|
}
|
||||||
@@ -359,7 +362,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
|||||||
|
|
||||||
const svg = tryGetSvgFromClipboard(data);
|
const svg = tryGetSvgFromClipboard(data);
|
||||||
if (svg) {
|
if (svg) {
|
||||||
await addImages(this.std, [svg], point);
|
await addImages(this.std, [svg], { point, maxWidth: MAX_IMAGE_WIDTH });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { AttachmentIcon, LinkIcon } from '@blocksuite/affine-components/icons';
|
import { AttachmentIcon, LinkIcon } from '@blocksuite/affine-components/icons';
|
||||||
|
import { MAX_IMAGE_WIDTH } from '@blocksuite/affine-model';
|
||||||
import { TelemetryProvider } from '@blocksuite/affine-shared/services';
|
import { TelemetryProvider } from '@blocksuite/affine-shared/services';
|
||||||
import type { GfxToolsFullOptionValue } from '@blocksuite/block-std/gfx';
|
import type { GfxToolsFullOptionValue } from '@blocksuite/block-std/gfx';
|
||||||
import { effect } from '@preact/signals-core';
|
import { effect } from '@preact/signals-core';
|
||||||
@@ -55,7 +56,9 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
|
|||||||
private async _addImages() {
|
private async _addImages() {
|
||||||
this._imageLoading = true;
|
this._imageLoading = true;
|
||||||
const imageFiles = await getImageFilesFromLocal();
|
const imageFiles = await getImageFilesFromLocal();
|
||||||
const ids = await addImages(this.edgeless.std, imageFiles);
|
const ids = await addImages(this.edgeless.std, imageFiles, {
|
||||||
|
maxWidth: MAX_IMAGE_WIDTH,
|
||||||
|
});
|
||||||
this._imageLoading = false;
|
this._imageLoading = false;
|
||||||
this.edgeless.gfx.tool.setTool('default');
|
this.edgeless.gfx.tool.setTool('default');
|
||||||
this.edgeless.gfx.selection.set({ elements: ids });
|
this.edgeless.gfx.selection.set({ elements: ids });
|
||||||
|
|||||||
@@ -118,7 +118,10 @@ export async function addAttachments(
|
|||||||
export async function addImages(
|
export async function addImages(
|
||||||
std: BlockStdScope,
|
std: BlockStdScope,
|
||||||
files: File[],
|
files: File[],
|
||||||
point?: IVec
|
options: {
|
||||||
|
point?: IVec;
|
||||||
|
maxWidth?: number;
|
||||||
|
}
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const imageFiles = [...files].filter(file => file.type.startsWith('image/'));
|
const imageFiles = [...files].filter(file => file.type.startsWith('image/'));
|
||||||
if (!imageFiles.length) return [];
|
if (!imageFiles.length) return [];
|
||||||
@@ -145,6 +148,7 @@ export async function addImages(
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { point, maxWidth } = options;
|
||||||
let { x, y } = gfx.viewport.center;
|
let { x, y } = gfx.viewport.center;
|
||||||
if (point) [x, y] = gfx.viewport.toModelCoord(...point);
|
if (point) [x, y] = gfx.viewport.toModelCoord(...point);
|
||||||
|
|
||||||
@@ -166,6 +170,7 @@ export async function addImages(
|
|||||||
{
|
{
|
||||||
size: file.size,
|
size: file.size,
|
||||||
xywh: bound.serialize(),
|
xywh: bound.serialize(),
|
||||||
|
index: gfx.layer.generateIndex(),
|
||||||
},
|
},
|
||||||
gfx.surface
|
gfx.surface
|
||||||
);
|
);
|
||||||
@@ -180,17 +185,22 @@ export async function addImages(
|
|||||||
const imageSize = await readImageSize(file);
|
const imageSize = await readImageSize(file);
|
||||||
|
|
||||||
const center = Vec.toVec(point);
|
const center = Vec.toVec(point);
|
||||||
const bound = calcBoundByOrigin(
|
// If maxWidth is provided, limit the width of the image to maxWidth
|
||||||
center,
|
// Otherwise, use the original width
|
||||||
inTopLeft,
|
const width = maxWidth
|
||||||
imageSize.width,
|
? Math.min(imageSize.width, maxWidth)
|
||||||
imageSize.height
|
: imageSize.width;
|
||||||
);
|
const height = maxWidth
|
||||||
|
? (imageSize.height / imageSize.width) * width
|
||||||
|
: imageSize.height;
|
||||||
|
const bound = calcBoundByOrigin(center, inTopLeft, width, height);
|
||||||
|
|
||||||
std.doc.withoutTransact(() => {
|
std.doc.withoutTransact(() => {
|
||||||
gfx.updateElement(blockId, {
|
gfx.updateElement(blockId, {
|
||||||
sourceId,
|
sourceId,
|
||||||
...imageSize,
|
...imageSize,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
xywh: bound.serialize(),
|
xywh: bound.serialize(),
|
||||||
} satisfies Partial<ImageBlockProps>);
|
} satisfies Partial<ImageBlockProps>);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ function responseToCreateImage(host: EditorHost) {
|
|||||||
const [x, y] = edgelessRoot.service.viewport.toViewCoord(minX, minY);
|
const [x, y] = edgelessRoot.service.viewport.toViewCoord(minX, minY);
|
||||||
|
|
||||||
host.doc.transact(() => {
|
host.doc.transact(() => {
|
||||||
addImages(edgelessRoot.std, [img], [x, y])
|
addImages(edgelessRoot.std, [img], { point: [x, y] })
|
||||||
.then(blockIds => {
|
.then(blockIds => {
|
||||||
const imageBlockId = blockIds[0];
|
const imageBlockId = blockIds[0];
|
||||||
const imageBlock = host.doc.getBlock(imageBlockId);
|
const imageBlock = host.doc.getBlock(imageBlockId);
|
||||||
|
|||||||
Reference in New Issue
Block a user