Viewer Window with thumbnail pan and centered zoom

Overiew

This tutorial shows how to do a pan and zoom with a thumbnail and large(er) viewing window. In addition, it does a centered zoom. While the centered zoom is not perfect, it works pretty well. I'm working on an update to it. In the meantime...This is what it does.

(742K with the photo)

The basic idea is to control the large view vial the smaller view. This tutorial assumes you know at least how to make buttons, create masks and movie clips. It assumes you can name an instance and. This tutorial is aimed at helping you to create the same thing from scratch, but obviously the existing parts will help since the learning curve should moreso be in the math and the interactions. It may be hard to follow for beginners. Either way, I would appreciate hearing your feedback

If you follow the action script from the tutorial as opposed to re-engineering from the .fla file, I would suggest going to expert mode. It's much easier to edit that way. <%BRK%>

The Viewer Window

Create the object to be viewed, panned, and zoomed in on

Create/import an object...photo, diagram, figure, floorplan or whatever you have that you want to be seen in the viewer window. We'll call this clip (library name) 'object2View' for this tutorial. We'll also assume we're placing the clips on the _root level. Here's a list of things to check when creating it to avoid problems later.

Mask the viewed object

Create a mask using the layer above the layer this clip is on. Make the mask slightly larger or the same size as your clip and note that down. We'll do it the same size for simplicity sake.

Note: Some people may want to create their mask area first and then put their object behind it so as to give perspective. That's fine too.
<%BRK%>

The Thumbnail Clip

Create the Thumbnail

In your library window, duplicate the object2View clip and edit it. Use the info. or properties panel to change the height and width to a factor of the original. For this sake, we'll make the thumbnail 1/5th of the original (120x88).

Note: When sizing (or resizing) the thumbnail (new Window/in the current Window/in Place). If there is special interactive functionality in the object2View clip that you don't want transfered...you will need to edit or simply mask it with an inert button.

Position the Thumbnail

Go back to your main timeline and place the thumbnail onto the stage on a new layer. You can place the thumbnail anywhere you'd like in reality. The important thing is to note where you do place it. For this example, we'll place it at (650,10).
Hint: round numbers and the info. panel make it easier to deal with the math later.

After placing the clip, name the instance 'lilfigure'. Why? Because the thumbnail was a small version of the 'figure'. Feel free to change these names to suit your project. <%BRK%>

The Magnifying Glass (Part 1)

Create the movie clip

Your overlay or magnifying glass correlates to your mask just like the thumbnail correlates to the larger movie clip to be viewed.

Create a new movie clip with a rectangle in it that is 1/5th of the mask. This will be easy since the mask and the large clip are the same size. That means this is the same size as the thumbnail (120x88). Use the mixer or properties panel to put an alpha effect on and it will be see through. Finally, make sure this object is at 0,0.

Create the drag effect

[Still in the magnifying glass movie clip] Create a transparent button and place it on the top layer of the clip. Register it at 0,0 inside the movie clip (i.e. position it to 0,0). Use the following code for the drag effect...

on (press) {
	// start the drag
	startDrag ("_root.mag");
	// play the clip to activate the code in frame 2
	play ();
	mouse_down = "true";
}
on (release, releaseOutside) {
	// stop the drag
	stopDrag ();
	// stop the clip to save some processing
	stop ();
	mouse_down = "false";
}
This code assumes we've named our movie clip 'mag'...we'll do that in a moment. It also sets something up we're about to do in the frames clips. <%BRK%>

4. The Magnifying Glass (Part 2)

Using frames allows this update to happen while other things process in flash. Essentially the two-frame arrangment sets up a while-loop effect (just like pre-loading). Add a frame (total of 2 frames) to the movie clip. And use the following code for each frame

Code for frame 1

if (mouse_down eq "true") {
	play ();
} else {
	stop ();
}
This code simply uses the mouse_down variable (set to true on press and false on release) to determine whether or not it should proceed and execute the code in frame 2.

Code for frame 2

cur_x = _root.mag._x;
cur_y = _root.mag._y;
// Check to see if the magnifying glass/viewing area has moved..if so, update
if (Number(cur_x)<>Number(prev_x) or Number(cur_y)<>Number(prev_y)) {
	// This function is on the root movie clip and is used to updated the viewing window
	_root.move_panel();
}
// set the current position as the next position
prev_x = cur_x;
prev_y = cur_y;
gotoAndPlay (1);
I discovered that you can use the same toggle idea (setting a variable to true/false or 0/1) with ClipEvent instead of the two frame loop with the first frame checking conditions. So instead of using frames...you can just put frame 2's code in the MC itself, something like...
onClipEvent (enterFrame) {
	if (mouse_down == 1) {
	cur_x = _root.mag._x;
	cur_y = _root.mag._y;
// Check to see if the magnifying glass/viewing area has moved..if so, update...etc
//	etc...
}

Placing the magnifying glass

Return to the main timeline and place the clip at the same x,y as the thumbnail (650,10). Give it an instance name of 'mag' to match what we've put in the code (or come up with your own inventive name...just adjust the code accordingly). <%BRK%>

The Zoom Slider (Part 1)

The zoom slider works similarly to the magnifying glass in the frame code...but does a little more math before passing on to the functions at the root level.

Create the movie clip

Create a new movie clip and create a knob looking graphic (a simple radial gradient will do for most people). over that graphic, place your/a transparent button. Size (and/or shape) it to lay over the knob graphic.
Important: Use the alignment tool to center (horizontally and vertically) the graphic and button relative to the stage...this clip is not registered at 0,0 internally.

The drag effect

on (press) {
	y_coord = _root.zoom_knob._y;
	//drag the knob in a confined space
	_root.zoom_knob.startDrag(true, x_coord, y_coord, x_limit, y_coord);
	mouse_down = "true";
	play ();
	// Set the toggle and play the magnifying glass clip as well
	_root.mag.mouse_down = "true";
	_root.mag.play();
}
on (release, releaseOutside) {
	stopDrag ();
	mouse_down = "false";
	stop ();
	// Stop the magnifying glass clip and set the mouse_down toggle to false
	_root.mag.mouse_down = "false";
	_root.mag.stop();
}
Next we do the code in the frames... <%BRK%>

The Zoom Slider (Part 2)

Add a second frame to the clip and use the following code...

Code for frame 1

// the x-coord is the starting point of the slider knob
x_coord = 650;
// 700 is as far as the
x_limit = 700;
if (mouse_down eq "true") {
	play ();
} else {
	stop ();
}

Code for frame 2

//get the current x of the knob and compare it to what it was previously to see if we need to update anything
var cur_x = _root.zoom_knob._x;
if (Number(cur_x)<>Number(prev_x)) {
	//the x has changed...use this *simple* equation below 
	// It's based on 50 px movement, 400% zoom & a base mag_factor of 5 (that's where the 6 comes from)
	var zoom_perc = 400 - (6*(x_limit - cur_x)); 
	// Figure out the inverse percentage for the magnifying glass
	// 20 is the maximum mag_factor (400% with a base mag_factor of 5 and defaulted at 100%)
	var mag_perc = (100/zoom_perc)*20;
	// Call the scaling function and moving function
	_root.scale_mag(zoom_perc,mag_perc);
	_root.move_panel();
}
// Set the current x as previous and do it again...as long as the knob is moving
prev_x = cur_x;
gotoAndPlay (1);
This code works like the panning routine in the 'mag' MC. Like that one you could also put frame 2's code in the MC using OnClipEvent(EnterFrame).
Note: You could do a vertical zoom (track _y instead of _x).
<%BRK%>

Functions at the root level

These functions are the glue that hold it all together. They are called by the magnifying glass and the slider knob. Somebody really smart could abstract these further than I have...if you do, send me an e-mail attached with the updated version! ;-P

Here's my best practices advice...create an 'actions/functions' layer on any MC you create...especially on the _root layer.

Pre-function code

This code runs when the movie loads before the functions get called...it is still very important
// The base_mag_factor is the correlation of the small picture to the big picture...
_root.base_mag_factor = 5;
// The mag_factor will change as scaling occurs
_root.mag_factor = _root.base_mag_factor;
//Stop so that this doesn't reset willy-nilly on us
stop();
The base_mag_factor is the proportion between your thumbnail and the viewer (viewed) object under the mask. _root.mag_factor starts out baselined, but is variable with the zooming.

The Zoom Function

/*
This function scales the magnifying glass and the bigpicture
It also helps to handle the centering effect on the zoom...
Read the comments on how that happens
*/
function scale_mag (zoom_perc,mag_perc) {

	// getting ready for later...to be able to center
	start_width = _root.mag._width;
	start_height = _root.mag._height;
	//scale it all...
	_root.figure._xscale = (zoom_perc);
	_root.figure._yscale = (zoom_perc);
	_root.mag._xscale = (mag_perc);
	_root.mag._yscale = (mag_perc);
	_root.mag_factor = (zoom_perc/100)*(_root.base_mag_factor);
	_root.zoom_ind = zoom_perc; //updates the percentage viewer
	// The other half keeps scaling in sync and centers the scaling
	// Find out the width and height now
	end_width = _root.mag._width;
	end_height = _root.mag._height;
	// Figure the difference in width and height (x and y)
	x_change = start_width - end_width;
	y_change = start_height - end_height;
	//adjust by half the difference
	_root.mag._x = _root.mag._x + x_change/2;
	_root.mag._y = _root.mag._y + y_change/2;
}
You'll notice the reference to the base_mag_factor (which remains constant)...that is why it has to be defined sepaprately from the mag_factor variable (which changes with the zoom).

The Pan Function

/*
Moves the panel inside the viewing window...
It moves opposite the magnifying glass.
This function is also called when scaling occurs
*/
function move_panel () {
	//trace (_root.mag_factor);
	_root.figure._x = 0 -((_root.mag._x-_root.lilfigure._x)*_root.mag_factor);
	_root.figure._y = 0 -((_root.mag._y-_root.lilfigure._y)*_root.mag_factor);
}

Essentially, the large window object (figure) moves opposite the thumbnail (lilfigure) with the magnification factor figured in. You could also do a simple drag on the object...but the idea here is to keep the inside-outside perspective.

Send me your feedback or questions