ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
PhotoShop style 'navigator' using AS 3.0 - Lesson 2 of 2
http://www.actionscript.org/resources/articles/692/1/PhotoShop-style-navigator-using-AS-30---Lesson-2-of-2/Page1.html
Erik Liddell
Erik Liddell is an interactive designer based out of Boston MA. He graduated from The School of The Museum of Fine Arts Boston where he focused in Experimental Film and Multi-Media Design. 
By Erik Liddell
Published on November 12, 2007
 

This is Lesson 2 of my original tutorial: If you have not completed Lesson1 please do so using the link below.

I have broken this tutorial into two lessons in an effort to make it more accessible and less daunting.  In this tutorial we will set up a Photoshop™ style image navigator.  Lesson 1 will focus on the slider bar that allows our users to simply zoom in and out of the image by dragging it back and forth.  In Lesson 2 we will finish out “navigator” by building the functionality which allows our users to change their viewing area or focus point of the image they are zooming in and out of.

 

Lesson 1 covers (event listeners, scaling, and dragging)

 

Lesson 2 covers (enter frame loops, event listeners, scaling, and dragging)


Introduction

In this tutorial we are picking up where we left off in Lesson 1.  You will need the FLA with all the code we created in Lesson 1 to continue.  If you have not completed Lesson 1, please do so by clicking here.

In Lesson 1 we got our slider bar working and enabled it to resize our main image in proportion to our new "viewing area" Now we get to go further and actually allow our users to drag the viewing area and change the focus point of the main image. 

To do so we are going to create two new button functions and one onEnterFrame function that will loop continuously.  We will also be eliminating one of our old functions and including it in our new onEnterFrame function..

in the end: we will have:



Lets get started!!!!


getting rid of the code we won't need

As I mentioned there is some code we will be moving into our new onEnterFrame function, that we will be creating later.  So lets start by commenting out the code in question.
Go ahead and find the following code:

[as]function zoom(event) {
 if (sliderDrag==true) {
  var redBoxScale = (zTool.slider.x-zTool.sliderLine.x);
  if (redBoxScale>95) {
   redBoxScale=95;
  }
  if (redBoxScale<1) {
   redBoxScale=1;
  }
  this.zTool.targetArea.scaleX=(redBoxScale-100)/100;
  this.zTool.targetArea.scaleY=(redBoxScale-100)/100;
var scaleFactor = zTool.image.width/zTool.targetArea.width;
  image.width = viewArea.width* scaleFactor;
  image.height = viewArea.height* scaleFactor;
 }
}
zTool.slider.addEventListener(MouseEvent.MOUSE_MOVE, zoom);[/as]

If you follwed the instructions to the T in lesson 1, this should be the last function we wrote.  Lets go ahead select it and delete it.  If you are the nervous type who doesn't like to delet you can coment it out but surroung the code with "/*" at the begining and "*/" at the end like so:

[as]
/*
function zoom(event) {
 if (sliderDrag==true) {
  var redBoxScale = (zTool.slider.x-zTool.sliderLine.x);
  if (redBoxScale>95) {
   redBoxScale=95;
  }
  if (redBoxScale<1) {
   redBoxScale=1;
  }
  this.zTool.targetArea.scaleX=(redBoxScale-100)/100;
  this.zTool.targetArea.scaleY=(redBoxScale-100)/100;
var scaleFactor = zTool.image.width/zTool.targetArea.width;
  image.width = viewArea.width* scaleFactor;
  image.height = viewArea.height* scaleFactor;
 }
}
zTool.slider.addEventListener(MouseEvent.MOUSE_MOVE, zoom);*/
[/as]


The new code!

Lets start by creating our on Enter Frame Loop where we will include the script for the slider that we just took out.

[as]
this.addEventListener(Event.ENTER_FRAME,EnterFrame);
function EnterFrame(event:Event):void {
 
 /// old code we deleted minus the function around it
 var smlRectScale = (zTool.slider.x-zTool.sliderLine.x);
  if (smlRectScale>95) {
   smlRectScale=95;
  }
  if (smlRectScale<1) {
   smlRectScale=1;
  }
  this.zTool.targetArea.scaleX=(smlRectScale-100)/100;
  this.zTool.targetArea.scaleY=(smlRectScale-100)/100;

  var scaleFactor = zTool.image.width/zTool.targetArea.width;
  image.width = viewArea.width* scaleFactor;
  image.height = viewArea.height* scaleFactor;

//*---- we will be coming back to this spot in a bit to ad more to our onEnterFrame loop----*// 

}[/as]

This code works just as it did before but instead of being updated when our user drags the slider back and forth, it is constantly being updated

Ok, so now we want to get the drag going on our little red box  or "target area"

Out side of our EnterFrame loop lets create two new functions that start the dragging of our little red box on click and end it on release or roll out. We will be doing this just the same way as we did with the slider bar but with different drag limitations.   Our slider bar we had grounded to its y axis and confined to the beginning and end or our "slider line".  For our little red box we are going to allow it to move up and down on the y axis as well, but be confined to the edges of  the image in our zoom tool.

[as]
function reTargetOn(event) {
 var targetLimits:Rectangle = new Rectangle(zTool.image.x-((zTool.image.width-zTool.targetArea.width)/2),
  zTool.image.y-((zTool.image.height-zTool.targetArea.height)/2),
    zTool.image.width - zTool.targetArea.width,
    zTool.image.height - zTool.targetArea.height);
 zTool.targetArea.startDrag(true, targetLimits);
}
zTool.targetArea.addEventListener(MouseEvent.MOUSE_DOWN, reTargetOn);

function endTargetDrag(event) {
 zTool.targetArea.stopDrag();
}
zTool.targetArea.addEventListener(MouseEvent.CLICK, endTargetDrag);
zTool.targetArea.addEventListener(MouseEvent.ROLL_OUT, endTargetDrag);
[/as]

You will note that we created the limits for this drag much the same way we did for our slider, by creating a variable (this time called  targetLimits instead of sliderLimits).
But the rectangle we drew seems much more complicated doesn't it?

No need to fret, I'll take a moment to explain.
Remember that the rectangle is read like this ( left drag limit, top drag limit, right drag limit, bottom drag limit).

So lets go over these- 
 
Left Limit - The Formula we set for the left limit is the X position of the image in our zoom tool, minus the (difference in width of that image and our rectangle) divided by 2.  We divide by 2 because both of those symbols have a registration point which is centered.  That means their x position is actually centered and not the corner.

Top Limit - same deal as above, but substituting our x position for y position and width for height. 

Right and Bottom - just using the difference in width or height.

Lets test our movie. And discover a slight problem.

Our Drag on the slider should work again changing the size of our main image in proportion.  And, our small red box should be draggable and constrained to the edges of the smaller image in our zoom tool.
 
The problem is, if we zoom in a bit and drag our small red box to any of its' edges, then zoom back out, our red box is now flying out of bounds.

Thats where our onEnterFrame loop is going to be super handy!

Lets go back to our EnterFrame Loop.  and find that spot we commented out:
[as]
//*---- we will be coming back to this spot in a bit to ad more to our onEnterFrame loop----*//  
[/as]

Right after that line and before the: "}"  lets place the following code:

[as]
var targetLimits:Rectangle = new Rectangle(zTool.image.x-((zTool.image.width-zTool.targetArea.width)/2),
        zTool.image.y-((zTool.image.height-zTool.targetArea.height)/2),
    zTool.image.width - zTool.targetArea.width,
    zTool.image.height - zTool.targetArea.height);
if (zTool.targetArea.x<=targetLimits.x) {
  zTool.targetArea.x=targetLimits.x;
 }
 if (zTool.targetArea.y<=targetLimits.y) {
  zTool.targetArea.y=targetLimits.y;
 }
 if (zTool.targetArea.x>=targetLimits.x+targetLimits.width) {
  zTool.targetArea.x=targetLimits.x+targetLimits.width;
 }
 if (zTool.targetArea.y>=targetLimits.y+targetLimits.height) {
  zTool.targetArea.y=targetLimits.y+targetLimits.height;
 }
[/as]

Notice we just put the drag limits for our small red box in the enterFrame loop.  We did this so our flash is constantly doing the math and resetting the limits.  We need to do this because our users are constantly changing the size of our rectangle when they use the slider, thus changing our actual limits. Then we added a series of "if" conditions to constantly replace the the red box with in the limits as they get redrawn.

Ok finally, we want to get the main image to move so that its focus point is always in proportion to the draggable red box's orientation over the image in out zoom tool.  Right after the code we just added and before the final "}" ad this code:
[as]
image.x= this.viewArea.x -((zTool.targetArea.x - zTool.image.x)*(image.width/zTool.image.width));
 image.y= this.viewArea.y - ((zTool.targetArea.y - zTool.image.y)*(image.width/zTool.image.width));[/as]

Pretty simple math there, so I won't bother explaining it as my boss is over my shoulder wondering what I am doing.  So if you have any questions just shoot me an email..  thats it!

Feel Free to Download the Final FLA with all the code for refrence.