Plotting Fractals in WebAssembly
Plotting Fractals in WebAssembly
Previous | Top | Next |
---|---|---|
5: Plotting a Julia Set | 6: Zooming In | 7: WebAssembly and Web Workers |
6.1: Add Zoom In/Out Functionality | 6.2 Add Slider for Changing max_iters |
6.1: Add Zoom In/Out Functionality
Now we will add the functionality that allows you to zoom in and out of the Mandelbrot Set. This will be implemented simply by left and right mouse clicks.
Any given zoom level is determined simply by deciding how many pixels are needed to plot one unit on the complex plane.
The higher the number of pixels, the greater your level of magnification.
The default (and also minimum) zoom level is 200
pixels per unit.
This value has been derived by dividing the entire canvas width by 4, thus allowing you to see the entire Mandelbrot Set.
We’ll start by defining the maximum, minimum and current zoom levels:
const MAX_PPU = 6553600 // Allow for 16 zoom steps (100 * 2^16)
const MIN_PPU = CANVAS_WIDTH / 4 // Start by showing entire Mandelbrot Set
let PPU = MIN_PPU
When you zoom in, the zoom level is doubled until MAX_PPU
is reached.
Similarly, when you zoom out, the zoom level is halved until MIN_PPU
is reached.
When MIN_PPU
is reached, the image of the Mandelbrot Set is automatically recentred.
In both cases, the location on which you click becomes the centre pixel of the new image.
Since both the zoom level and the coordinates of the image’s centre pixel are now variable, every time the zoom level changes, we need to redefine the helper functions that transform a pixel location to complex plane coordinates.
This firstly means that functions mandel_x_pos_to_ccord
and mandel_y_pos_to_ccord
can no longer be defined as constants:
let mandel_x_pos_to_coord = canvas_pxl_to_coord(CANVAS_WIDTH, PPU, X_ORIGIN)
let mandel_y_pos_to_coord = canvas_pxl_to_coord(CANVAS_HEIGHT, PPU, Y_ORIGIN)
Zoom Event Handler
The functionality needed when zooming into the Mandelbrot Set is almost identical to that needed when zooming out.
The only difference is that when we zoom in, PPU
is multiplied by two until it reaches MAX_PPU
, and when we zoom out, PPU
is divided by two until it reaches MIN_PPU
.
This means we can create a single partial function that when passed the zoom direction, returns an event handler function that changes PPU
appropriately.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Partial function for handling image zoom in/out events
const zoom = zoom_in => evt => {
// Suppress default context menu when zooming out
if (!zoom_in) evt.preventDefault()
// Transform the mouse pointer pixel location to coordinates in the complex plane
X_ORIGIN = mandel_x_pos_to_coord(
offset_to_clamped_pos(evt.offsetX, evt.target.width, evt.target.offsetWidth)
)
Y_ORIGIN = mandel_y_pos_to_coord(
offset_to_clamped_pos(evt.offsetY, evt.target.height, evt.target.offsetHeight)
)
// Change zoom level
PPU = zoom_in
? (new_ppu => new_ppu > MAX_PPU ? MAX_PPU : new_ppu)(PPU * 2)
: (new_ppu => new_ppu < MIN_PPU ? MIN_PPU : new_ppu)(PPU / 2)
$id("ppu_txt").innerHTML = PPU
// If we're back out to the default zoom level, then recentre the Mandelbrot Set image
if (PPU === MIN_PPU) {
X_ORIGIN = DEFAULT_X_ORIGIN
Y_ORIGIN = DEFAULT_Y_ORIGIN
}
// Update the mouse position helper functions using the new X/Y origin and zoom level
mandel_x_pos_to_coord = canvas_pxl_to_coord(CANVAS_WIDTH, PPU, X_ORIGIN)
mandel_y_pos_to_coord = canvas_pxl_to_coord(CANVAS_HEIGHT, PPU, Y_ORIGIN)
// Redraw the Mandelbrot Set
draw_fractal(0.0, 0.0, true)
}
Notice also that the call to the WebAssembly function mj_plot
has been moved into a function called draw_fractal
.
Now, the zoom event handler is added to the Mandelbrot canvas
HTML element for both the left (click
) and right (contextmenu
) mouse click events:
mCanvas.addEventListener('click', zoom(true), false)
mCanvas.addEventListener('contextmenu', zoom(false), false)