import React, { useState } from 'react'; type Relationship = 'none' | 'vertical' | 'linear' | 'corresponding' | 'alt-interior' | 'same-side'; const InteractiveTransversal: React.FC = () => { const [activeRel, setActiveRel] = useState('same-side'); // SVG Config const width = 500; const height = 300; const line1Y = 100; const line2Y = 200; // Transversal passes through (200, 100) and (300, 200) // Slope is 1 (45 degrees down-right) const intersection1 = { x: 200, y: 100 }; const intersection2 = { x: 300, y: 200 }; // Angle Definitions (SVG y-down coordinates) // 0 deg = Right, 90 deg = Down, 180 deg = Left, 270 deg = Up // Transversal vector is (1, 1), angle is 45 deg. // Opposite ray is 225 deg. const angles = [ // Intersection 1 (Top) { id: 1, cx: intersection1.x, cy: intersection1.y, start: 180, end: 225, labelPos: 202.5, quadrant: 'TL' }, // Top-Left (Acute) { id: 2, cx: intersection1.x, cy: intersection1.y, start: 225, end: 360, labelPos: 292.5, quadrant: 'TR' }, // Top-Right (Obtuse) { id: 3, cx: intersection1.x, cy: intersection1.y, start: 0, end: 45, labelPos: 22.5, quadrant: 'BR' }, // Bottom-Right (Acute) { id: 4, cx: intersection1.x, cy: intersection1.y, start: 45, end: 180, labelPos: 112.5, quadrant: 'BL' }, // Bottom-Left (Obtuse) // Intersection 2 (Bottom) { id: 5, cx: intersection2.x, cy: intersection2.y, start: 180, end: 225, labelPos: 202.5, quadrant: 'TL' }, { id: 6, cx: intersection2.x, cy: intersection2.y, start: 225, end: 360, labelPos: 292.5, quadrant: 'TR' }, { id: 7, cx: intersection2.x, cy: intersection2.y, start: 0, end: 45, labelPos: 22.5, quadrant: 'BR' }, { id: 8, cx: intersection2.x, cy: intersection2.y, start: 45, end: 180, labelPos: 112.5, quadrant: 'BL' }, ]; const getArcPath = (cx: number, cy: number, r: number, startDeg: number, endDeg: number) => { // Convert to radians const startRad = (startDeg * Math.PI) / 180; const endRad = (endDeg * Math.PI) / 180; const x1 = cx + r * Math.cos(startRad); const y1 = cy + r * Math.sin(startRad); const x2 = cx + r * Math.cos(endRad); const y2 = cy + r * Math.sin(endRad); const largeArc = (endDeg - startDeg) > 180 ? 1 : 0; return `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2} Z`; }; const getLabelPos = (cx: number, cy: number, r: number, angleDeg: number) => { const rad = (angleDeg * Math.PI) / 180; return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) }; }; const getStyles = (id: number) => { const base = { fill: 'transparent', stroke: 'transparent', label: 'text-slate-400' }; const highlightBlue = { fill: 'rgba(99, 102, 241, 0.3)', stroke: '#4f46e5', label: 'text-indigo-600 font-bold' }; const highlightPink = { fill: 'rgba(244, 63, 94, 0.3)', stroke: '#e11d48', label: 'text-rose-600 font-bold' }; switch (activeRel) { case 'vertical': // 1 & 3 are equal if ([1, 3].includes(id)) return highlightBlue; return base; case 'linear': // 1 & 2 are supplementary if (id === 1) return highlightBlue; if (id === 2) return highlightPink; return base; case 'corresponding': // 2 & 6 are equal if ([2, 6].includes(id)) return highlightBlue; return base; case 'alt-interior': // 4 & 6 are equal if ([4, 6].includes(id)) return highlightBlue; return base; case 'same-side': // 3 & 6 are supplementary if (id === 3) return highlightBlue; if (id === 6) return highlightPink; return base; default: return base; } }; const getDescription = () => { switch (activeRel) { case 'vertical': return "Vertical Angles are equal (e.g. ∠1 = ∠3)"; case 'linear': return "Linear Pairs sum to 180° (e.g. ∠1 + ∠2 = 180°)"; case 'corresponding': return "Corresponding Angles are equal (e.g. ∠2 = ∠6)"; case 'alt-interior': return "Alternate Interior Angles are equal (e.g. ∠4 = ∠6)"; case 'same-side': return "Same-Side Interior sum to 180° (e.g. ∠3 + ∠6 = 180°)"; default: return "Select a relationship to highlight"; } }; const buttons: { id: Relationship, label: string }[] = [ { id: 'vertical', label: 'Vertical Angles' }, { id: 'linear', label: 'Linear Pair' }, { id: 'corresponding', label: 'Corresponding' }, { id: 'alt-interior', label: 'Alt. Interior' }, { id: 'same-side', label: 'Same-Side Interior' }, ]; return (
{buttons.map(btn => ( ))}

{getDescription()}

{/* Parallel Lines */} {/* Transversal (infinite line simulation) */} {/* Angles */} {angles.map((angle) => { const styles = getStyles(angle.id); const r = 35; const labelPos = getLabelPos(angle.cx, angle.cy, r + 15, angle.labelPos); return ( {angle.id} ); })}
); }; export default InteractiveTransversal;