Zooming In and Out of an Image
October 10, 2001
by Will Turnage
Dear Multimedia Handyman,
I have a bit of a big question. I was wondering if it is possible to program some sort of loop (zoom) application in director, that can zoom in and out of images. Any help is most welcome.
Yves Peeters
Yves-
If you want to create an application that can zoom in and out of images, then you can do this using just two behaviors. Take a look at this movie:
To create this effect in your own movie, all you need are two behaviors. The first behavior will control whether the cursor is the zoom in or zoom out cursor, and the second behavior will use imaging lingo to display a zoomed in part of an image.
The first behavior to display the proper cursor is pretty easy. You want the zoom-in cursor to appear when you roll the cursor over the image, however, if the SHIFT key is being held down, then you want the cursor to change to the zoom-out cursor. The key in this behavior is to use the mouseWithin handler which continually executes as you roll over the image. Here's the code for the behavior.
property pSprRef
on beginSprite me
pSprRef = sprite (me.spriteNum)
pSprRef.cursor = 302
end
on mouseWithin me
if the shiftDown then
if (pSprRef.cursor <> 303) then
pSprRef.cursor = 303
end if
else
if (pSprRef.cursor <> 302) then
pSprRef.cursor = 302
end if
end if
end
This behavior begins by making a reference to its own sprite and storing that reference in a variable (pSprRef). Next, you set the sprite's cursor to 302, which is the number for the zoom-in cursor.
Now you create a mouseWithin function that will execute when the mouse is rolling over the sprite on the screen. In this mouseWithin handler, the first thing you do is check whether or not the SHIFT key is being held down. If it is, then you check to see if the sprite's current cursor is set to 303, which is the number for the zoom-out cursor. If the sprite's cursor is not set to 303, your code sets the cursor to 303. Finally, if the SHIFT key is not held down, you check to see if the sprite's current cursor is set to 302. If it's not, then it sets the sprite's cursor to the zoom-in cursor. It's very important that you check the status of the cursor before changing it. Constantly setting the cursor can cause it to flicker.
Now that you have this behavior in place, you're ready to write the code that handles zooming in and out of an image. The way this behavior works is that it uses two bitmaps. The first bitmap is the full image you want to zoom and zoom out of. This image can be located anywhere in your cast and can be any size. The second image is a different bitmap that will just be used to display the specific part of the image that you're looking at any given point in time. The first step is to create some variables you'll need and initialize them.
on beginSprite me
pSprRef = sprite (me.spriteNum)
pMainImage = member ("rockies").image.duplicate ()
pMagnification = 1
pImgSourceRect = pMainImage.rect
pBlankImage = image (400, 300, 32)
pBlankImage.fill (pBlankImage.rect, color (#rgb, 0, 0, 0))
me.resetPict ()
end
When the behavior begins, it first creates a variable containing a reference to its sprite. Then it creates an image object containing the full image you are zooming in and out of. Next, a variable named pMagnification defines a number representing how much you've zoomed into the picture. By default, the magnification will be set to one. The next variable you create is called pImgSourceRect which will store a rect that tells you which part of your image is being displayed in the sprite on screen. Its initial value is equal to the rect of the full, zoomed-out image. Finally, you create a blank image object to display the zoomed-in part of the image. This image is filled with the color black so that if the image runs off of the screen, you just see a black background. The last step, once you have initialized all of your variables, is to call the resetPict function.
on resetPict me
tempImage = pBlankImage.duplicate ()
tempImage.copyPixels (pMainImage, tempImage.rect, pImgSourceRect)
pSprRef.member.image = tempImage
end
The resetPict function first creates a duplicate of the blank image and stores it in a local variable. Next, it copies a section of your original image, specified by the variable pImgSourceRect, and pastes it into the temporary image object. Finally, it displays the image object, by setting the image of the member of the sprite that this behavior is attached to.
So now you've initialized all of your variables, and you're ready to zoom in to (or out of) the image displayed on screen. When the user clicks the mouse, this is what happens:
on mouseDown me
if pSprRef.cursor = 302 then
pMagnification = min (pMagnification * 2.0, 32.0)
else
pMagnification = max (1.0, pMagnification / 2.0)
end if
if pMagnification = 1 then
pImgSourceRect = pMainImage.rect
else
tempRect = pMainImage.rect / pMagnification
tempClick = the mouseLoc - point (pSprRef.left, pSprRef.top)
offsetPercentH = tempClick.locH / float (pBlankImage.rect.width)
offsetPercentV = tempClick.locV / float (pBlankImage.rect.height)
absLocH = (offsetPercentH * pImgSourceRect.width) + pImgSourceRect[1]
absLocV = (offsetPercentV * pImgSourceRect.height) + pImgSourceRect[2]
newOffsetH = absLocH - (tempRect.width * offsetPercentH)
newOffsetV = absLocV - (tempRect.height * offsetPercentV)
pImgSourceRect = tempRect.offset (newOffsetH, newOffsetV)
end if
me.resetPict ()
end
When you click the mouse on the image, the first thing the code checks the cursor of the sprite to see whether you are zooming in or out. If you are zooming in, it multiplies the magnification by 2, up to a maximum of 32. If you are zooming out, then it divides the magnification by 2, making sure that the magnification doesn't get less than 1.
Next comes the complicated part, calculating the zoomed portion of the image to display. If the magnification is set to 1, this is easy because you will just display the full image on screen. However, if the magnification is greater than 1, you have to do some calculations based on where the user clicked.
You start by dividing the rect of your image by the magnification factor. This will give you the exact size of the area of your original image that will be blown up and displayed on screen. Now, you have to calculate where this rect needs to be located within your image.
The key step is to use the location where the user clicks the mouse. Your first step is to find the mouse's location relative to the edges of the displayed image. Next, you use those percentages to calculate the absolute location in your main image that the user clicked on. Finally, you use those percentages again to recalculate the location of the new rect using the point the user clicked as your center reference point .
The first step is to calculate where the user clicked the image relative to the image itself. You do this by taking the mouse's location when the user clicked and subtracting from it the location of your sprite's upper left corner. Then you calculate the percentage of how far to the right and how far down in your image you actually clicked. This is done by dividing the clicked location by the entire height and length of the on-screen image.
Once you've found the relative location of the user click on screen, you need to calculate where that click corresponds in your full image. You do this by taking the relative percentage you just calculated, and multiplying it by the width or height of the pImgSourceRect, which contains the absolute location of the image displayed on-screen. Keep in mind that you also need to offset these values by the upper left corner of the pImgSourceRect for an exact fit.
Now that you have the absolute location in your main image of where the user clicked, the final step is to take that location and calculate a new rect of what will be shown to the user. This is done by taking your relative percentages and the new sized rect, and calculating the offset of the rect with the absolute location you clicked on. Finally, you take this newly-calculated rect and store that value into pImgSourceRect. At this point, you're done with all the math, and you can just call the resetPict function to display the proper portion of the image on the screen.
A sample movie is available for download in Macintosh (1.1MB) or Windows (950k) format.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.