<!DOCTYPE html><html lang="de"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Zeichnen einer Parabel</title> <script src="https://cdn.tailwindcss.com"></script> <style> body { background-color: #f0f2f5; font-family: 'Inter', sans-serif; } canvas { background-color: #ffffff; cursor: crosshair; touch-action: none; } .glass-panel { background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.2); } .slider-thumb::-webkit-slider-thumb { appearance: none; width: 18px; height: 18px; background: #3b82f6; border-radius: 50%; cursor: pointer; border: 2px solid white; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } /* Stil für die verschiebbare Leiste */ #controls-container { cursor: grab; } #controls-container:active { cursor: grabbing; } </style></head><body class="h-screen overflow-hidden flex flex-col">
<header class="p-4 flex justify-between items-center bg-white shadow-sm z-10"> <div> <h1 class="text-xl font-bold text-slate-800">Zeichnen einer Parabel</h1> <p class="text-xs text-slate-500 font-medium">Lerne, wie Mathe zu Grafiken wird</p> </div> <div class="bg-blue-50 px-4 py-2 rounded-lg border border-blue-100"> <span id="equation-display" class="text-blue-700 font-mono font-bold text-lg">y = 1x² + 0x + 0</span> </div> </header>
<main class="flex-grow relative overflow-hidden"> <canvas id="plotCanvas" class="w-full h-full"></canvas>
<div class="absolute top-6 left-6 space-y-3 pointer-events-none"> <div class="glass-panel p-4 rounded-xl shadow-lg border border-slate-200 w-64"> <h3 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-2">Mathematik</h3> <div class="space-y-2"> <div class="flex justify-between items-center"> <span class="text-sm text-slate-600">Scheitelpunkt:</span> <span id="vertex-info" class="text-sm font-bold text-red-500 font-mono">(0, 0)</span> </div> <div class="flex flex-col"> <span class="text-sm text-slate-600">Nullstellen:</span> <span id="roots-info" class="text-sm font-bold text-blue-500 font-mono">Keine</span> </div> </div> </div> </div>
<div id="controls-container" class="absolute bottom-10 left-1/2 -translate-x-1/2 w-full max-w-3xl px-6 select-none"> <div class="glass-panel p-6 rounded-2xl shadow-2xl border border-white flex flex-col md:flex-row gap-6 items-center"> <div class="flex-grow grid grid-cols-1 md:grid-cols-3 gap-6 w-full pointer-events-auto"> <div class="space-y-1"> <div class="flex justify-between text-xs font-bold text-slate-500"><span>Faktor a</span><span id="val-a" class="text-blue-600">1.0</span></div> <input type="range" id="input-a" min="-4" max="4" step="0.1" value="1" class="w-full h-1.5 bg-slate-200 rounded-lg appearance-none cursor-pointer slider-thumb"> </div> <div class="space-y-1"> <div class="flex justify-between text-xs font-bold text-slate-500"><span>Faktor b</span><span id="val-b" class="text-emerald-600">0.0</span></div> <input type="range" id="input-b" min="-10" max="10" step="0.1" value="0" class="w-full h-1.5 bg-slate-200 rounded-lg appearance-none cursor-pointer slider-thumb"> </div> <div class="space-y-1"> <div class="flex justify-between text-xs font-bold text-slate-500"><span>Faktor c</span><span id="val-c" class="text-purple-600">0.0</span></div> <input type="range" id="input-c" min="-15" max="15" step="0.5" value="0" class="w-full h-1.5 bg-slate-200 rounded-lg appearance-none cursor-pointer slider-thumb"> </div> </div> <button id="reset-btn" class="p-3 bg-white border border-slate-200 text-slate-600 rounded-xl hover:bg-slate-50 shadow-sm pointer-events-auto"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg> </button> </div> <p class="text-center mt-3 text-[10px] text-slate-400 font-medium uppercase tracking-[0.2em]">Anfassen zum Verschieben der Leiste</p> </div> </main>
<script> /** * LERN-ABSCHNITT 1: Variablen & HTML-Verknüpfung */ const canvas = document.getElementById('plotCanvas'); const ctx = canvas.getContext('2d'); const controlsContainer = document.getElementById('controls-container'); const inputs = { a: document.getElementById('input-a'), b: document.getElementById('input-b'), c: document.getElementById('input-c') }; const displays = { eq: document.getElementById('equation-display'), vertex: document.getElementById('vertex-info'), roots: document.getElementById('roots-info') };
let scale = 40; let width, height; let offsetX = 0; let offsetY = 0;
/** * LERN-ABSCHNITT 4: Verschiebbare Benutzeroberfläche */ let isDraggingControls = false; let dragStartX, dragStartY; let containerStartX, containerStartY;
controlsContainer.addEventListener('mousedown', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON' || e.target.closest('button')) return; isDraggingControls = true; dragStartX = e.clientX; dragStartY = e.clientY; const rect = controlsContainer.getBoundingClientRect(); containerStartX = rect.left; containerStartY = rect.top; });
window.addEventListener('mousemove', (e) => { if (!isDraggingControls) return; const dx = e.clientX - dragStartX; const dy = e.clientY - dragStartY; controlsContainer.style.transform = 'none'; controlsContainer.style.left = (containerStartX + dx) + 'px'; controlsContainer.style.top = (containerStartY + dy) + 'px'; controlsContainer.style.bottom = 'auto'; });
window.addEventListener('mouseup', () => { isDraggingControls = false; });
/** * LERN-ABSCHNITT 2: Mathematische Funktionen */ function toScreenX(x) { return width / 2 + x * scale + offsetX; } function toScreenY(y) { return height / 2 - y * scale + offsetY; }
/** * LERN-ABSCHNITT 3: Das Zeichnen & Nullstellen-Logik */ function draw() { ctx.clearRect(0, 0, width, height); const a = parseFloat(inputs.a.value); const b = parseFloat(inputs.b.value); const c = parseFloat(inputs.c.value);
drawGrid(); drawAxes();
// Parabel zeichnen ctx.strokeStyle = '#3b82f6'; ctx.lineWidth = 4; ctx.beginPath(); let first = true; const startX = ( -width/2 - offsetX ) / scale; const endX = ( width/2 - offsetX ) / scale; const step = 1 / scale;
for (let x = startX - 1; x <= endX + 1; x += step) { const y = a * x * x + b * x + c; const sx = toScreenX(x); const sy = toScreenY(y); if (first) { ctx.moveTo(sx, sy); first = false; } else { ctx.lineTo(sx, sy); } } ctx.stroke();
// Analyse: Scheitelpunkt & Nullstellen if (a !== 0) { const xs = -b / (2 * a); const ys = a * xs * xs + b * xs + c; displays.vertex.textContent = `(${xs.toFixed(2)}, ${ys.toFixed(2)})`; ctx.fillStyle = '#ef4444'; ctx.beginPath(); ctx.arc(toScreenX(xs), toScreenY(ys), 6, 0, Math.PI * 2); ctx.fill();
const D = b * b - 4 * a * c; if (D > 0) { const x1 = (-b + Math.sqrt(D)) / (2 * a); const x2 = (-b - Math.sqrt(D)) / (2 * a); displays.roots.innerHTML = `x₁: ${x1.toFixed(2)}<br>x₂: ${x2.toFixed(2)}`; drawPoint(x1, 0, '#3b82f6'); drawPoint(x2, 0, '#3b82f6'); } else if (D === 0) { const x0 = -b / (2 * a); displays.roots.textContent = `x₀: ${x0.toFixed(2)} (Berührpunkt)`; drawPoint(x0, 0, '#3b82f6'); } else { displays.roots.textContent = "Keine reellen"; } } else { if (b !== 0) { const x0 = -c / b; displays.roots.textContent = `x₀: ${x0.toFixed(2)}`; drawPoint(x0, 0, '#3b82f6'); } else { displays.roots.textContent = c === 0 ? "Unendlich viele" : "Keine"; } displays.vertex.textContent = "n/a (Linie)"; }
displays.eq.textContent = `y = ${a}x² ${b>=0?'+':''}${b}x ${c>=0?'+':''}${c}`; document.getElementById('val-a').textContent = a.toFixed(1); document.getElementById('val-b').textContent = b.toFixed(1); document.getElementById('val-c').textContent = c.toFixed(1); }
function drawPoint(x, y, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.arc(toScreenX(x), toScreenY(y), 5, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = 'white'; ctx.lineWidth = 1.5; ctx.stroke(); }
function drawGrid() { ctx.strokeStyle = '#e2e8f0'; ctx.lineWidth = 1; const xSteps = Math.ceil(width/scale); const ySteps = Math.ceil(height/scale); for(let x = -xSteps; x <= xSteps; x++) { ctx.beginPath(); ctx.moveTo(toScreenX(x), 0); ctx.lineTo(toScreenX(x), height); ctx.stroke(); } for(let y = -ySteps; y <= ySteps; y++) { ctx.beginPath(); ctx.moveTo(0, toScreenY(y)); ctx.lineTo(width, toScreenY(y)); ctx.stroke(); } }
function drawAxes() { ctx.strokeStyle = '#64748b'; ctx.lineWidth = 2.5; ctx.beginPath(); ctx.moveTo(0, height / 2 + offsetY); ctx.lineTo(width, height / 2 + offsetY); ctx.moveTo(width / 2 + offsetX, 0); ctx.lineTo(width / 2 + offsetX, height); ctx.stroke(); }
Object.values(inputs).forEach(el => el.addEventListener('input', draw)); window.addEventListener('resize', () => { width = window.innerWidth; height = window.innerHeight; canvas.width = width; canvas.height = height; draw(); });
document.getElementById('reset-btn').addEventListener('click', () => { inputs.a.value = 1; inputs.b.value = 0; inputs.c.value = 0; draw(); });
window.onload = () => window.dispatchEvent(new Event('resize')); </script></body></html>