feat: 画布图片按原始比例 1:1 显示
- 图片使用 object-contain 保持原始比例,不再裁剪 - 添加 getImageDimensions 函数获取图片原始尺寸 - 图片节点大小根据原始尺寸动态设置(最大 500px,最小 150px) - 图片间距动态调整,避免重叠
This commit is contained in:
parent
52867404f7
commit
d7c0e66c3e
@ -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',
|
||||
|
||||
@ -384,12 +384,12 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
{/* 图片内容 */}
|
||||
{/* 图片内容 - 使用 object-contain 保持原始比例 */}
|
||||
{data.src ? (
|
||||
<img
|
||||
src={data.src}
|
||||
alt={data.prompt || "图片"}
|
||||
className="w-full h-full object-cover"
|
||||
className="w-full h-full object-contain bg-muted/30"
|
||||
draggable={false}
|
||||
/>
|
||||
) : data.status === 'generating' ? (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user