import { CopyOutlined, DownloadOutlined, PlayCircleOutlined, ReloadOutlined, ZoomInOutlined, ZoomOutOutlined, } from '@ant-design/icons'; import { Button, Modal, Slider, Space, Tabs } from 'antd'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { CodePreview } from './code-preview'; /** * SVG preview component is used to display SVG code and provide preview and download functionality * @param {Object} props The component props * @param {string} props.code SVG code content * @param {string} props.language Code language, default is svg */ const SvgPreview = ({ code, language = 'svg' }) => { const [isModalVisible, setIsModalVisible] = useState(false); const [isCopied, setIsCopied] = useState(false); const [zoom, setZoom] = useState(100); const { t } = useTranslation(); // Clean up SVG code (remove XML declaration, etc.) const cleanSvgCode = svgCode => { // Remove XML declaration let cleaned = svgCode.replace(/<\?xml[^>]*\?>/g, ''); // Fix incomplete SVG tags if (!cleaned.includes('${cleaned}`; } // Make sure there is a correct xmlns attribute if (!cleaned.includes('xmlns=') && cleaned.includes('')) { cleaned = `${cleaned}`; } return cleaned; }; // Get SVG content const getSvgContent = () => { // Create a regex to match the SVG tag const svgRegex = //im; const match = code.match(svgRegex); if (match) { // If a complete SVG tag is found, use only that part return cleanSvgCode(match[0]); } else { // Otherwise, try to clean up the whole code return cleanSvgCode(code); } }; const showModal = () => { setIsModalVisible(true); }; const handleCancel = () => { setIsModalVisible(false); // Reset zoom setZoom(100); }; const copyToClipboard = () => { navigator.clipboard.writeText(code).then(() => { setIsCopied(true); setTimeout(() => setIsCopied(false), 2000); }); }; // Download SVG file const downloadSVG = () => { // Create a Blob object const blob = new Blob([getSvgContent()], { type: 'image/svg+xml' }); // Create a URL object const url = URL.createObjectURL(blob); // Create an a tag const a = document.createElement('a'); a.href = url; a.download = 'image.svg'; // 文件名 // Add to body and trigger click document.body.appendChild(a); a.click(); // Clean up document.body.removeChild(a); URL.revokeObjectURL(url); }; // Download PNG file const downloadPNG = () => { // Create a canvas const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // Create an image element const img = new Image(); const svgBlob = new Blob([getSvgContent()], { type: 'image/svg+xml' }); const url = URL.createObjectURL(svgBlob); img.onload = () => { // Resize the canvas to match the SVG size canvas.width = img.width; canvas.height = img.height; // Draw the SVG to the canvas ctx.drawImage(img, 0, 0); // Try to convert to PNG and download try { const pngUrl = canvas.toDataURL('image/png'); const a = document.createElement('a'); a.href = pngUrl; a.download = 'image.png'; document.body.appendChild(a); a.click(); document.body.removeChild(a); } catch (e) { console.error('PNG export failed:', e); } // Clean up URL.revokeObjectURL(url); }; img.src = url; }; // Control zoom const handleZoomChange = value => { setZoom(value); }; const zoomIn = () => { setZoom(Math.min(zoom + 10, 200)); }; const zoomOut = () => { setZoom(Math.max(zoom - 10, 50)); }; const resetZoom = () => { setZoom(100); }; // Create tab items const getTabItems = () => { const items = [ { key: 'preview', label: t('code_preview'), children: (
), }, { key: 'code', label: t('code_preview_code'), children: (
), }, ]; return items; }; return (
{/* Code preview section */} {/* Operation button */}
{/* Preview modal */} } onClick={downloadSVG}> {t('code_preview_download')} SVG , , , ]} width={800} bodyStyle={{ padding: 0 }} >
); }; export default SvgPreview;