import React, { useState, useRef } from 'react'; const InequalityRegionWidget: React.FC = () => { // State for Inequalities: y > or < mx + b // isGreater: true for >=, false for <= const [ineq1, setIneq1] = useState({ m: 1, b: 1, isGreater: true }); const [ineq2, setIneq2] = useState({ m: -0.5, b: -2, isGreater: false }); const [testPoint, setTestPoint] = useState({ x: 0, y: 0 }); const isDragging = useRef(false); const svgRef = useRef(null); // Viewport const range = 10; const size = 300; const scale = size / (range * 2); const center = size / 2; // Helpers const toPx = (val: number, isY = false) => { return isY ? center - val * scale : center + val * scale; }; const fromPx = (px: number, isY = false) => { return isY ? (center - px) / scale : (px - center) / scale; }; // Generate polygon points for shading const getRegionPoints = (m: number, b: number, isGreater: boolean) => { const xMin = -range; const xMax = range; const yAtMin = m * xMin + b; const yAtMax = m * xMax + b; // y limit is the top (range) or bottom (-range) of the graph const limitY = isGreater ? range : -range; const p1 = { x: xMin, y: yAtMin }; const p2 = { x: xMax, y: yAtMax }; const p3 = { x: xMax, y: limitY }; const p4 = { x: xMin, y: limitY }; return `${toPx(p1.x)},${toPx(p1.y, true)} ${toPx(p2.x)},${toPx(p2.y, true)} ${toPx(p3.x)},${toPx(p3.y, true)} ${toPx(p4.x)},${toPx(p4.y, true)}`; }; const getLinePath = (m: number, b: number) => { const x1 = -range; const y1 = m * x1 + b; const x2 = range; const y2 = m * x2 + b; return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`; }; // Interaction const handleInteraction = (e: React.MouseEvent) => { if (!svgRef.current) return; const rect = svgRef.current.getBoundingClientRect(); const x = fromPx(e.clientX - rect.left); const y = fromPx(e.clientY - rect.top, true); // Clamp const cx = Math.max(-range, Math.min(range, x)); const cy = Math.max(-range, Math.min(range, y)); setTestPoint({ x: cx, y: cy }); }; // Logic Check const check1 = ineq1.isGreater ? testPoint.y >= ineq1.m * testPoint.x + ineq1.b : testPoint.y <= ineq1.m * testPoint.x + ineq1.b; const check2 = ineq2.isGreater ? testPoint.y >= ineq2.m * testPoint.x + ineq2.b : testPoint.y <= ineq2.m * testPoint.x + ineq2.b; const isSolution = check1 && check2; return (
{/* Controls */}
{/* Inequality 1 */}
Region 1 (Blue)
Slope{ineq1.m}
setIneq1({...ineq1, m: parseFloat(e.target.value)})} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600"/>
Y-Int{ineq1.b}
setIneq1({...ineq1, b: parseFloat(e.target.value)})} className="w-full h-1 bg-indigo-200 rounded accent-indigo-600"/>
{/* Inequality 2 */}
Region 2 (Red)
Slope{ineq2.m}
setIneq2({...ineq2, m: parseFloat(e.target.value)})} className="w-full h-1 bg-rose-200 rounded accent-rose-600"/>
Y-Int{ineq2.b}
setIneq2({...ineq2, b: parseFloat(e.target.value)})} className="w-full h-1 bg-rose-200 rounded accent-rose-600"/>
Test Point: ({testPoint.x.toFixed(1)}, {testPoint.y.toFixed(1)})
{isSolution ? "SOLUTION FOUND" : "NOT A SOLUTION"}
{/* Graph */}
{ isDragging.current = true; handleInteraction(e); }} onMouseMove={(e) => { if(isDragging.current) handleInteraction(e); }} onMouseUp={() => isDragging.current = false} onMouseLeave={() => isDragging.current = false} > {/* Axes */} {/* Region 1 */} {/* Region 2 */} {/* Test Point */}
); }; export default InequalityRegionWidget;