From d7c0e66c3e96dd5fce38ac5994deba7a11474752 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 2 Feb 2026 10:57:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=BB=E5=B8=83=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E6=8C=89=E5=8E=9F=E5=A7=8B=E6=AF=94=E4=BE=8B=201:1=20=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 图片使用 object-contain 保持原始比例,不再裁剪 - 添加 getImageDimensions 函数获取图片原始尺寸 - 图片节点大小根据原始尺寸动态设置(最大 500px,最小 150px) - 图片间距动态调整,避免重叠 --- components/canvas/CanvasChatPanel.tsx | 67 ++++++++++++++++++++++----- components/canvas/nodes/ImageNode.tsx | 4 +- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index d51ff2d..0ed74c8 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -34,6 +34,41 @@ interface CanvasChatPanelProps { // 建议卡片数据 - 已移除 const SUGGESTIONS: { title: string; desc: string; image: string }[] = []; +// 获取图片的原始尺寸 +function getImageDimensions(url: string): Promise<{ width: number; height: number }> { + return new Promise((resolve) => { + const img = new Image(); + img.onload = () => { + // 限制最大尺寸,避免节点过大 + const maxSize = 500; + let width = img.naturalWidth; + let height = img.naturalHeight; + + // 如果图片太大,按比例缩小 + if (width > maxSize || height > maxSize) { + const scale = Math.min(maxSize / width, maxSize / height); + width = Math.round(width * scale); + height = Math.round(height * scale); + } + + // 设置最小尺寸 + const minSize = 150; + if (width < minSize && height < minSize) { + const scale = minSize / Math.min(width, height); + width = Math.round(width * scale); + height = Math.round(height * scale); + } + + resolve({ width, height }); + }; + img.onerror = () => { + // 加载失败时使用默认尺寸 + resolve({ width: 300, height: 300 }); + }; + img.src = url; + }); +} + // 从消息中提取图片 URL(只提取原始图片,避免重复) function extractImageUrls(text: string): string[] { const urls: string[] = []; @@ -349,7 +384,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF } // 只处理新消息 - messages.forEach(message => { + messages.forEach(async (message) => { if (message.role === 'assistant' && !processedMessageIds.current.has(message.id)) { const content = message.parts?.map((p: any) => p.text || '').join('') || ''; const imageUrls = extractImageUrls(content); @@ -366,16 +401,22 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF // 只添加不存在的图片 const newUrls = imageUrls.filter(url => !existingUrls.has(url)); - newUrls.forEach((url, index) => { - // 计算位置(避免重叠) - const existingNodes = nodes.length; - const x = 100 + ((existingNodes + index) % 4) * 320; - const y = 100 + Math.floor((existingNodes + index) / 4) * 320; + // 异步获取每张图片的尺寸并添加到画布 + for (let index = 0; index < newUrls.length; index++) { + const url = newUrls[index]; + // 获取图片原始尺寸 + const dimensions = await getImageDimensions(url); + + // 计算位置(避免重叠,根据图片宽度动态调整间距) + const existingNodes = nodes.length + index; + const spacing = 20; // 图片间距 + const x = 100 + (existingNodes % 3) * (dimensions.width + spacing); + const y = 100 + Math.floor(existingNodes / 3) * (dimensions.height + spacing); addNode({ type: 'image', position: { x, y }, - size: { width: 300, height: 300 }, + size: { width: dimensions.width, height: dimensions.height }, data: { src: url, status: 'completed', @@ -383,7 +424,7 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF }, connections: [], }); - }); + } if (newUrls.length > 0) { toast.success(`已将 ${newUrls.length} 张图片添加到画布`); @@ -605,15 +646,17 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF }]; }); - // 立即将图片添加到画布 + // 获取图片原始尺寸后添加到画布 + const dimensions = await getImageDimensions(imageUrl); const existingNodes = nodes.length; - const x = 100 + (existingNodes % 4) * 320; - const y = 100 + Math.floor(existingNodes / 4) * 320; + const spacing = 20; + const x = 100 + (existingNodes % 3) * (dimensions.width + spacing); + const y = 100 + Math.floor(existingNodes / 3) * (dimensions.height + spacing); addNode({ type: 'image', position: { x, y }, - size: { width: 300, height: 300 }, + size: { width: dimensions.width, height: dimensions.height }, data: { src: imageUrl, status: 'completed', diff --git a/components/canvas/nodes/ImageNode.tsx b/components/canvas/nodes/ImageNode.tsx index 6629d43..b691616 100644 --- a/components/canvas/nodes/ImageNode.tsx +++ b/components/canvas/nodes/ImageNode.tsx @@ -384,12 +384,12 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) { onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > - {/* 图片内容 */} + {/* 图片内容 - 使用 object-contain 保持原始比例 */} {data.src ? ( {data.prompt ) : data.status === 'generating' ? (