There are all sorts of fun things that you can do in javascript and html once you have a basic drag infrastructure working - and in fact we have covered a whole bunch of these possibilities here at Switch on the Code. Today we are going to take a look at another one - using a container as a sort of 'window' on a larger object. Almost every mapping website makes use of this technique, and Google Maps probably does it best - you only have so much space on the screen to look at the map, but you can grab and drag around the map inside of its container to view different areas.
Since we already have a pretty solid dragging infrastructure (you can read the tutorial on Draggable Elements if you want more info), actually accomplishing this task is going to be pretty easy. Because really, there is not that much to it - you have a container, and an element inside the container that is bigger than the container. And then you hook all the dragging operations up to the element inside the container. You really can't get a whole lot simpler than that. Below, we have the example that we are going to build today - go ahead, have fun dragging the duck around for a few moments!
Guess what? The code (not including the code from the Draggable Elements tutorial) is so simple, it can fit in a single code block:
border:1px solid black;width:520px;
height:250px;overflow:hidden;" >
<img id="draggableElement" src="duck.jpg"
style="width:1024px;height:1024px;position:absolute;
top:-333px;left:-500px;cursor:move;" />
</div>
<script type="text/javascript">
var el = document.getElementById('draggableElement');
var parent = el.parentNode;
var leftEdge = parent.clientWidth - el.clientWidth;
var topEdge = parent.clientHeight - el.clientHeight;
var dragObj = new dragObject(el, null,
new Position(leftEdge, topEdge), new Position(0, 0));
</script>
So first, we have the container div. The border and the explicit height and width are not needed - you could change those to whatever you needed. However, the overflow:hidden style is very important, because otherwise the entire child element would be visible, instead of only the portion that is actually in the container's area.
Next, we have the child element, the element being viewed through the 'window' that is the container. In this case, it is an image of a duck that is much bigger than the container element. We set the id (in this case to 'draggableElement'), because we are going to need to refer to it later in javascript. We set the height, the width, and the position - and we set it to be positioned absolutely (very important for the dragging code to work properly). Because I want the the duck's face to appear when the page is initially loaded, the top and left values are set to an appropriate offset. And, just to be nice, the image's cursor is set to the move cursor, so that when a user mouses over the image, they can tell that the image is draggable.
Then we have some initialization javascript code. We grab the child element out of the document (in this case 'draggableElement'), and get to work figuring out the relative size differences of the child and its parent. We use these number to figure out appropriate lower bounds for dragging. In this particular case, (with a 1024x1024 image and a 520x250 container), we end up with a minimum position of -504 by -774. At this position, the lower right corner of the image would be in the lower right corner of the container. The maximum position is always 0,0 - because that puts the upper left corner of the image in the upper left corner of the container
The final call creates the drag object. If you remember anything about the drag object constructor (or you just read the tutorial on Draggable Elements), you will know that the constructor can be pretty complicated. Here, the first parameter is the element that we will be dragging - i.e., the image. The second argument is what the user will click and hold to drag the element - in this case it is the same thing as the draggable element itself - so we can pass in null. The third argument is the minimum drag position, and the fourth is the maximum drag position. And as soon as this object is created, everything is hooked up, and you can drag the image!
Short and sweet, eh? That is all you need to get draggable container view like this off the ground (although I do admit, there is nothing short or sweet about the actually drag abject code - but hey, we wrote that already so it doesn't count against this particular little project, right?). You can download a zip file with all the source for the example here, and, as always, if you have any questions or comments, feel free to leave them below.
06/18/2008 - 02:30
Great!
How to add small zones responding to mouse clicks? (like google maps)
For example clicking the duck's eye triggers a function that shows related info.
regards,
bruno
07/11/2008 - 15:01
I have made a way to open and close these windows from buttons but because they are relative i cannot get them to pop up on top of each other, can you help?
08/05/2009 - 06:03
Great script, very usefull and exactly was i was looking for, but i have a little problem, im trying to make this work inside a jquery simple modal and it doest dragg at all, do you what can be the problem?
Thank you very much
11/16/2009 - 21:37
If you use this script for bigger image like 5000px the dragging is going to be very slowly
01/25/2010 - 12:41
Hi Bruno!
Why don't you create a draggable DIV instead of an image?
Then you put the image inside the draggable div with z-index=1.
This way you can place anything you want over the image simply using z-index=2...
Something like a transparent layer with a map or simply another div with a red dot positioned in absolute...
What do you think?
01/25/2010 - 13:08
ohua!
I was forgetting my question...
I've create a simply zoom effect that increases of 25% width and height of the image for every click of "+" button.
No problems with FF & Opera but Explorer is driving me mad.
To try, I've setted the correspondences this way (schematic):
if x=+, img.widht=1000px; leftEdge = ... - 1000;
if x=-, img.widht=800px; leftEdge = ... - 800;
initially it works, but after some click (only god knows why)the script confuses the bounds...
So once i can't see the full image and another I see the void down on the right...
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.