-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
143 lines (120 loc) · 4.52 KB
/
Copy pathscript.js
File metadata and controls
143 lines (120 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Get the canvas element and its 2D rendering context
const canvas = document.getElementById('mandelbrotCanvas');
const ctx = canvas.getContext('2d');
// --- Configuration ---
const MAX_ITERATIONS = 500; // Higher numbers mean more detail but are slower
// Set canvas dimensions to fill the window
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// --- Viewport State ---
let centerX = -0.75; // The X-coordinate in the complex plane to center the view on
let centerY = 0; // The Y-coordinate in the complex plane
let zoom = 1; // The zoom level
// --- Panning State ---
let isDragging = false;
let startX, startY;
// --- Main Drawing Function ---
function drawMandelbrot() {
const width = canvas.width;
const height = canvas.height;
const imageData = ctx.createImageData(width, height);
const data = imageData.data;
// Calculate the scale based on the current zoom level and canvas size
const scale = 2 / (width * zoom);
// Loop over every pixel in the canvas
for (let px = 0; px < width; px++) {
for (let py = 0; py < height; py++) {
// Convert pixel coordinates to a point on the complex plane
// C = (x0, y0)
const x0 = (px - width / 2) * scale + centerX;
const y0 = (py - height / 2) * scale + centerY;
let x = 0, y = 0;
let iteration = 0;
// The main Mandelbrot iteration loop
// Check if the point escapes to infinity
while (x * x + y * y <= 4 && iteration < MAX_ITERATIONS) {
const xtemp = x * x - y * y + x0;
y = 2 * x * y + y0;
x = xtemp;
iteration++;
}
// --- Coloring ---
const pixelIndex = (py * width + px) * 4;
if (iteration === MAX_ITERATIONS) {
// Point is inside the set - color it black
data[pixelIndex] = 0;
data[pixelIndex + 1] = 0;
data[pixelIndex + 2] = 0;
} else {
// Point is outside the set - color it based on how quickly it escaped
const hue = (iteration * 360 / MAX_ITERATIONS) % 360;
const saturation = 100;
const lightness = 50;
const [r, g, b] = hslToRgb(hue / 360, saturation / 100, lightness / 100);
data[pixelIndex] = r;
data[pixelIndex + 1] = g;
data[pixelIndex + 2] = b;
}
data[pixelIndex + 3] = 255; // Alpha (fully opaque)
}
}
// Put the generated image data onto the canvas
ctx.putImageData(imageData, 0, 0);
}
// --- Event Handlers for Interactivity ---
// Zooming with the mouse wheel
canvas.addEventListener('wheel', (event) => {
event.preventDefault();
const scaleFactor = event.deltaY > 0 ? 1.1 : 0.9; // Zoom in or out
zoom /= scaleFactor;
drawMandelbrot(); // Redraw the fractal with the new zoom level
});
// Panning with mouse drag
canvas.addEventListener('mousedown', (event) => {
isDragging = true;
startX = event.clientX;
startY = event.clientY;
});
canvas.addEventListener('mousemove', (event) => {
if (!isDragging) return;
const dx = event.clientX - startX;
const dy = event.clientY - startY;
// Move the center point based on how far the mouse was dragged
const scale = 2 / (canvas.width * zoom);
centerX -= dx * scale;
centerY -= dy * scale;
startX = event.clientX;
startY = event.clientY;
drawMandelbrot(); // Redraw at the new position
});
canvas.addEventListener('mouseup', () => {
isDragging = false;
});
canvas.addEventListener('mouseleave', () => {
isDragging = false;
});
// --- Helper Function for Coloring ---
// Converts HSL (Hue, Saturation, Lightness) color to RGB
function hslToRgb(h, s, l) {
let r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
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;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
// --- Initial Draw ---
drawMandelbrot();