chore(build): refactor codebase for production
This commit is contained in:
@ -1,19 +1,19 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState } from "react";
|
||||
|
||||
const LinearTransformationWidget: React.FC = () => {
|
||||
const [h, setH] = useState(0); // Horizontal shift (x - h)
|
||||
const [k, setK] = useState(0); // Vertical shift + k
|
||||
const [reflectX, setReflectX] = useState(false); // -f(x)
|
||||
const [stretch, setStretch] = useState(1); // a * f(x)
|
||||
const stretch = 1; // a * f(x)
|
||||
|
||||
// Base function f(x) = 0.5x
|
||||
// Transformed g(x) = a * f(x - h) + k
|
||||
// Transformed g(x) = a * f(x - h) + k
|
||||
// g(x) = a * (0.5 * (x - h)) + k
|
||||
|
||||
// Actually, let's use f(x) = x for simplicity, or 0.5x to show slope changes easier?
|
||||
|
||||
// Actually, let's use f(x) = x for simplicity, or 0.5x to show slope changes easier?
|
||||
// PDF examples use general f(x). Let's use f(x) = x as base.
|
||||
// g(x) = stretch * (x - h) + k. If reflectX is true, stretch becomes -stretch.
|
||||
|
||||
|
||||
const effectiveStretch = reflectX ? -stretch : stretch;
|
||||
|
||||
const range = 10;
|
||||
@ -21,100 +21,158 @@ const LinearTransformationWidget: React.FC = () => {
|
||||
const size = 300;
|
||||
const center = size / 2;
|
||||
|
||||
const toPx = (v: number, isY = false) => isY ? center - v * scale : center + v * scale;
|
||||
const toPx = (v: number, isY = false) =>
|
||||
isY ? center - v * scale : center + v * scale;
|
||||
|
||||
// Base: y = 0.5x (to make it distinct from diagonals)
|
||||
const getBasePath = () => {
|
||||
const m = 0.5;
|
||||
const x1 = -range, x2 = range;
|
||||
const y1 = m * x1;
|
||||
const y2 = m * x2;
|
||||
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
|
||||
const m = 0.5;
|
||||
const x1 = -range,
|
||||
x2 = range;
|
||||
const y1 = m * x1;
|
||||
const y2 = m * x2;
|
||||
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
|
||||
};
|
||||
|
||||
const getTransformedPath = () => {
|
||||
// f(x) = 0.5x
|
||||
// g(x) = effectiveStretch * (0.5 * (x - h)) + k
|
||||
const x1 = -range, x2 = range;
|
||||
const y1 = effectiveStretch * (0.5 * (x1 - h)) + k;
|
||||
const y2 = effectiveStretch * (0.5 * (x2 - h)) + k;
|
||||
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
|
||||
// f(x) = 0.5x
|
||||
// g(x) = effectiveStretch * (0.5 * (x - h)) + k
|
||||
const x1 = -range,
|
||||
x2 = range;
|
||||
const y1 = effectiveStretch * (0.5 * (x1 - h)) + k;
|
||||
const y2 = effectiveStretch * (0.5 * (x2 - h)) + k;
|
||||
return `M ${toPx(x1)} ${toPx(y1, true)} L ${toPx(x2)} ${toPx(y2, true)}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
|
||||
<div className="flex flex-col md:flex-row gap-8">
|
||||
<div className="w-full md:w-1/3 space-y-6">
|
||||
<div className="p-4 bg-slate-50 border border-slate-200 rounded-xl font-mono text-sm">
|
||||
<p className="text-slate-400 mb-2">Base: <span className="text-slate-600 font-bold">f(x) = 0.5x</span></p>
|
||||
<p className="text-indigo-900 font-bold text-lg">
|
||||
g(x) = {reflectX ? '-' : ''}{stretch !== 1 ? stretch : ''}f(x {h > 0 ? '-' : '+'} {Math.abs(h)}) {k >= 0 ? '+' : '-'} {Math.abs(k)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full md:w-1/3 space-y-6">
|
||||
<div className="p-4 bg-slate-50 border border-slate-200 rounded-xl font-mono text-sm">
|
||||
<p className="text-slate-400 mb-2">
|
||||
Base:{" "}
|
||||
<span className="text-slate-600 font-bold">f(x) = 0.5x</span>
|
||||
</p>
|
||||
<p className="text-indigo-900 font-bold text-lg">
|
||||
g(x) = {reflectX ? "-" : ""}
|
||||
{stretch !== 1 ? stretch : ""}f(x {h > 0 ? "-" : "+"}{" "}
|
||||
{Math.abs(h)}) {k >= 0 ? "+" : "-"} {Math.abs(k)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="text-xs font-bold text-indigo-600 uppercase flex justify-between">
|
||||
Horizontal Shift (h) <span>{h}</span>
|
||||
</label>
|
||||
<input
|
||||
type="range" min="-5" max="5" step="1"
|
||||
value={h} onChange={e => setH(parseInt(e.target.value))}
|
||||
className="w-full h-2 bg-indigo-100 rounded-lg appearance-none cursor-pointer accent-indigo-600 mt-1"
|
||||
/>
|
||||
<div className="flex justify-between text-[10px] text-slate-400">
|
||||
<span>Left (x+h)</span>
|
||||
<span>Right (x-h)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="text-xs font-bold text-indigo-600 uppercase flex justify-between">
|
||||
Horizontal Shift (h) <span>{h}</span>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="-5"
|
||||
max="5"
|
||||
step="1"
|
||||
value={h}
|
||||
onChange={(e) => setH(parseInt(e.target.value))}
|
||||
className="w-full h-2 bg-indigo-100 rounded-lg appearance-none cursor-pointer accent-indigo-600 mt-1"
|
||||
/>
|
||||
<div className="flex justify-between text-[10px] text-slate-400">
|
||||
<span>Left (x+h)</span>
|
||||
<span>Right (x-h)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-xs font-bold text-emerald-600 uppercase flex justify-between">
|
||||
Vertical Shift (k) <span>{k}</span>
|
||||
</label>
|
||||
<input
|
||||
type="range" min="-5" max="5" step="1"
|
||||
value={k} onChange={e => setK(parseInt(e.target.value))}
|
||||
className="w-full h-2 bg-emerald-100 rounded-lg appearance-none cursor-pointer accent-emerald-600 mt-1"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-bold text-emerald-600 uppercase flex justify-between">
|
||||
Vertical Shift (k) <span>{k}</span>
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="-5"
|
||||
max="5"
|
||||
step="1"
|
||||
value={k}
|
||||
onChange={(e) => setK(parseInt(e.target.value))}
|
||||
className="w-full h-2 bg-emerald-100 rounded-lg appearance-none cursor-pointer accent-emerald-600 mt-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4 pt-2">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-slate-700 cursor-pointer">
|
||||
<input type="checkbox" checked={reflectX} onChange={e => setReflectX(e.target.checked)} className="accent-rose-600 w-4 h-4"/>
|
||||
Reflect (-f(x))
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 pt-2">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-slate-700 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={reflectX}
|
||||
onChange={(e) => setReflectX(e.target.checked)}
|
||||
className="accent-rose-600 w-4 h-4"
|
||||
/>
|
||||
Reflect (-f(x))
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 flex justify-center">
|
||||
<div className="relative w-[300px] h-[300px] border border-slate-200 rounded-xl overflow-hidden bg-white">
|
||||
<svg width="300" height="300" viewBox="0 0 300 300">
|
||||
<defs>
|
||||
<pattern id="grid-t" width="20" height="20" patternUnits="userSpaceOnUse">
|
||||
<path d="M 20 0 L 0 0 0 20" fill="none" stroke="#f1f5f9" strokeWidth="1"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="url(#grid-t)" />
|
||||
|
||||
{/* Axes */}
|
||||
<line x1="0" y1={center} x2={size} y2={center} stroke="#cbd5e1" strokeWidth="2" />
|
||||
<line x1={center} y1="0" x2={center} y2={size} stroke="#cbd5e1" strokeWidth="2" />
|
||||
<div className="flex-1 flex justify-center">
|
||||
<div className="relative w-[300px] h-[300px] border border-slate-200 rounded-xl overflow-hidden bg-white">
|
||||
<svg width="300" height="300" viewBox="0 0 300 300">
|
||||
<defs>
|
||||
<pattern
|
||||
id="grid-t"
|
||||
width="20"
|
||||
height="20"
|
||||
patternUnits="userSpaceOnUse"
|
||||
>
|
||||
<path
|
||||
d="M 20 0 L 0 0 0 20"
|
||||
fill="none"
|
||||
stroke="#f1f5f9"
|
||||
strokeWidth="1"
|
||||
/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="url(#grid-t)" />
|
||||
|
||||
{/* Base Function (Ghost) */}
|
||||
<path d={getBasePath()} stroke="#94a3b8" strokeWidth="2" strokeDasharray="4,4" />
|
||||
<text x="260" y={toPx(0.5*8, true) - 5} className="text-xs fill-slate-400 font-bold">f(x)</text>
|
||||
{/* Axes */}
|
||||
<line
|
||||
x1="0"
|
||||
y1={center}
|
||||
x2={size}
|
||||
y2={center}
|
||||
stroke="#cbd5e1"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<line
|
||||
x1={center}
|
||||
y1="0"
|
||||
x2={center}
|
||||
y2={size}
|
||||
stroke="#cbd5e1"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
|
||||
{/* Transformed Function */}
|
||||
<path d={getTransformedPath()} stroke="#4f46e5" strokeWidth="3" />
|
||||
<text x="20" y="20" className="text-xs fill-indigo-600 font-bold">g(x)</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
{/* Base Function (Ghost) */}
|
||||
<path
|
||||
d={getBasePath()}
|
||||
stroke="#94a3b8"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="4,4"
|
||||
/>
|
||||
<text
|
||||
x="260"
|
||||
y={toPx(0.5 * 8, true) - 5}
|
||||
className="text-xs fill-slate-400 font-bold"
|
||||
>
|
||||
f(x)
|
||||
</text>
|
||||
|
||||
{/* Transformed Function */}
|
||||
<path d={getTransformedPath()} stroke="#4f46e5" strokeWidth="3" />
|
||||
<text x="20" y="20" className="text-xs fill-indigo-600 font-bold">
|
||||
g(x)
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LinearTransformationWidget;
|
||||
export default LinearTransformationWidget;
|
||||
|
||||
Reference in New Issue
Block a user