index.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { useEffect, useRef, useState } from 'react'
  2. import { SVG } from '@svgdotjs/svg.js'
  3. import ImagePreview from '@/app/components/base/image-uploader/image-preview'
  4. export const SVGRenderer = ({ content }: { content: string }) => {
  5. const svgRef = useRef<HTMLDivElement>(null)
  6. const [imagePreview, setImagePreview] = useState('')
  7. const [windowSize, setWindowSize] = useState({
  8. width: typeof window !== 'undefined' ? window.innerWidth : 0,
  9. height: typeof window !== 'undefined' ? window.innerHeight : 0,
  10. })
  11. const svgToDataURL = (svgElement: Element): string => {
  12. const svgString = new XMLSerializer().serializeToString(svgElement)
  13. const base64String = Buffer.from(svgString).toString('base64')
  14. return `data:image/svg+xml;base64,${base64String}`
  15. }
  16. useEffect(() => {
  17. const handleResize = () => {
  18. setWindowSize({ width: window.innerWidth, height: window.innerHeight })
  19. }
  20. window.addEventListener('resize', handleResize)
  21. return () => window.removeEventListener('resize', handleResize)
  22. }, [])
  23. useEffect(() => {
  24. if (svgRef.current) {
  25. try {
  26. svgRef.current.innerHTML = ''
  27. const draw = SVG().addTo(svgRef.current).size('100%', '100%')
  28. const parser = new DOMParser()
  29. const svgDoc = parser.parseFromString(content, 'image/svg+xml')
  30. const svgElement = svgDoc.documentElement
  31. if (!(svgElement instanceof SVGElement))
  32. throw new Error('Invalid SVG content')
  33. const originalWidth = parseInt(svgElement.getAttribute('width') || '400', 10)
  34. const originalHeight = parseInt(svgElement.getAttribute('height') || '600', 10)
  35. const scale = Math.min(windowSize.width / originalWidth, windowSize.height / originalHeight, 1)
  36. const scaledWidth = originalWidth * scale
  37. const scaledHeight = originalHeight * scale
  38. draw.size(scaledWidth, scaledHeight)
  39. const rootElement = draw.svg(content)
  40. rootElement.scale(scale)
  41. rootElement.click(() => {
  42. setImagePreview(svgToDataURL(svgElement as Element))
  43. })
  44. }
  45. catch (error) {
  46. if (svgRef.current)
  47. svgRef.current.innerHTML = 'Error rendering SVG. Wait for the image content to complete.'
  48. }
  49. }
  50. }, [content, windowSize])
  51. return (
  52. <>
  53. <div ref={svgRef} style={{
  54. width: '100%',
  55. height: '100%',
  56. minHeight: '300px',
  57. maxHeight: '80vh',
  58. display: 'flex',
  59. justifyContent: 'center',
  60. alignItems: 'center',
  61. cursor: 'pointer',
  62. }} />
  63. {imagePreview && (<ImagePreview url={imagePreview} title='Preview' onCancel={() => setImagePreview('')} />)}
  64. </>
  65. )
  66. }
  67. export default SVGRenderer