import React, { useState, useRef } from "react"; const SimilarityWidget: React.FC = () => { const [ratio, setRatio] = useState(0.5); // Position of D along AB (0 to 1) const isDragging = useRef(false); const svgRef = useRef(null); // Triangle Vertices const A = { x: 200, y: 50 }; const B = { x: 50, y: 300 }; const C = { x: 350, y: 300 }; // Calculate D and E based on ratio const D = { x: A.x + (B.x - A.x) * ratio, y: A.y + (B.y - A.y) * ratio, }; const E = { x: A.x + (C.x - A.x) * ratio, y: A.y + (C.y - A.y) * ratio, }; const handleInteraction = (clientY: number) => { if (!svgRef.current) return; const rect = svgRef.current.getBoundingClientRect(); const y = clientY - rect.top; // Clamp y between A.y and B.y const clampedY = Math.max(A.y, Math.min(B.y, y)); // Calculate new ratio const newRatio = (clampedY - A.y) / (B.y - A.y); setRatio(Math.max(0.1, Math.min(0.9, newRatio))); // clamp to avoid degenerate }; const handleMouseDown = (e: React.MouseEvent) => { isDragging.current = true; handleInteraction(e.clientY); }; const handleMouseMove = (e: React.MouseEvent) => { if (isDragging.current) { handleInteraction(e.clientY); } }; return (
(isDragging.current = false)} onMouseLeave={() => (isDragging.current = false)} > {/* Main Triangle */} {/* Filled Top Triangle (Similar) */} {/* Parallel Line DE */} {/* Labels */} A B C D E {/* Drag Handle */}

Triangle Proportionality

Drag the red line. Because DE || BC, the small triangle is similar to the large triangle.

Scale Factor

{ratio.toFixed(2)}

Corresponding Sides Ratio:

AD / AB
=
AE / AC
=
{ratio.toFixed(2)}

Area Ratio (k²):

Area(ADE)
/
Area(ABC)
=
{(ratio * ratio).toFixed(2)}
); }; export default SimilarityWidget;