import React, { useRef, useEffect } from 'react'; import * as d3 from 'd3'; import { useStaticFontData } from '../../hooks/useStaticFontData'; import { useGlyphRendererV2 } from './hooks/useGlyphRendererV2'; import { useZoomV2 } from './hooks/useZoomV2'; import { calculateMappingDimensions } from './utils/mappingUtils'; import './FontMapV2.css'; /** * FontMapV2 - Clean implementation using DebugUMAP's proven rendering approach * Phase 1: Just the map with working rendering */ const FontMapV2 = ({ darkMode = false }) => { const svgRef = useRef(null); const { fonts, glyphPaths, loading, error } = useStaticFontData(); // Calculate mapped coordinates const mappedFonts = React.useMemo(() => { if (!fonts || fonts.length === 0) return []; const { mapX, mapY } = calculateMappingDimensions(fonts); return fonts.map(font => ({ ...font, x: mapX(font.x), y: mapY(font.y) })); }, [fonts]); // Initialize SVG and viewport group useEffect(() => { if (!svgRef.current) { console.log('FontMapV2: svgRef not ready'); return; } const svg = svgRef.current; svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); svg.style.backgroundColor = darkMode ? '#1a1a1a' : '#ffffff'; // Create viewport group if it doesn't exist const d3svg = d3.select(svg); if (d3svg.select('.viewport-group').empty()) { d3svg.append('g').attr('class', 'viewport-group'); console.log('✅ FontMapV2: Created viewport-group'); } else { console.log('FontMapV2: viewport-group already exists'); } }, [darkMode]); // Setup zoom FIRST (before rendering glyphs) useZoomV2(svgRef, darkMode); // Render glyphs AFTER zoom is set up useGlyphRendererV2({ svgRef, fonts: mappedFonts, glyphPaths, darkMode, baseGlyphSize: 0.2 // Small base size since we're using 80x80 viewBox }); if (loading) { return (
Loading FontMapV2...
); } if (error) { return (
Error: {error}
); } return (
FontMapV2 - Phase 1
{fonts.length} fonts loaded
{Object.keys(glyphPaths).length} glyph paths
); }; export default FontMapV2;