Skip to content

Commit a95a2dc

Browse files
committed
improve zooming and panning through bounds.
1 parent abe2e8d commit a95a2dc

File tree

9 files changed

+97
-79
lines changed

9 files changed

+97
-79
lines changed

js/mandelbrot.js

Lines changed: 97 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use strict";
22

3-
import { GL } from './lib/gl.js';
4-
import { Vector } from './lib/vector.js';
3+
import { GL } from '../lib/gl.js';
4+
import { Vector } from '../lib/vector.js';
55

66
/**
77
* Class representing the madelbrot animation.
@@ -68,21 +68,11 @@ export class Mandelbrot {
6868
event.preventDefault();
6969
break;
7070
case 'c':
71-
this.zoom_target = this.mouse_position;
72-
if (this.zoom_speed > 0) {
73-
this.zoom_speed += 1;
74-
} else {
75-
this.zoom_speed = 1;
76-
}
71+
this.zoom(true);
7772
event.preventDefault();
7873
break;
7974
case 'v':
80-
this.zoom_target = this.mouse_position;
81-
if (this.zoom_speed > 0) {
82-
this.zoom_speed = -1;
83-
} else {
84-
this.zoom_speed -= 1;
85-
}
75+
this.zoom(false);
8676
event.preventDefault();
8777
break;
8878
default:
@@ -127,8 +117,17 @@ export class Mandelbrot {
127117
);
128118

129119
// Don't move outside the quad.
130-
if (position.x < -2 || position.x > 1 || position.y < -1 || position.y > 1) {
131-
return;
120+
if (position.x < -2) {
121+
position.x = -2;
122+
}
123+
if (position.x > 1) {
124+
position.x = 1;
125+
}
126+
if (position.y < -1) {
127+
position.y = -1;
128+
}
129+
if (position.y > 1) {
130+
position.y = 1;
132131
}
133132

134133
this.gl.set_camera_position(
@@ -140,63 +139,93 @@ export class Mandelbrot {
140139

141140
// Add mouse wheel listener
142141
this.canvas.addEventListener('wheel', (event) => {
143-
// No zooming while dragging.
144-
if (this.drag_active) {
145-
return;
146-
}
147-
148142
// Unproject mouse coords into scene coords.
149143
this.mouse_position = this.gl.unproject(event.layerX, this.canvas.clientHeight - event.layerY, 0.5);
150-
151-
this.zoom_target = this.gl.view_matrix.inverse().multiply_vector(this.mouse_position);
152-
153-
// Don't move outside the quad.
154-
if (this.zoom_target.x < -2) {
155-
this.zoom_target.x = -2;
156-
}
157-
if (this.zoom_target.x > 1) {
158-
this.zoom_target.x = 1;
159-
}
160-
if (this.zoom_target.y < -1) {
161-
this.zoom_target.y = -1;
162-
}
163-
if (this.zoom_target.y > 1) {
164-
this.zoom_target.y = 1;
165-
}
166-
167-
if (event.deltaY > 0) {
168-
if (this.zoom_speed > 0) {
169-
this.zoom_speed += 1;
170-
} else {
171-
this.zoom_speed = 1;
172-
}
173-
} else {
174-
if (this.zoom_speed > 0) {
175-
this.zoom_speed = -1;
176-
} else {
177-
this.zoom_speed -= 1;
178-
}
179-
}
144+
this.zoom(event.deltaY > 0);
180145
});
181146

182-
this.gl.add_render_hook((frame_delta) => this.zoom(frame_delta));
183-
this.gl.add_render_hook((frame_delta) => this.cycle(frame_delta));
184-
this.gl.add_render_hook(() => this.switch());
147+
this.gl.add_render_hook((frame_delta) => this.zoom_hook(frame_delta));
148+
this.gl.add_render_hook((frame_delta) => this.cycle_hook(frame_delta));
149+
this.gl.add_render_hook(() => this.switch_hook());
185150
this.gl.add_render_hook(() => this.drag_active);
186151

187152
this.gl.event_loop();
188153
}
189154

155+
/**
156+
* Handle a zoom event.
157+
*
158+
* @param {float} x
159+
* @param {float} y
160+
* @param {boolean} out True if zooming out.
161+
*/
162+
zoom(out) {
163+
// No zooming while dragging.
164+
if (this.drag_active) {
165+
return;
166+
}
167+
168+
this.zoom_target = this.gl.view_matrix.inverse().multiply_vector(this.mouse_position);
169+
170+
// Don't move outside the quad.
171+
if (this.zoom_target.x < -2) {
172+
this.zoom_target.x = -2;
173+
}
174+
if (this.zoom_target.x > 1) {
175+
this.zoom_target.x = 1;
176+
}
177+
if (this.zoom_target.y < -1) {
178+
this.zoom_target.y = -1;
179+
}
180+
if (this.zoom_target.y > 1) {
181+
this.zoom_target.y = 1;
182+
}
183+
184+
if (out) {
185+
if (this.zoom_speed > 0) {
186+
this.zoom_speed += 1;
187+
} else {
188+
this.zoom_speed = 1;
189+
}
190+
} else {
191+
if (this.zoom_speed > 0) {
192+
this.zoom_speed = -1;
193+
} else {
194+
this.zoom_speed -= 1;
195+
}
196+
}
197+
}
198+
190199
/**
191200
* Perform zoom calculations.
192201
*
193202
* @param {integer} frame_delta
194203
*/
195-
zoom(frame_delta) {
204+
zoom_hook(frame_delta) {
196205
if (this.zoom_speed === 0) {
197206
return false;
198207
}
199208

209+
// Scale the projection matrix for the zoom effect.
210+
if ((this.zoom_level < 30000 && this.zoom_speed < 0) || (this.zoom_level > 1 && this.zoom_speed > 0)) {
211+
const scale_factor = 1 - (frame_delta * this.zoom_speed / 1000);
212+
this.gl.projection_matrix = this.gl.projection_matrix.scale(
213+
scale_factor,
214+
scale_factor,
215+
1
216+
);
217+
218+
this.zoom_level *= scale_factor;
219+
220+
// Reduce the zoom speed over time.
221+
this.zoom_speed *= 1 - (frame_delta / 1000);
222+
if (Math.abs(this.zoom_speed) < 0.005) {
223+
this.zoom_speed = 0;
224+
}
225+
} else {
226+
this.zoom_speed = 0;
227+
}
228+
200229
// Find the vector from the current camera position to the zoom target.
201230
// Scale by the frame_delta so that the movement would occur in 1 / zoom_speed seconds.
202231
const movement_vector = new Vector(
@@ -207,29 +236,18 @@ export class Mandelbrot {
207236
).multiply(frame_delta * Math.abs(this.zoom_speed) / 1000);
208237

209238
// Update the camera position along the movement vector.
210-
this.gl.translate_camera_position(
211-
movement_vector.x,
212-
movement_vector.y,
213-
0,
214-
);
215-
216-
// Scale the projection matrix for the zoom effect.
217-
if ((this.zoom_level < 30000 && this.zoom_speed < 0)
218-
|| (this.zoom_level > 1 && this.zoom_speed > 0)) {
219-
const scale_factor = 1 + (frame_delta * -this.zoom_speed / 1000);
220-
this.gl.projection_matrix = this.gl.projection_matrix.scale(
221-
scale_factor,
222-
scale_factor,
223-
1
239+
if (this.zoom_speed < 0) {
240+
this.gl.translate_camera_position(
241+
movement_vector.x,
242+
movement_vector.y,
243+
0
244+
);
245+
} else {
246+
this.gl.translate_camera_position(
247+
-movement_vector.x,
248+
-movement_vector.y,
249+
0
224250
);
225-
226-
this.zoom_level *= scale_factor;
227-
}
228-
229-
// Reduce the zoom speed over time.
230-
this.zoom_speed *= 1 - (frame_delta / 1000);
231-
if (Math.abs(this.zoom_speed) < 0.005) {
232-
this.zoom_speed = 0;
233251
}
234252

235253
return true;
@@ -240,7 +258,7 @@ export class Mandelbrot {
240258
*
241259
* @param {integer} frame_delta
242260
*/
243-
cycle(frame_delta) {
261+
cycle_hook(frame_delta) {
244262
let speed = 200;
245263
if (this.extreme_mode) {
246264
speed = 10;
@@ -258,7 +276,7 @@ export class Mandelbrot {
258276
/**
259277
* Switch the rendered set.
260278
*/
261-
switch() {
279+
switch_hook() {
262280
if (this.current_julia === this.desired_julia) {
263281
return false;
264282
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)