新增放大镜工具及相关状态管理,优化手动上色模式下的用户交互体验,提升界面友好性。

This commit is contained in:
zihanjian
2025-06-06 14:41:29 +08:00
parent d420299dd2
commit fe6f3f1129
4 changed files with 661 additions and 1 deletions

View File

@@ -87,6 +87,8 @@ import GridTooltip from '../components/GridTooltip';
import CustomPaletteEditor from '../components/CustomPaletteEditor';
import FloatingColorPalette from '../components/FloatingColorPalette';
import FloatingToolbar from '../components/FloatingToolbar';
import MagnifierTool from '../components/MagnifierTool';
import MagnifierSelectionOverlay from '../components/MagnifierSelectionOverlay';
import { loadPaletteSelections, savePaletteSelections, presetToSelections, PaletteSelections } from '../utils/localStorageUtils';
import { TRANSPARENT_KEY, transparentColorData } from '../utils/pixelEditingUtils';
@@ -161,6 +163,70 @@ export default function Home() {
// 新增:悬浮调色盘状态
const [isFloatingPaletteOpen, setIsFloatingPaletteOpen] = useState<boolean>(true);
// 新增:放大镜状态
const [isMagnifierActive, setIsMagnifierActive] = useState<boolean>(false);
const [magnifierSelectionArea, setMagnifierSelectionArea] = useState<{
startRow: number;
startCol: number;
endRow: number;
endCol: number;
} | null>(null);
// 放大镜切换处理函数
const handleToggleMagnifier = () => {
setIsMagnifierActive(!isMagnifierActive);
};
// 放大镜像素编辑处理函数
const handleMagnifierPixelEdit = (row: number, col: number, colorData: { key: string; color: string }) => {
if (!mappedPixelData) return;
// 创建新的像素数据
const newMappedPixelData = mappedPixelData.map((rowData, r) =>
rowData.map((pixel, c) => {
if (r === row && c === col) {
return {
key: colorData.key,
color: colorData.color
} as MappedPixel;
}
return pixel;
})
);
setMappedPixelData(newMappedPixelData);
// 更新颜色统计
if (colorCounts) {
const newColorCounts = { ...colorCounts };
// 减少原颜色的计数
const oldPixel = mappedPixelData[row][col];
if (newColorCounts[oldPixel.key]) {
newColorCounts[oldPixel.key].count--;
if (newColorCounts[oldPixel.key].count === 0) {
delete newColorCounts[oldPixel.key];
}
}
// 增加新颜色的计数
if (newColorCounts[colorData.key]) {
newColorCounts[colorData.key].count++;
} else {
newColorCounts[colorData.key] = {
count: 1,
color: colorData.color
};
}
setColorCounts(newColorCounts);
// 更新总计数
const newTotal = Object.values(newColorCounts).reduce((sum, item) => sum + item.count, 0);
setTotalBeadCount(newTotal);
}
};
const originalCanvasRef = useRef<HTMLCanvasElement>(null);
const pixelatedCanvasRef = useRef<HTMLCanvasElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
@@ -2074,7 +2140,10 @@ export default function Home() {
step: 'select-source'
});
setHighlightColorKey(null);
setIsMagnifierActive(false);
}}
onToggleMagnifier={handleToggleMagnifier}
isMagnifierActive={isMagnifierActive}
/>
{/* 悬浮调色盘 */}
@@ -2098,6 +2167,33 @@ export default function Home() {
/>
)}
{/* 放大镜工具 */}
{isManualColoringMode && (
<>
<MagnifierTool
isActive={isMagnifierActive}
onToggle={handleToggleMagnifier}
mappedPixelData={mappedPixelData}
gridDimensions={gridDimensions}
selectedColor={selectedColor}
selectedColorSystem={selectedColorSystem}
onPixelEdit={handleMagnifierPixelEdit}
cellSize={gridDimensions ? Math.min(6, Math.max(4, 500 / Math.max(gridDimensions.N, gridDimensions.M))) : 6}
selectionArea={magnifierSelectionArea}
onClearSelection={() => setMagnifierSelectionArea(null)}
/>
{/* 放大镜选择覆盖层 */}
<MagnifierSelectionOverlay
isActive={isMagnifierActive && !magnifierSelectionArea}
canvasRef={pixelatedCanvasRef}
gridDimensions={gridDimensions}
cellSize={gridDimensions ? Math.min(6, Math.max(4, 500 / Math.max(gridDimensions.N, gridDimensions.M))) : 6}
onSelectionComplete={setMagnifierSelectionArea}
/>
</>
)}
{/* Apply dark mode styles to the Footer */}
<footer className="w-full md:max-w-4xl mt-10 mb-6 py-6 text-center text-xs sm:text-sm text-gray-500 dark:text-gray-400 border-t border-gray-200 dark:border-gray-700 bg-gradient-to-b from-white to-gray-50 dark:from-gray-900 dark:to-gray-800/50 rounded-lg shadow-inner">

View File

@@ -7,13 +7,17 @@ interface FloatingToolbarProps {
isPaletteOpen: boolean;
onTogglePalette: () => void;
onExitManualMode: () => void;
onToggleMagnifier: () => void;
isMagnifierActive: boolean;
}
const FloatingToolbar: React.FC<FloatingToolbarProps> = ({
isManualColoringMode,
isPaletteOpen,
onTogglePalette,
onExitManualMode
onExitManualMode,
onToggleMagnifier,
isMagnifierActive
}) => {
if (!isManualColoringMode) return null;
@@ -34,6 +38,21 @@ const FloatingToolbar: React.FC<FloatingToolbarProps> = ({
</svg>
</button>
{/* 放大镜按钮 */}
<button
onClick={onToggleMagnifier}
className={`w-12 h-12 rounded-full shadow-lg transition-all duration-200 flex items-center justify-center ${
isMagnifierActive
? 'bg-green-500 text-white hover:bg-green-600'
: 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 border border-gray-200 dark:border-gray-600'
}`}
title={isMagnifierActive ? '关闭放大镜' : '打开放大镜'}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</button>
{/* 退出手动编辑模式按钮 */}
<button
onClick={onExitManualMode}

View File

@@ -0,0 +1,264 @@
import React, { useRef, useState, useCallback, useEffect } from 'react';
interface SelectionArea {
startRow: number;
startCol: number;
endRow: number;
endCol: number;
}
interface MagnifierSelectionOverlayProps {
isActive: boolean;
canvasRef: React.RefObject<HTMLCanvasElement | null>;
gridDimensions: { N: number; M: number } | null;
cellSize: number;
onSelectionComplete: (area: SelectionArea) => void;
}
const MagnifierSelectionOverlay: React.FC<MagnifierSelectionOverlayProps> = ({
isActive,
canvasRef,
gridDimensions,
onSelectionComplete
}) => {
const [isSelecting, setIsSelecting] = useState(false);
const [selectionStart, setSelectionStart] = useState<{ x: number; y: number } | null>(null);
const [selectionEnd, setSelectionEnd] = useState<{ x: number; y: number } | null>(null);
const overlayRef = useRef<HTMLDivElement>(null);
// 滚动禁用状态
const scrollDisabledRef = useRef<boolean>(false);
const savedScrollPositionRef = useRef<number>(0);
// 禁用/启用页面滚动
const preventScrolling = useCallback((e: Event) => {
e.preventDefault();
e.stopPropagation();
}, []);
const disableScroll = useCallback(() => {
if (scrollDisabledRef.current) return; // 避免重复禁用
// 保存当前滚动位置
savedScrollPositionRef.current = window.scrollY;
// 设置CSS样式
document.body.style.overflow = 'hidden';
document.documentElement.style.overflow = 'hidden';
// 阻止滚动事件但不使用fixed定位避免跳转问题
document.addEventListener('wheel', preventScrolling, { passive: false });
document.addEventListener('touchmove', preventScrolling, { passive: false });
scrollDisabledRef.current = true;
}, [preventScrolling]);
const enableScroll = useCallback(() => {
if (!scrollDisabledRef.current) return; // 避免重复启用
// 恢复CSS样式
document.body.style.overflow = '';
document.documentElement.style.overflow = '';
// 移除事件监听器
document.removeEventListener('wheel', preventScrolling);
document.removeEventListener('touchmove', preventScrolling);
scrollDisabledRef.current = false;
// 不再强制恢复滚动位置,让浏览器保持自然状态
}, [preventScrolling]);
// 获取画布相对坐标
const getCanvasCoordinates = useCallback((clientX: number, clientY: number) => {
if (!canvasRef.current) return null;
const rect = canvasRef.current.getBoundingClientRect();
return {
x: clientX - rect.left,
y: clientY - rect.top
};
}, [canvasRef]);
// 将像素坐标转换为网格坐标
const pixelToGrid = useCallback((x: number, y: number) => {
if (!gridDimensions || !canvasRef.current) return null;
const canvasWidth = canvasRef.current.width;
const canvasHeight = canvasRef.current.height;
const cellWidth = canvasWidth / gridDimensions.N;
const cellHeight = canvasHeight / gridDimensions.M;
const col = Math.floor(x / cellWidth);
const row = Math.floor(y / cellHeight);
return {
row: Math.max(0, Math.min(gridDimensions.M - 1, row)),
col: Math.max(0, Math.min(gridDimensions.N - 1, col))
};
}, [gridDimensions, canvasRef]);
// 处理鼠标事件
const handleMouseDown = useCallback((event: React.MouseEvent) => {
if (!isActive) return;
const coords = getCanvasCoordinates(event.clientX, event.clientY);
if (!coords) return;
setIsSelecting(true);
setSelectionStart(coords);
setSelectionEnd(coords);
disableScroll(); // 禁用滚动
event.preventDefault();
}, [isActive, getCanvasCoordinates, disableScroll]);
const handleMouseMove = useCallback((event: MouseEvent) => {
if (!isSelecting || !selectionStart) return;
const coords = getCanvasCoordinates(event.clientX, event.clientY);
if (!coords) return;
setSelectionEnd(coords);
}, [isSelecting, selectionStart, getCanvasCoordinates]);
const handleMouseUp = useCallback(() => {
if (!isSelecting || !selectionStart || !selectionEnd) {
enableScroll(); // 确保恢复滚动
return;
}
const startGrid = pixelToGrid(selectionStart.x, selectionStart.y);
const endGrid = pixelToGrid(selectionEnd.x, selectionEnd.y);
if (startGrid && endGrid) {
const area: SelectionArea = {
startRow: Math.min(startGrid.row, endGrid.row),
startCol: Math.min(startGrid.col, endGrid.col),
endRow: Math.max(startGrid.row, endGrid.row),
endCol: Math.max(startGrid.col, endGrid.col)
};
onSelectionComplete(area);
}
setIsSelecting(false);
setSelectionStart(null);
setSelectionEnd(null);
enableScroll(); // 恢复滚动
}, [isSelecting, selectionStart, selectionEnd, pixelToGrid, onSelectionComplete, enableScroll]);
// 处理触摸事件
const handleTouchStart = useCallback((event: React.TouchEvent) => {
if (!isActive) return;
const touch = event.touches[0];
const coords = getCanvasCoordinates(touch.clientX, touch.clientY);
if (!coords) return;
setIsSelecting(true);
setSelectionStart(coords);
setSelectionEnd(coords);
disableScroll(); // 禁用滚动
event.preventDefault();
}, [isActive, getCanvasCoordinates, disableScroll]);
const handleTouchMove = useCallback((event: TouchEvent) => {
if (!isSelecting || !selectionStart) return;
const touch = event.touches[0];
const coords = getCanvasCoordinates(touch.clientX, touch.clientY);
if (!coords) return;
setSelectionEnd(coords);
event.preventDefault();
}, [isSelecting, selectionStart, getCanvasCoordinates]);
const handleTouchEnd = useCallback(() => {
handleMouseUp();
}, [handleMouseUp]);
// 事件监听器
useEffect(() => {
if (isSelecting) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
document.addEventListener('touchmove', handleTouchMove);
document.addEventListener('touchend', handleTouchEnd);
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
document.removeEventListener('touchmove', handleTouchMove);
document.removeEventListener('touchend', handleTouchEnd);
enableScroll(); // 清理时恢复滚动
};
}
}, [isSelecting, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd, enableScroll]);
// 组件卸载时恢复滚动
useEffect(() => {
return () => {
enableScroll();
};
}, [enableScroll]);
// 当组件变为非活跃状态时恢复滚动
useEffect(() => {
if (!isActive) {
enableScroll();
setIsSelecting(false);
setSelectionStart(null);
setSelectionEnd(null);
}
}, [isActive, enableScroll]);
// 计算选择框的样式
const getSelectionStyle = useCallback(() => {
if (!selectionStart || !selectionEnd || !canvasRef.current) return {};
const rect = canvasRef.current.getBoundingClientRect();
const minX = Math.min(selectionStart.x, selectionEnd.x);
const minY = Math.min(selectionStart.y, selectionEnd.y);
const maxX = Math.max(selectionStart.x, selectionEnd.x);
const maxY = Math.max(selectionStart.y, selectionEnd.y);
return {
left: rect.left + minX,
top: rect.top + minY,
width: maxX - minX,
height: maxY - minY,
position: 'fixed' as const,
border: '2px solid #10b981',
backgroundColor: 'rgba(16, 185, 129, 0.1)',
pointerEvents: 'none' as const,
zIndex: 1000
};
}, [selectionStart, selectionEnd, canvasRef]);
if (!isActive) return null;
return (
<>
{/* 覆盖层 */}
<div
ref={overlayRef}
className="fixed inset-0 z-50"
style={{
cursor: 'crosshair',
pointerEvents: isActive ? 'auto' : 'none'
}}
onMouseDown={handleMouseDown}
onTouchStart={handleTouchStart}
onWheel={(e) => e.preventDefault()}
onTouchMove={(e) => e.preventDefault()}
onScroll={(e) => e.preventDefault()}
/>
{/* 选择框 */}
{isSelecting && selectionStart && selectionEnd && (
<div style={getSelectionStyle()} />
)}
</>
);
};
export default MagnifierSelectionOverlay;

View File

@@ -0,0 +1,281 @@
import React, { useState, useRef, useEffect, useCallback } from 'react';
import { MappedPixel } from '../utils/pixelation';
import { getColorKeyByHex, ColorSystem } from '../utils/colorSystemUtils';
interface MagnifierToolProps {
isActive: boolean;
onToggle: () => void;
mappedPixelData: MappedPixel[][] | null;
gridDimensions: { N: number; M: number } | null;
selectedColor: MappedPixel | null;
selectedColorSystem: ColorSystem;
onPixelEdit: (row: number, col: number, colorData: { key: string; color: string }) => void;
cellSize: number;
selectionArea: SelectionArea | null;
onClearSelection: () => void;
}
interface SelectionArea {
startRow: number;
startCol: number;
endRow: number;
endCol: number;
}
const MagnifierTool: React.FC<MagnifierToolProps> = ({
isActive,
onToggle,
mappedPixelData,
selectedColor,
selectedColorSystem,
onPixelEdit,
selectionArea,
onClearSelection
}) => {
const [magnifierPosition, setMagnifierPosition] = useState<{ x: number; y: number }>({ x: 50, y: 50 });
const [isDragging, setIsDragging] = useState<boolean>(false);
const magnifierRef = useRef<HTMLDivElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
// 计算选择区域的尺寸
const getSelectionDimensions = useCallback(() => {
if (!selectionArea) return { width: 0, height: 0 };
return {
width: Math.abs(selectionArea.endCol - selectionArea.startCol) + 1,
height: Math.abs(selectionArea.endRow - selectionArea.startRow) + 1
};
}, [selectionArea]);
// 渲染放大视图
const renderMagnifiedView = useCallback(() => {
if (!selectionArea || !mappedPixelData || !canvasRef.current) return;
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
if (!ctx) return;
const { width, height } = getSelectionDimensions();
const magnifiedCellSize = 20; // 放大后每个像素的大小
// 设置画布的实际尺寸
canvas.width = width * magnifiedCellSize;
canvas.height = height * magnifiedCellSize;
// 设置画布的显示尺寸,确保不会太大
const maxDisplayWidth = 400;
const maxDisplayHeight = 400;
const displayWidth = Math.min(canvas.width, maxDisplayWidth);
const displayHeight = Math.min(canvas.height, maxDisplayHeight);
canvas.style.width = `${displayWidth}px`;
canvas.style.height = `${displayHeight}px`;
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 渲染放大的像素
const startRow = Math.min(selectionArea.startRow, selectionArea.endRow);
const endRow = Math.max(selectionArea.startRow, selectionArea.endRow);
const startCol = Math.min(selectionArea.startCol, selectionArea.endCol);
const endCol = Math.max(selectionArea.startCol, selectionArea.endCol);
for (let row = startRow; row <= endRow; row++) {
for (let col = startCol; col <= endCol; col++) {
if (row >= 0 && row < mappedPixelData.length && col >= 0 && col < mappedPixelData[0].length) {
const pixel = mappedPixelData[row][col];
const canvasRow = row - startRow;
const canvasCol = col - startCol;
// 绘制像素
ctx.fillStyle = pixel.color;
ctx.fillRect(
canvasCol * magnifiedCellSize,
canvasRow * magnifiedCellSize,
magnifiedCellSize,
magnifiedCellSize
);
// 绘制网格线
ctx.strokeStyle = '#e0e0e0';
ctx.lineWidth = 1;
ctx.strokeRect(
canvasCol * magnifiedCellSize,
canvasRow * magnifiedCellSize,
magnifiedCellSize,
magnifiedCellSize
);
}
}
}
}, [selectionArea, mappedPixelData, getSelectionDimensions]);
// 处理放大视图点击
const handleMagnifiedClick = useCallback((event: React.MouseEvent<HTMLCanvasElement>) => {
if (!selectionArea || !mappedPixelData || !selectedColor || !canvasRef.current) return;
const canvas = canvasRef.current;
const rect = canvas.getBoundingClientRect();
// 获取点击在画布上的相对位置(考虑缩放)
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
const x = (event.clientX - rect.left) * scaleX;
const y = (event.clientY - rect.top) * scaleY;
const magnifiedCellSize = 20;
const clickedCol = Math.floor(x / magnifiedCellSize);
const clickedRow = Math.floor(y / magnifiedCellSize);
const startRow = Math.min(selectionArea.startRow, selectionArea.endRow);
const startCol = Math.min(selectionArea.startCol, selectionArea.endCol);
const actualRow = startRow + clickedRow;
const actualCol = startCol + clickedCol;
// 确保点击在有效范围内
if (actualRow >= 0 && actualRow < mappedPixelData.length &&
actualCol >= 0 && actualCol < mappedPixelData[0].length) {
onPixelEdit(actualRow, actualCol, selectedColor);
}
}, [selectionArea, mappedPixelData, selectedColor, onPixelEdit]);
// 处理拖拽移动
const handleTitleBarMouseDown = useCallback((event: React.MouseEvent) => {
// 只有点击在标题栏区域且不是按钮时才开始拖拽
const target = event.target as HTMLElement;
if (target.tagName === 'BUTTON' || target.closest('button')) {
return; // 点击按钮时不拖拽
}
setIsDragging(true);
event.preventDefault();
}, []);
const handleMouseMove = useCallback((event: MouseEvent) => {
if (isDragging && magnifierRef.current) {
const rect = magnifierRef.current.getBoundingClientRect();
const newX = Math.max(0, Math.min(window.innerWidth - rect.width, event.clientX - rect.width / 2));
const newY = Math.max(0, Math.min(window.innerHeight - rect.height, event.clientY - rect.height / 2));
setMagnifierPosition({ x: newX, y: newY });
}
}, [isDragging]);
const handleMouseUp = useCallback(() => {
setIsDragging(false);
}, []);
useEffect(() => {
if (isDragging) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
}
}, [isDragging, handleMouseMove, handleMouseUp]);
// 重新渲染放大视图
useEffect(() => {
renderMagnifiedView();
}, [renderMagnifiedView]);
if (!isActive) return null;
return (
<>
{/* 选择区域提示 */}
{!selectionArea && (
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 bg-blue-500 text-white px-4 py-2 rounded-lg shadow-lg z-50">
<div className="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<span></span>
</div>
</div>
)}
{/* 放大视图窗口 */}
{selectionArea && (
<div
ref={magnifierRef}
className="fixed bg-white dark:bg-gray-800 rounded-xl shadow-2xl border border-gray-200 dark:border-gray-600 z-50 select-none"
style={{
left: magnifierPosition.x,
top: magnifierPosition.y,
maxWidth: '500px',
maxHeight: '500px'
}}
>
{/* 标题栏 */}
<div
className="flex items-center justify-between p-3 bg-gradient-to-r from-green-500 to-teal-500 text-white rounded-t-xl cursor-move"
onMouseDown={handleTitleBarMouseDown}
>
<div className="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<span className="text-sm font-medium"> ({getSelectionDimensions().width}×{getSelectionDimensions().height})</span>
</div>
<div className="flex items-center gap-2">
{/* 重新选择按钮 */}
<button
onClick={onClearSelection}
className="p-1 hover:bg-white/20 rounded transition-colors"
title="重新选择区域"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
{/* 关闭按钮 */}
<button
onClick={onToggle}
className="p-1 hover:bg-white/20 rounded transition-colors"
title="关闭放大镜"
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* 放大视图内容 */}
<div className="p-3">
<div className="border border-gray-300 dark:border-gray-600 rounded-lg overflow-hidden">
<canvas
ref={canvasRef}
onClick={handleMagnifiedClick}
className="cursor-crosshair block"
/>
</div>
{/* 当前选中颜色信息 */}
{selectedColor && (
<div className="mt-2 p-2 bg-gray-100 dark:bg-gray-700 rounded-lg">
<div className="flex items-center gap-2 text-xs">
<div
className="w-4 h-4 rounded border border-gray-300 dark:border-gray-500"
style={{ backgroundColor: selectedColor.color }}
></div>
<span className="text-gray-700 dark:text-gray-300">
: {getColorKeyByHex(selectedColor.color, selectedColorSystem)}
</span>
</div>
</div>
)}
</div>
</div>
)}
</>
);
};
export default MagnifierTool;