Ich will es jetzt in JS

This commit is contained in:
2026-01-24 11:58:25 +01:00
parent 6acf34db5c
commit cb50a66fbb
2 changed files with 136 additions and 1 deletions

134
Mandelbrot.html Normal file
View File

@@ -0,0 +1,134 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Interaktives Mandelbrot</title>
<style>
body { margin: 0; background: #111; color: white; font-family: sans-serif; overflow: hidden; }
canvas { display: block; cursor: crosshair; }
.controls { position: absolute; top: 10px; left: 10px; background: rgba(0,0,0,0.7); padding: 15px; border-radius: 8px; pointer-events: none; }
kbd { background: #444; padding: 2px 5px; border-radius: 3px; }
</style>
</head>
<body>
<div class="controls">
<h2>Mandelbrot Explorer</h2>
<p><kbd>Links-Klick</kbd> Zoom In</p>
<p><kbd>Rechts-Klick</kbd> Zoom Out</p>
<small id="status">Berechne...</small>
</div>
<canvas id="mandelCanvas"></canvas>
<script>
const canvas = document.getElementById('mandelCanvas');
const ctx = canvas.getContext('2d');
const status = document.getElementById('status');
let width, height;
// Start-Koordinaten des Mandelbrot-Sets
let zoom = 1.0;
let centerX = -0.5;
let centerY = 0;
let maxIter = 150;
function resize() {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
draw();
}
function draw() {
const imgData = ctx.createImageData(width, height);
const data = imgData.data;
// Logik für den Bildausschnitt
const aspect = width / height;
const viewWidth = 4 / zoom;
const viewHeight = viewWidth / aspect;
const xMin = centerX - viewWidth / 2;
const yMin = centerY - viewHeight / 2;
for (let py = 0; py < height; py++) {
for (let px = 0; px < width; px++) {
let c_re = xMin + (px / width) * viewWidth;
let c_im = yMin + (py / height) * viewHeight;
let x = 0, y = 0, x2 = 0, y2 = 0, iter = 0;
while (x2 + y2 <= 4 && iter < maxIter) {
y = 2 * x * y + c_im;
x = x2 - y2 + c_re;
x2 = x * x;
y2 = y * y;
iter++;
}
const pixelIndex = (py * width + px) * 4;
if (iter === maxIter) {
data[pixelIndex] = data[pixelIndex+1] = data[pixelIndex+2] = 0; // Schwarz
} else {
// Dynamische Färbung (Hübsch & Schnell)
const hue = (iter / maxIter) * 360;
const rgb = hslToRgb(hue / 360, 0.8, 0.5);
data[pixelIndex] = rgb[0];
data[pixelIndex+1] = rgb[1];
data[pixelIndex+2] = rgb[2];
}
data[pixelIndex+3] = 255; // Alpha
}
}
ctx.putImageData(imgData, 0, 0);
status.textContent = `Zoom: ${zoom.toFixed(2)}x | Iterationen: ${maxIter}`;
}
// Hilfsfunktion für Farben
function hslToRgb(h, s, l) {
let r, g, b;
if (s === 0) r = g = b = l;
else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1; if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [r * 255, g * 255, b * 255];
}
// Interaktion
canvas.addEventListener('mousedown', (e) => {
const aspect = width / height;
const viewWidth = 4 / zoom;
const viewHeight = viewWidth / aspect;
// Klick-Position in komplexe Koordinaten umrechnen
const xClick = (centerX - viewWidth / 2) + (e.clientX / width) * viewWidth;
const yClick = (centerY - viewHeight / 2) + (e.clientY / height) * viewHeight;
if (e.button === 0) { // Links: Rein
zoom *= 2;
maxIter += 50; // Mehr Details beim Zoomen
} else if (e.button === 2) { // Rechts: Raus
zoom /= 2;
maxIter = Math.max(100, maxIter - 50);
}
centerX = xClick;
centerY = yClick;
draw();
});
canvas.oncontextmenu = (e) => e.preventDefault();
window.addEventListener('resize', resize);
resize();
</script>
</body>
</html>

View File

@@ -20,5 +20,6 @@ function draw()
# Zeichnet einen einzelnen Punkt (Pixel) bei x=200, y=200
# Da ein Pixel winzig ist, nutzt man oft ein kleines Rechteck
# oder die Point-Funktion.
draw(Rect(200, 200, 1, 1), :red, fill=true)
draw(Rect((200, 200), (1, 1)), colorant"red", fill=true)
end