Ask yourself this question: "Why should Google have all the fun?"

Let's build our own web page application that permits us to drag an image around...our project will be a simplication of the Google map application...we'll use one image that you can drag around, and not have hundreds of small images in an array, blah, blah, blah with AJAX calls to update the array of images, blah, blah.

It's simply a cool effect to be able to drag an image around. Here's the image we'll use.




The fundamental architecture of this application is to place the image in a background DIV that is larger than a foreground DIV. The foreground DIV acts as a viewport to the image behind it. More or less, this kind of architecture:




Create a web page with the following style and HTML elements. Download the big pretty picture of SnowWhite above. I saved it as "largeSnowWhite.jpg".

[CSS Style]
/* This DIV acts as the window to the inner DIV */
#outerDiv {
    height: 400px;
    width: 600px;
    border: 1px solid black; 
    /* The overflow is not visible */ 
    overflow: hidden;
}

/* This DIV carries the big image */
#innerDiv {
    position: relative; 
    left: 0px;
    top: 0px;
}

[HTML]       
<div id="outerDiv">       
    <div id="innerDiv">
      <img id="snowWhite" src="largeSnowWhite.jpg">
    </div>
</div>
      


Caution! If you use the following declarations as the head of your document, our application won't work, because it's not up to XHTML standards [Yes, it's a hack.]:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
		

Instead, use a simpler declaration:

        <HTML>
        


This code should produce a truncated image effect, like this:




A whole bunch of JavaScript!


Dragging an object around is not a simple operation to code. It involves capturing a mouse event, determining where the mouse was and where it is going, etc. A lot of this stuff is browser specific.

The following code is based on an example presented in the book "Pragmatic Ajax: A Web 2.0 Primer" by Gehtland, Galbraith and Almaer. [Actually, the Google example code in chapter one of their book doesn't work, so I messed around with five or six examples of code available on the web site for the book and found something like the following code example.]

Essentially the JavaScript has to do three things: (1) Handle cross-browser problems of recognizing events, (2) Define the events of beginning to drag, dragging and finished dragging, and (3) Calculating left-edge, top-edge position on the web page as you drag the image around.

Create a JavaScript file with the following script. Note that there is a function "init()" so that means that you'll have to use the onload attribute for the <body> tag of your web page.


 
// Variables for our JavaScript
var dragging = false;
var top;
var left;
var dragStartTop;
var dragStartLeft;


// Set up the application when the page loads
function init() {
    
    // Size the inner DIV    
    var innerDiv = document.getElementById("innerDiv");
    innerDiv.style.width = "1024px";
    innerDiv.style.height = "687px";

    // Prepare the outerDIV to listen to our cursor
    var outerDiv = document.getElementById("outerDiv");
    outerDiv.onmousedown = startMove;
    outerDiv.onmousemove = processMove;
    outerDiv.onmouseup = stopMove;

    // Hack up Internet Explorer
    outerDiv.ondragstart = function() { return false; }

   
}

// Responds when moving begins
function startMove(event) {
    
    // Hack up Internet Explorer
    if (!event) event = window.event;

    // Get the starting X,Y coordinates
    dragStartLeft = event.clientX;
    dragStartTop = event.clientY;
    // Target the innerDIV; fiddle with the cursor style
    var innerDiv = document.getElementById("innerDiv");
    innerDiv.style.cursor = "move";

    // Get the cursor position
    top = stripPx(innerDiv.style.top);
    left = stripPx(innerDiv.style.left);

    // Set a boolean to indicate things are happening
    dragging = true;
    return false;
}

// Things are moving
function processMove(event) {
    // Hack up Internet Explorer
    if (!event) event = window.event; 
    var innerDiv = document.getElementById("innerDiv");
    // If things are happening, reset the left and top positions
    if (dragging) {
        innerDiv.style.top = top + (event.clientY - dragStartTop);
        innerDiv.style.left = left + (event.clientX - dragStartLeft);
    }
}

// Stop dragging
function stopMove() {
    var innerDiv = document.getElementById("innerDiv");
    innerDiv.style.cursor = "";
    dragging = false;
}

// A helper function for turning strings like "250px" into numbers like "250"
function stripPx(value) {
    if (value == "") return 0;
    return parseFloat(value.substring(0, value.length - 2));
}

Drag me!



"Zooming" to different image sizes


Google maps has a zoom function that permits you to enlarge an image. We can emulate this effect with three different versions of the Snow White image: Small (645px x 480px), Medium (726px x 540px) and Large (806px x 600px). Place all these images in your working directory.

Since the smallest image size is 645px x 480px, I'll reduce the size of the outerDIV and default to targeting the smallest image "80largeSnowWhite.jpg" (i.e., go into your HTML and change the src attribute of the <img> tag).

#outerDiv 
{
    height: 300px;
    width: 500px;
    border: 1px solid black; 
    overflow: hidden;
}
 

Switching among these images can be done by adding some buttons "Small" "Medium" and "Large" and then adding functions that change the src attribute. For example:

   
function medium()
    {
        var i = document.getElementById("snowWhite");
        i.src = "90largeSnowWhite.jpg";
    }
    
  

At this point, my application looks like the following. It loads up with the smallest image and then I can click a button to get a larger image. All the images are draggable.




Adding a slider


Google maps has a slider widget to zoom the focus in and out; we can build our own with the help of the YUI library, which features several types of sliders.

For example, play with the following:


SmallMediumLarge

Pixel value: 0


Constructing a slider


Our slider will replace the three buttons ("Small", "Medium", "Large") so you might delete that code first. Save the JavaScript functions, however, that the buttons triggered. We can re-use those functions and have our slider fire them to exchange the various images.

Put the following code where you had your three buttons. The DIV with the words "Small", "Medium", "Large" is my code and you can modify it as you like. I also chose cyan as the background color for the DIV "slider-bg". Note that the little moveable slider is an image that you'll have to download.

<div style="font-size:xx-small">Small
   <span style="margin-left: 70px">Medium</span>
   <span style="margin-left: 70px;">Large</span>   
</div>
<div id="slider-bg" title="Slider" style="background-color:#33FFFF">
    <div id="slider-thumb"><img src="thumb-n.gif"></div>
</div>

There are several YUI JavaScripts that you have to import to your project. Place the following code in the head of your project. I've constructed some links here so you can download these files directly from this page.

  <!-- Dependencies --> 
  <script src = "yahoo-dom-event.js" ></script>
  <script src = "dragdrop-min.js" ></script>
  
  <!-- Slider source file --> 
  <script src = "slider-min.js" ></script>

  <script type="text/javascript" src="utilities.js"></script>
  <script type="text/javascript" src="slider.js"></script>


Add this special CSS style code to your project. Note the use of the "background:url" code to pick up the transparent gif that presents the little tick marks of the slider.

    #slider-bg {
        position: relative;
        background:url(bg-fader.gif) 5px 0 no-repeat;
        height:28px;
        width:228px; 
    }

    #slider-thumb {
        cursor:default;
        position: absolute;
        top: 4px;
    }


More JavaScript!


Finally, here is the JavaScript function that drives the slider.


(function() {
 
 // Declaration of variables
    var Event = YAHOO.util.Event,
        Dom   = YAHOO.util.Dom,
        lang  = YAHOO.lang,
        slider, 
        bg="slider-bg", thumb="slider-thumb", 
        textfield="slider-converted-value"

    // The slider can move 0 pixels up
    var topConstraint = 0;

    // The slider can move 200 pixels down
    var bottomConstraint = 200;

    // Custom scale factor for converting the pixel offset into a real value
    var scaleFactor = 1.5;

    // The amount the slider moves when the value is changed with the arrow
    // keys
    var keyIncrement = 20;

    var tickSize = 20;

    // The slider function
    Event.onDOMReady(function() {

        slider = YAHOO.widget.Slider.getHorizSlider(bg, 
                         thumb, topConstraint, bottomConstraint, 20);
		
        slider.subscribe("change", function(offsetFromStart) {
	

        // Put your switch here
		 
		 
        });

		
		
        // YUI code to start the slider
        slider.subscribe("slideStart", function() {
                YAHOO.log("slideStart fired", "warn");
            });
        // YUI code to stop the slider
        slider.subscribe("slideEnd", function() {
                YAHOO.log("slideEnd fired", "warn");
            });

  
    });
})();        


Re-engineer the code above with calls to your three functions that are fired by the positions of the slider.

// "offsetFromStart" is position of slider
// My code that fires on positions of the slider
switch (offsetFromStart)
{
case 20:
// Your code to fire your small() function
break
case 100:
// Your code to fire your medium() function
break
case 180:
// Your code to fire your large() function
break
default:			
}


Here's what the final effect looks like:




Bravo for you! Add this one to your deliverables page.