You've already forked Nano-Banana-AI-Image-Editor
移除了生成详情中的下载按钮
This commit is contained in:
@@ -1,199 +0,0 @@
|
|||||||
// 全面测试修复效果
|
|
||||||
async function comprehensiveTest() {
|
|
||||||
console.log('=== 全面测试修复效果 ===');
|
|
||||||
|
|
||||||
// 模拟React状态和refs
|
|
||||||
let canvasImageState = null;
|
|
||||||
let imageState = null;
|
|
||||||
let canvasZoomState = 1;
|
|
||||||
let canvasPanState = { x: 0, y: 0 };
|
|
||||||
let stageSizeState = { width: 800, height: 600 };
|
|
||||||
|
|
||||||
// 模拟stageRef
|
|
||||||
const stageRefMock = {
|
|
||||||
current: {
|
|
||||||
scaleX: () => canvasZoomState,
|
|
||||||
scaleY: () => canvasZoomState,
|
|
||||||
x: () => canvasPanState.x * canvasZoomState,
|
|
||||||
y: () => canvasPanState.y * canvasZoomState,
|
|
||||||
scale: (scale) => {
|
|
||||||
if (scale) {
|
|
||||||
canvasZoomState = scale.x;
|
|
||||||
console.log('Stage缩放已设置为:', scale.x);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
position: (pos) => {
|
|
||||||
if (pos) {
|
|
||||||
canvasPanState = { x: pos.x / canvasZoomState, y: pos.y / canvasZoomState };
|
|
||||||
console.log('Stage位置已设置为:', pos);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
batchDraw: () => {
|
|
||||||
console.log('Stage已重新绘制');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 模拟setter函数
|
|
||||||
const setCanvasImage = (url) => {
|
|
||||||
console.log('setCanvasImage被调用:', url);
|
|
||||||
canvasImageState = url;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setImage = (img) => {
|
|
||||||
console.log('setImage被调用');
|
|
||||||
imageState = img;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCanvasZoom = (zoom) => {
|
|
||||||
console.log('setCanvasZoom被调用:', zoom);
|
|
||||||
canvasZoomState = zoom;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCanvasPan = (pan) => {
|
|
||||||
console.log('setCanvasPan被调用:', pan);
|
|
||||||
canvasPanState = pan;
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('\n1. 测试图像加载useEffect...');
|
|
||||||
|
|
||||||
// 模拟canvasImage变化
|
|
||||||
const testImageUrl = 'https://cdn.pandorastudio.cn/upload/886ab948b.png';
|
|
||||||
console.log('设置canvasImage为:', testImageUrl);
|
|
||||||
setCanvasImage(testImageUrl);
|
|
||||||
|
|
||||||
// 模拟图像加载useEffect执行
|
|
||||||
function simulateImageLoadingEffect() {
|
|
||||||
console.log('执行图像加载useEffect...');
|
|
||||||
|
|
||||||
if (canvasImageState) {
|
|
||||||
console.log('开始加载图像:', canvasImageState);
|
|
||||||
|
|
||||||
// 模拟图像加载完成
|
|
||||||
const mockImage = {
|
|
||||||
width: 1024,
|
|
||||||
height: 1024,
|
|
||||||
src: canvasImageState
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('图像加载完成,尺寸:', mockImage.width, 'x', mockImage.height);
|
|
||||||
setImage(mockImage);
|
|
||||||
|
|
||||||
// 模拟自动适应画布(使用setTimeout模拟)
|
|
||||||
console.log('模拟自动适应画布...');
|
|
||||||
|
|
||||||
// 计算最优缩放
|
|
||||||
const isMobile = window.innerWidth < 768;
|
|
||||||
const padding = isMobile ? 0.9 : 0.8;
|
|
||||||
|
|
||||||
const scaleX = (stageSizeState.width * padding) / mockImage.width;
|
|
||||||
const scaleY = (stageSizeState.height * padding) / mockImage.height;
|
|
||||||
|
|
||||||
const maxZoom = isMobile ? 0.3 : 0.8;
|
|
||||||
const optimalZoom = Math.min(scaleX, scaleY, maxZoom);
|
|
||||||
|
|
||||||
// 直接通过stage控制,不依赖状态更新
|
|
||||||
console.log('直接设置Stage缩放:', optimalZoom);
|
|
||||||
stageRefMock.current.scale({ x: optimalZoom, y: optimalZoom });
|
|
||||||
stageRefMock.current.position({ x: 0, y: 0 });
|
|
||||||
stageRefMock.current.batchDraw();
|
|
||||||
|
|
||||||
// 同时更新React状态以保持同步
|
|
||||||
setCanvasZoom(optimalZoom);
|
|
||||||
setCanvasPan({ x: 0, y: 0 });
|
|
||||||
|
|
||||||
console.log('图像自动适应画布完成');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
simulateImageLoadingEffect();
|
|
||||||
|
|
||||||
console.log('\n2. 测试多次执行useEffect...');
|
|
||||||
|
|
||||||
// 模拟多次执行useEffect,确保不会引起无限循环
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
console.log(`\n第${i + 1}次执行useEffect:`);
|
|
||||||
simulateImageLoadingEffect();
|
|
||||||
|
|
||||||
// 检查状态是否稳定
|
|
||||||
console.log(' 当前canvasZoom:', canvasZoomState);
|
|
||||||
console.log(' 当前canvasPan:', canvasPanState);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\n3. 测试handleZoom函数...');
|
|
||||||
|
|
||||||
// 模拟handleZoom函数
|
|
||||||
function handleZoom(delta) {
|
|
||||||
const stage = stageRefMock.current;
|
|
||||||
if (stage) {
|
|
||||||
const currentZoom = stage.scaleX();
|
|
||||||
const newZoom = Math.max(0.1, Math.min(3, currentZoom + delta));
|
|
||||||
|
|
||||||
// 直接通过stage控制
|
|
||||||
console.log('handleZoom: 设置新缩放:', newZoom);
|
|
||||||
stage.scale({ x: newZoom, y: newZoom });
|
|
||||||
stage.batchDraw();
|
|
||||||
|
|
||||||
// 同时更新React状态以保持同步
|
|
||||||
setCanvasZoom(newZoom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('调用handleZoom(0.1)...');
|
|
||||||
handleZoom(0.1);
|
|
||||||
|
|
||||||
console.log('调用handleZoom(-0.1)...');
|
|
||||||
handleZoom(-0.1);
|
|
||||||
|
|
||||||
console.log('\n4. 测试handleReset函数...');
|
|
||||||
|
|
||||||
// 模拟handleReset函数
|
|
||||||
function handleReset() {
|
|
||||||
if (imageState) {
|
|
||||||
const isMobile = window.innerWidth < 768;
|
|
||||||
const padding = isMobile ? 0.9 : 0.8;
|
|
||||||
const scaleX = (stageSizeState.width * padding) / imageState.width;
|
|
||||||
const scaleY = (stageSizeState.height * padding) / imageState.height;
|
|
||||||
const maxZoom = isMobile ? 0.3 : 0.8;
|
|
||||||
const optimalZoom = Math.min(scaleX, scaleY, maxZoom);
|
|
||||||
|
|
||||||
// 直接通过stage控制
|
|
||||||
console.log('handleReset: 设置最优缩放:', optimalZoom);
|
|
||||||
stageRefMock.current.scale({ x: optimalZoom, y: optimalZoom });
|
|
||||||
stageRefMock.current.position({ x: 0, y: 0 });
|
|
||||||
stageRefMock.current.batchDraw();
|
|
||||||
|
|
||||||
// 同时更新React状态以保持同步
|
|
||||||
setCanvasZoom(optimalZoom);
|
|
||||||
setCanvasPan({ x: 0, y: 0 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('调用handleReset()...');
|
|
||||||
handleReset();
|
|
||||||
|
|
||||||
console.log('\n5. 测试新图像加载...');
|
|
||||||
|
|
||||||
// 模拟加载新图像
|
|
||||||
const newImageUrl = 'https://cdn.pandorastudio.cn/upload/new-image.png';
|
|
||||||
console.log('加载新图像:', newImageUrl);
|
|
||||||
|
|
||||||
setCanvasImage(newImageUrl);
|
|
||||||
simulateImageLoadingEffect();
|
|
||||||
|
|
||||||
console.log('\n=== 测试完成 ===');
|
|
||||||
console.log('\n最终状态:');
|
|
||||||
console.log('canvasImage:', canvasImageState);
|
|
||||||
console.log('canvasZoom:', canvasZoomState);
|
|
||||||
console.log('canvasPan:', canvasPanState);
|
|
||||||
|
|
||||||
console.log('\n修复效果验证:');
|
|
||||||
console.log('✓ 图像加载useEffect只依赖于canvasImage');
|
|
||||||
console.log('✓ 通过stageRef直接控制Stage,避免状态循环更新');
|
|
||||||
console.log('✓ React状态与Stage状态保持同步');
|
|
||||||
console.log('✓ handleZoom和handleReset函数正确工作');
|
|
||||||
console.log('✓ 多次执行不会引起无限循环');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 运行测试
|
|
||||||
comprehensiveTest();
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
// 测试居中显示修复效果
|
|
||||||
async function testCenteringFix() {
|
|
||||||
console.log('=== 测试居中显示修复效果 ===');
|
|
||||||
|
|
||||||
// 模拟React状态和refs
|
|
||||||
let canvasImageState = null;
|
|
||||||
let imageState = null;
|
|
||||||
let canvasZoomState = 1;
|
|
||||||
let canvasPanState = { x: 0, y: 0 };
|
|
||||||
let stageSizeState = { width: 800, height: 600 };
|
|
||||||
|
|
||||||
// 模拟stageRef
|
|
||||||
const stageRefMock = {
|
|
||||||
current: {
|
|
||||||
scaleX: () => canvasZoomState,
|
|
||||||
scaleY: () => canvasZoomState,
|
|
||||||
x: () => canvasPanState.x * canvasZoomState,
|
|
||||||
y: () => canvasPanState.y * canvasZoomState,
|
|
||||||
scale: (scale) => {
|
|
||||||
if (scale) {
|
|
||||||
canvasZoomState = scale.x;
|
|
||||||
console.log('Stage缩放已设置为:', scale.x);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
position: (pos) => {
|
|
||||||
if (pos) {
|
|
||||||
canvasPanState = { x: pos.x / canvasZoomState, y: pos.y / canvasZoomState };
|
|
||||||
console.log('Stage位置已设置为:', pos);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
batchDraw: () => {
|
|
||||||
console.log('Stage已重新绘制');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 模拟setter函数
|
|
||||||
const setCanvasImage = (url) => {
|
|
||||||
console.log('setCanvasImage被调用:', url);
|
|
||||||
canvasImageState = url;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setImage = (img) => {
|
|
||||||
console.log('setImage被调用');
|
|
||||||
imageState = img;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCanvasZoom = (zoom) => {
|
|
||||||
console.log('setCanvasZoom被调用,新值:', zoom);
|
|
||||||
canvasZoomState = zoom;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCanvasPan = (pan) => {
|
|
||||||
console.log('setCanvasPan被调用,新值:', pan);
|
|
||||||
canvasPanState = pan;
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('\n1. 测试图像加载时的居中计算...');
|
|
||||||
|
|
||||||
// 模拟canvasImage变化
|
|
||||||
const testImageUrl = 'https://cdn.pandorastudio.cn/upload/886ab948b.png';
|
|
||||||
console.log('设置canvasImage为:', testImageUrl);
|
|
||||||
setCanvasImage(testImageUrl);
|
|
||||||
|
|
||||||
// 模拟图像加载完成
|
|
||||||
const mockImage = {
|
|
||||||
width: 1024,
|
|
||||||
height: 1024,
|
|
||||||
src: testImageUrl
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('图像加载完成,尺寸:', mockImage.width, 'x', mockImage.height);
|
|
||||||
setImage(mockImage);
|
|
||||||
|
|
||||||
console.log('\n2. 测试图像居中逻辑...');
|
|
||||||
|
|
||||||
// 模拟图像加载完成后的居中逻辑
|
|
||||||
function simulateImageCentering() {
|
|
||||||
console.log('开始图像居中计算...');
|
|
||||||
|
|
||||||
const isMobile = window.innerWidth < 768;
|
|
||||||
const padding = isMobile ? 0.9 : 0.8;
|
|
||||||
|
|
||||||
const scaleX = (stageSizeState.width * padding) / mockImage.width;
|
|
||||||
const scaleY = (stageSizeState.height * padding) / mockImage.height;
|
|
||||||
|
|
||||||
const maxZoom = isMobile ? 0.3 : 0.8;
|
|
||||||
const optimalZoom = Math.min(scaleX, scaleY, maxZoom);
|
|
||||||
|
|
||||||
console.log('计算得到的最优缩放:', optimalZoom);
|
|
||||||
|
|
||||||
// 立即更新React状态以确保Konva Image组件使用正确的缩放值
|
|
||||||
console.log('立即更新React状态...');
|
|
||||||
setCanvasZoom(optimalZoom);
|
|
||||||
setCanvasPan({ x: 0, y: 0 });
|
|
||||||
|
|
||||||
// 模拟setTimeout中的Stage设置
|
|
||||||
console.log('模拟setTimeout中的Stage设置...');
|
|
||||||
|
|
||||||
// 直接设置缩放,但保持Stage居中
|
|
||||||
stageRefMock.current.scale({ x: optimalZoom, y: optimalZoom });
|
|
||||||
// 重置Stage位置以确保居中
|
|
||||||
stageRefMock.current.position({ x: 0, y: 0 });
|
|
||||||
stageRefMock.current.batchDraw();
|
|
||||||
|
|
||||||
console.log('图像居中设置完成');
|
|
||||||
}
|
|
||||||
|
|
||||||
simulateImageCentering();
|
|
||||||
|
|
||||||
console.log('\n3. 测试Konva Image组件的坐标计算...');
|
|
||||||
|
|
||||||
// 模拟Konva Image组件的坐标计算
|
|
||||||
function calculateImagePosition() {
|
|
||||||
console.log('使用当前状态计算图像位置...');
|
|
||||||
console.log('stageSize.width:', stageSizeState.width);
|
|
||||||
console.log('stageSize.height:', stageSizeState.height);
|
|
||||||
console.log('canvasZoom:', canvasZoomState);
|
|
||||||
console.log('image.width:', mockImage.width);
|
|
||||||
console.log('image.height:', mockImage.height);
|
|
||||||
|
|
||||||
const x = (stageSizeState.width / canvasZoomState - mockImage.width) / 2;
|
|
||||||
const y = (stageSizeState.height / canvasZoomState - mockImage.height) / 2;
|
|
||||||
|
|
||||||
console.log('计算得到的图像坐标: x=', x, 'y=', y);
|
|
||||||
|
|
||||||
// 验证是否居中
|
|
||||||
const stageCenterX = stageSizeState.width / 2;
|
|
||||||
const stageCenterY = stageSizeState.height / 2;
|
|
||||||
const imageCenterX = x + mockImage.width / 2;
|
|
||||||
const imageCenterY = y + mockImage.height / 2;
|
|
||||||
|
|
||||||
console.log('Stage中心点:', stageCenterX, 'x', stageCenterY);
|
|
||||||
console.log('图像中心点:', imageCenterX, 'x', imageCenterY);
|
|
||||||
|
|
||||||
const isCentered = Math.abs(stageCenterX - imageCenterX) < 1 && Math.abs(stageCenterY - imageCenterY) < 1;
|
|
||||||
console.log('图像是否居中:', isCentered ? '是' : '否');
|
|
||||||
|
|
||||||
return { x, y, isCentered };
|
|
||||||
}
|
|
||||||
|
|
||||||
const position = calculateImagePosition();
|
|
||||||
|
|
||||||
console.log('\n4. 测试handleReset函数...');
|
|
||||||
|
|
||||||
// 模拟handleReset函数
|
|
||||||
function handleReset() {
|
|
||||||
console.log('执行handleReset...');
|
|
||||||
|
|
||||||
if (imageState) {
|
|
||||||
const isMobile = window.innerWidth < 768;
|
|
||||||
const padding = isMobile ? 0.9 : 0.8;
|
|
||||||
const scaleX = (stageSizeState.width * padding) / imageState.width;
|
|
||||||
const scaleY = (stageSizeState.height * padding) / imageState.height;
|
|
||||||
const maxZoom = isMobile ? 0.3 : 0.8;
|
|
||||||
const optimalZoom = Math.min(scaleX, scaleY, maxZoom);
|
|
||||||
|
|
||||||
console.log('计算得到的最优缩放:', optimalZoom);
|
|
||||||
|
|
||||||
// 先更新React状态
|
|
||||||
setCanvasZoom(optimalZoom);
|
|
||||||
setCanvasPan({ x: 0, y: 0 });
|
|
||||||
|
|
||||||
// 模拟setTimeout中的Stage设置
|
|
||||||
console.log('模拟setTimeout中的Stage设置...');
|
|
||||||
|
|
||||||
// 直接控制Stage
|
|
||||||
stageRefMock.current.scale({ x: optimalZoom, y: optimalZoom });
|
|
||||||
stageRefMock.current.position({ x: 0, y: 0 });
|
|
||||||
stageRefMock.current.batchDraw();
|
|
||||||
|
|
||||||
console.log('handleReset执行完成');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleReset();
|
|
||||||
|
|
||||||
console.log('\n5. 测试handleZoom函数...');
|
|
||||||
|
|
||||||
// 模拟handleZoom函数
|
|
||||||
function handleZoom(delta) {
|
|
||||||
console.log('执行handleZoom,delta:', delta);
|
|
||||||
|
|
||||||
const currentZoom = stageRefMock.current.scaleX();
|
|
||||||
const newZoom = Math.max(0.1, Math.min(3, currentZoom + delta));
|
|
||||||
|
|
||||||
console.log('当前缩放:', currentZoom, '新缩放:', newZoom);
|
|
||||||
|
|
||||||
// 先更新React状态
|
|
||||||
setCanvasZoom(newZoom);
|
|
||||||
|
|
||||||
// 模拟setTimeout中的Stage设置
|
|
||||||
console.log('模拟setTimeout中的Stage设置...');
|
|
||||||
|
|
||||||
// 直接控制Stage
|
|
||||||
stageRefMock.current.scale({ x: newZoom, y: newZoom });
|
|
||||||
stageRefMock.current.batchDraw();
|
|
||||||
|
|
||||||
console.log('handleZoom执行完成');
|
|
||||||
}
|
|
||||||
|
|
||||||
handleZoom(0.1);
|
|
||||||
|
|
||||||
console.log('\n=== 测试完成 ===');
|
|
||||||
console.log('\n最终状态:');
|
|
||||||
console.log('canvasZoom:', canvasZoomState);
|
|
||||||
console.log('canvasPan:', canvasPanState);
|
|
||||||
console.log('图像位置:', position);
|
|
||||||
|
|
||||||
console.log('\n修复效果验证:');
|
|
||||||
console.log('✓ 图像加载时正确计算并设置居中位置');
|
|
||||||
console.log('✓ React状态与Stage状态保持同步');
|
|
||||||
console.log('✓ Konva Image组件使用正确的坐标计算');
|
|
||||||
console.log('✓ handleReset和handleZoom函数正确处理居中');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 运行测试
|
|
||||||
testCenteringFix();
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
// 测试修复效果
|
|
||||||
async function testFixEffect() {
|
|
||||||
console.log('=== 测试修复效果 ===');
|
|
||||||
|
|
||||||
// 模拟React状态和setter函数
|
|
||||||
let canvasImageState = null;
|
|
||||||
let imageState = null;
|
|
||||||
let canvasZoomState = 1;
|
|
||||||
let canvasPanState = { x: 0, y: 0 };
|
|
||||||
let stageSizeState = { width: 800, height: 600 };
|
|
||||||
|
|
||||||
// 模拟setter函数
|
|
||||||
const setCanvasImage = (url) => {
|
|
||||||
console.log('setCanvasImage被调用:', url);
|
|
||||||
canvasImageState = url;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setImage = (img) => {
|
|
||||||
console.log('setImage被调用');
|
|
||||||
imageState = img;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCanvasZoom = (zoom) => {
|
|
||||||
console.log('setCanvasZoom被调用:', zoom);
|
|
||||||
canvasZoomState = zoom;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCanvasPan = (pan) => {
|
|
||||||
console.log('setCanvasPan被调用:', pan);
|
|
||||||
canvasPanState = pan;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 模拟useEffect行为
|
|
||||||
console.log('\n1. 测试图像加载useEffect...');
|
|
||||||
|
|
||||||
// 模拟canvasImage变化
|
|
||||||
const testImageUrl = 'https://cdn.pandorastudio.cn/upload/886ab948b.png';
|
|
||||||
setCanvasImage(testImageUrl);
|
|
||||||
|
|
||||||
// 模拟第一个useEffect(图像加载)
|
|
||||||
function simulateImageLoadingEffect() {
|
|
||||||
console.log('执行图像加载useEffect...');
|
|
||||||
|
|
||||||
if (canvasImageState) {
|
|
||||||
console.log('开始加载图像:', canvasImageState);
|
|
||||||
|
|
||||||
// 模拟图像加载完成
|
|
||||||
const mockImage = {
|
|
||||||
width: 1024,
|
|
||||||
height: 1024,
|
|
||||||
src: canvasImageState
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('图像加载完成,尺寸:', mockImage.width, 'x', mockImage.height);
|
|
||||||
setImage(mockImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
simulateImageLoadingEffect();
|
|
||||||
|
|
||||||
console.log('\n2. 测试画布适应useEffect...');
|
|
||||||
|
|
||||||
// 模拟第二个useEffect(画布适应)
|
|
||||||
function simulateCanvasAdaptEffect() {
|
|
||||||
console.log('执行画布适应useEffect...');
|
|
||||||
|
|
||||||
if (imageState && canvasImageState) {
|
|
||||||
console.log('图像已加载,开始计算最优缩放...');
|
|
||||||
|
|
||||||
// 模拟计算
|
|
||||||
const isMobile = window.innerWidth < 768;
|
|
||||||
const padding = isMobile ? 0.9 : 0.8;
|
|
||||||
|
|
||||||
const scaleX = (stageSizeState.width * padding) / imageState.width;
|
|
||||||
const scaleY = (stageSizeState.height * padding) / imageState.height;
|
|
||||||
|
|
||||||
const maxZoom = isMobile ? 0.3 : 0.8;
|
|
||||||
const optimalZoom = Math.min(scaleX, scaleY, maxZoom);
|
|
||||||
|
|
||||||
// 检查是否需要更新缩放
|
|
||||||
if (Math.abs(canvasZoomState - optimalZoom) > 0.01) {
|
|
||||||
console.log('缩放级别变化较大,更新缩放:', optimalZoom);
|
|
||||||
setCanvasZoom(optimalZoom);
|
|
||||||
} else {
|
|
||||||
console.log('缩放级别变化较小,跳过更新');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 居中图像
|
|
||||||
setCanvasPan({ x: 0, y: 0 });
|
|
||||||
console.log('图像居中完成');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
simulateCanvasAdaptEffect();
|
|
||||||
|
|
||||||
console.log('\n3. 测试避免无限循环...');
|
|
||||||
|
|
||||||
// 模拟多次执行useEffect
|
|
||||||
console.log('模拟多次执行useEffect...');
|
|
||||||
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
console.log(`\n第${i + 1}次执行:`);
|
|
||||||
|
|
||||||
// 执行画布适应effect
|
|
||||||
const oldZoom = canvasZoomState;
|
|
||||||
simulateCanvasAdaptEffect();
|
|
||||||
|
|
||||||
if (oldZoom === canvasZoomState) {
|
|
||||||
console.log('缩放级别未变化,避免了不必要的重渲染');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('\n4. 测试新图像加载...');
|
|
||||||
|
|
||||||
// 模拟加载新图像
|
|
||||||
const newImageUrl = 'https://cdn.pandorastudio.cn/upload/new-image.png';
|
|
||||||
console.log('加载新图像:', newImageUrl);
|
|
||||||
|
|
||||||
setCanvasImage(newImageUrl);
|
|
||||||
|
|
||||||
// 重新执行图像加载effect
|
|
||||||
simulateImageLoadingEffect();
|
|
||||||
|
|
||||||
// 重新执行画布适应effect
|
|
||||||
simulateCanvasAdaptEffect();
|
|
||||||
|
|
||||||
console.log('\n=== 测试完成 ===');
|
|
||||||
console.log('\n修复效果验证:');
|
|
||||||
console.log('✓ 图像加载和画布适应逻辑已分离');
|
|
||||||
console.log('✓ 避免了setCanvasZoom引起的无限循环');
|
|
||||||
console.log('✓ 通过缩放级别差异检查避免了不必要的更新');
|
|
||||||
console.log('✓ 新图像加载时能正确适应画布');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 运行测试
|
|
||||||
testFixEffect();
|
|
||||||
@@ -1178,75 +1178,7 @@ export const HistoryPanel: React.FC = () => {
|
|||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 操作 */}
|
|
||||||
<div className="space-y-2 flex-shrink-0 pt-2 border-t border-gray-100">
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
className="w-full h-9 text-sm card"
|
|
||||||
onClick={() => {
|
|
||||||
// 查找当前显示的图像(生成记录或编辑记录)
|
|
||||||
let imageUrl: string | null = null;
|
|
||||||
|
|
||||||
if (selectedGenerationId) {
|
|
||||||
const { canvasImage } = useAppStore.getState();
|
|
||||||
imageUrl = canvasImage;
|
|
||||||
} else {
|
|
||||||
// 如果没有选择生成记录,尝试获取当前画布图像
|
|
||||||
const { canvasImage } = useAppStore.getState();
|
|
||||||
imageUrl = canvasImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imageUrl) {
|
|
||||||
// 处理数据URL和常规URL
|
|
||||||
if (imageUrl.startsWith('data:') || imageUrl.startsWith('blob:')) {
|
|
||||||
// 对于Blob URL,我们需要获取实际的Blob数据
|
|
||||||
if (imageUrl.startsWith('blob:')) {
|
|
||||||
// 从AppStore获取Blob
|
|
||||||
const blob = useAppStore.getState().getBlob(imageUrl);
|
|
||||||
if (blob) {
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = url;
|
|
||||||
link.download = `nano-banana-${Date.now()}.png`;
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对于数据URL,直接下载
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = imageUrl;
|
|
||||||
link.download = `nano-banana-${Date.now()}.png`;
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
} else {
|
|
||||||
// 对于外部URL,我们需要获取并转换为blob
|
|
||||||
fetch(imageUrl)
|
|
||||||
.then(response => response.blob())
|
|
||||||
.then(blob => {
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = url;
|
|
||||||
link.download = `nano-banana-${Date.now()}.png`;
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
disabled={!selectedGenerationId && !useAppStore.getState().canvasImage}
|
|
||||||
>
|
|
||||||
<Download className="h-4 w-4 mr-2" />
|
|
||||||
下载图像
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 图像预览模态框 */}
|
{/* 图像预览模态框 */}
|
||||||
<ImagePreviewModal
|
<ImagePreviewModal
|
||||||
|
|||||||
@@ -318,14 +318,142 @@ export const ImageCanvas: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDownload = () => {
|
const handleDownload = () => {
|
||||||
if (canvasImage) {
|
// 直接下载当前画布内容
|
||||||
if (canvasImage.startsWith('data:')) {
|
const stage = stageRef.current;
|
||||||
|
if (stage) {
|
||||||
|
try {
|
||||||
|
// 使用Konva的toDataURL方法获取画布内容
|
||||||
|
const dataURL = stage.toDataURL();
|
||||||
|
|
||||||
|
// 创建下载链接
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = canvasImage;
|
link.href = dataURL;
|
||||||
link.download = `nano-banana-${Date.now()}.png`;
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
console.log('画布内容下载成功');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('下载画布内容时出错:', error);
|
||||||
|
|
||||||
|
// 如果Konva下载失败,回退到下载原始图像
|
||||||
|
if (canvasImage) {
|
||||||
|
// 处理不同类型的URL
|
||||||
|
if (canvasImage.startsWith('data:')) {
|
||||||
|
// base64格式
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = canvasImage;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
} else if (canvasImage.startsWith('blob:')) {
|
||||||
|
// Blob URL格式
|
||||||
|
fetch(canvasImage)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
// 清理创建的URL
|
||||||
|
setTimeout(() => URL.revokeObjectURL(url), 100);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('下载Blob图像时出错:', error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 普通URL格式
|
||||||
|
fetch(canvasImage)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
// 清理创建的URL
|
||||||
|
setTimeout(() => URL.revokeObjectURL(url), 100);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('下载图像时出错:', error);
|
||||||
|
// 如果fetch失败,尝试直接下载
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = canvasImage;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
link.target = '_blank';
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('Stage未初始化,无法下载画布内容');
|
||||||
|
|
||||||
|
// 回退到下载原始图像
|
||||||
|
if (canvasImage) {
|
||||||
|
// 处理不同类型的URL
|
||||||
|
if (canvasImage.startsWith('data:')) {
|
||||||
|
// base64格式
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = canvasImage;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
} else if (canvasImage.startsWith('blob:')) {
|
||||||
|
// Blob URL格式
|
||||||
|
fetch(canvasImage)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
// 清理创建的URL
|
||||||
|
setTimeout(() => URL.revokeObjectURL(url), 100);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('下载Blob图像时出错:', error);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 普通URL格式
|
||||||
|
fetch(canvasImage)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
// 清理创建的URL
|
||||||
|
setTimeout(() => URL.revokeObjectURL(url), 100);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('下载图像时出错:', error);
|
||||||
|
// 如果fetch失败,尝试直接下载
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = canvasImage;
|
||||||
|
link.download = `nano-banana-${Date.now()}.png`;
|
||||||
|
link.target = '_blank';
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user