MoveableMap (or anything else in a 'viewport')
March 12th, 2008
MoveableMap is a javascript library that allows you to turn any block of HTML into a draggable, moveable entity within a viewport. Similar to the behavior of Google Maps, but hopefully very easy to implement. On the right here, you can see a real simple example; it’s just a div block with an img element in the middle of it.
How simple is the code for this example? The moveableMap library is built on top of the fantastic prototype.js library, the slick scriptaculous library, and the enlightening Low Pro library. It takes just a little CSS magic and a little unobtrusive javascript to get the behavior you see here.
We need two elements: the “container” block, and the block inside the viewport. In this example, they’ll both be divs.
Our CSS sets us up:
1 2 3 4 5 6 7 8 9 10 11 12 |
#map_holder { /* the 'container' */
width: 256px; height: 256px; /* size of the viewable area */
overflow: hidden; position:relative; /* necessary to make the whole thing work */
padding:0px; border: 3px dotted #990; /* aesthetics */
}
#the_map { /* the inner block */
width: 512px; height: 512px; /* defining the size keeps us from getting squashed */
left:-128px; top:-128px; /* the starting offset - always negative */
position:relative; /* better believe it, you need it */
border:3px solid #550; /* so we can see the edge of the map */
} |
A little javascript to create the MoveableMap object and apply some behaviors:
1 2 3 4 5 6 7 8 9 10 11 12 |
// we don't attempt anything until the DOM is loaded Event.observe(window, 'load', function() { // create a new MoveableMap object and pass in the two elements we need // I'm using the prototype shortcut $('my_html_id') to represent an element: mainMap = new MoveableMap($('the_map'), $('map_holder')); // here's the Low Pro unobtrusive helper: Event.addBehavior({ // specify the CSS selector for the inner block and // apply the MapDrag behavior to it (specifying the MoveableMap object) '#the_map' : MapDrag(mainMap) }); }); |
And the HTML, which is pretty trim:
1 2 3 4 5 |
<div id="map_holder"> <div id="the_map" style="background: url(/examples/map/images/fakemap.jpg)"> <!- just empty to give us a div with a image background --> </div> </div> |
Notice the lack of onclick, onmousedown, onmouseup in the HTML? That’s the unobtrusive bit, baby. All that stuff is handled by the MoveableMap library (as Behaviors a la Low Pro).
Let’s see some more impressive examples. Here’s something similar to what’s on the page here, but with a compass in the corner that you can click on to slide the map in that direction. Double-click to slide all the way to the edge. Take note of the fake HTML attribute called ‘mapdir’ inside each compass direction.
Check it: Old World Map with Compass
That was fun. What else you got? Here’s a (crudely drawn) map of Aethora. The ‘compass’ from the previous example has been placed around the edges of the map to give the viewer a feeling of clicking on the sides of the map to make it scroll. Additionally, you can see a list of cities below the map – click on any city to make the map slide to that location. In reality, the ‘cities’ are positioned div elements. The clickable element has a fake HTML attribute, targetelement, which names the id of the element you want to center the map on.
Peep: Fantasy map with clickable city names
This last map is more of the same really, but the big deal is that the inner block of code is a table. It’s basically here to prove to you that you can put some pretty complex stuff on the inside (not just a jpg of a street map) and still move the map around. This example is closer to the actual purpose I created this library for (Aethora, my RPG written in Ruby on Rails and javascript).
Observe: Tiled (table-based) ‘battle field’
Here’s the MoveableMap js file. You’ll need to load prototype, the scriptaculous effects.js library, Low Pro, MoveableMap, and then your own javascript in that order. Check out the source code of those examples above for more details. The code seems to work well in Firefox, IE6, and IE7. In Opera, it seems to do a slight, 3-4 pixel detour before getting on track when using the compass movement. If anyone can tell me how to fix it, I’ll buy you a beer/coffee (I had to sell my soul just to get it to work in IE). I haven’t had a chance to test it in Safari or anything else, but I’d love to hear how it works out.
So enjoy – and let me know if you find any bugs. And definitely let me know if you find it useful!
Update: Here’s a great example, this one provided Kahil, who is the developer of a browser-based game called WMD Tank Battle: Vertical Scrolling a la old school arcade shooters
Parallax Animation with CSS/JS
February 27th, 2008
I just read an article on ThinkVitamin about creating some nifty parallax scrolling style animation by using multiple layers of images that shrink at various proportions when you resize the browser window. A few of the comments noted that it’s unfortunate that the animation is only apparent when resizing the window, and something that would go fairly unnoticed by most people.
Being a lover of all video games, old and new, I thought this trick that I’ve seen in so many side scrollers was brilliant. My first thought was how to combine this with Script.aculo.us’s Morph effect so that you can see the animation without actually resizing the browser window. Turns out it wasn’t that hard – check it out!
Apologies for: (a) stealing the images from Paul’s example on the ThinkVitamin site for demonstration purposes and (b) for using onclick (I should be practicing unobtrusive javascript, but this is a really simple example that I wanted to crank out).
Pretty slick. Now I’m determined to find a need to use this trick in Aethora....
Unobtrusive Image Rollovers with Low Pro
February 17th, 2008
This week I finally broke down and decided to find out what this Unobtrusive Javascript thing is all about. First, I got really excited about trying out the UJS plugin for Rails. I’m not linking to it, because after a couple of hours of digging around, Googling for the errors I was getting and finally digging into the source to find out it was breaking the tag_options helper in Rails 2, I discovered it’s no longer a supported plugin. Dan Webb, the original author, came to the conclusion that the unobtrusive message was not getting through to the typical Rails developer who picked up the plugin for it’s shortcuts. He pulled the lowpro.js library out of the plugin and ditched the Rails bits. I think it was a good move (I just wish someone would update ujs4rails.com to say something to that effect – it’s still the same page it was over a year ago, and it really sells the plugin well…)
There’s not really a lot of documentation for Low Pro out there, but to be honest, once you start using it I think you find there really isn’t a lot to it. Built on prototype, the lowpro.js file is only 300 or so lines of code, including some helpful comments. There are some links on the lowpro wiki to a couple blog posts with examples. In particular I found Jarkko Laine’s article very helpful and of course Dan’s blog is worth a read. Unfortunately, due to the speed of technology, some of Dan’s examples are a little dated (thanks to improvements he’s made to the code).
So I figure, how’s about another example? One key concept behind unobtrusive javascripting is yanking those obnoxious mouse events out of your anchor tags; Onmouseover, onmouseout, etc – they’ve got to go. So how can we use Low Pro to add a rollover behavior to some images?
note: at the time of this writing, Low Pro is version 0.5 and requires prototype version 1.6.x
Step 1: Plain HTML
Let’s start with the HTML. Imagine a menu that’s just a column of images; no javascript yet, just plain ol images (and of course styled with CSS in another file):
1 2 3 4 5 |
<ul class="main_menu"> <li><a href="/pages/home"><img src="home.gif" alt="Home"/></a></li> <li><a href="/pages/about"><img src="about.gif" alt="About"/></a></li> <li><a href="/pages/contact"><img src="contact.gif" alt="Contact"/></a></li> </ul> |
Very simple. Probably everyone knows the mechanics of a rollover by now: what we want is for the img src attribute to change to a different value when the mouse cursor is placed over the image. The effect is getting a different image to display in place of the current image. And of course, when the cursor leaves the area of the image, we want the src to switch back. So how do we do that without using our tried and true “onmouseover/onmouseout” HTML attributes?
Step 2: Create a Behavior
We want to define a Behavior to describe the effect certain mouse events have on a particular image object. Low Pro makes this nice and clean, using the Class module baked into prototype to give us an object-oriented feel.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
var ImageRollover = Behavior.create({ // define some attributes for this new Behavior (mmmm, OOP...) orig_name: null, // the filename without extension image_ext: null, // jpg, gif, etc, plus any ?123 nonsense at the end roll_suffix: null, // whatever we want to stick on the end of the image name // one of these instances of ImageRollover will be created for each image // when we set them up, we'll need to know the "suffix" of the rolled over image // for example, home.gif might be our image and home_on.gif might be our // rollover, making '_on' our suffix initialize: function(roll_suffix) { this.roll_suffix = roll_suffix // here comes some lovely regex // image.src example: http://example.com/images/something.gif?1234567890 // we need to chop that up into: // 'http://example.com/images/something' and '.gif?1234567890' matches = this.element.src.match(/(.*)((?:.gif|.jpg|.png).*)/); this.orig_name = matches[1]; this.image_ext = matches[2]; }, // this function will get called on mouseover onmouseover: function() { // we're just stapling the pieces back together with the suffix between // the file name and the file extension this.element.src = this.orig_name + this.roll_suffix + this.image_ext }, onmouseout: function() { // back to the original, no suffix this.element.src = this.orig_name + this.image_ext } }); |
So there’s our behavior. It’s nice and generic – we could apply it to any image element. I’m not great with regex, but this will work for any image that ends with .gif, .jpg, or .png and optionally if it has an asset timestamp at the end following a question mark (Ruby on Rails likes to stick these on the end of assets to trick browsers into reloading cached image, css, and js files that might have changed when code has been updated). I recently came across this great testing tool for regex expressions: http://www.rubular.com/. Of course, the Firebug console is also great for this type of thing as well. For some reason my regular expression yields a third, unnecessary match (just the file extension with no timestamp) and I can’t quite nail it down. It doesn’t affect anything, but hey – let me know if you have a suggestion. Edit: Andy (in the comments) points out where the extra match comes from and how to ignore it. I updated the regex and it works.
Step 3: Assign Behavior
Finally, we can assign our ImageRollover behavior to some images. The magic of CSS selectors makes it easy to assign a behavior to a whole group.
1 2 3 |
Event.addBehavior({
'.main_menu img': ImageRollover('_on')
}); |
The addBehavior method takes a hash where every key is a CSS selector and the value is a behavior. In this example, we can see that the CSS selector is saying “look for elements of the main_menu class and collect any of their children that have the img tag”. We also have to pass a value to ImageRollover that designates the rollover image suffix needed by the initialize method of the ImageRollover class.
Want proof that it works? See it in action (warning: extremely bad graphics that I cranked out in 5 minutes).
So there you have it. If anyone who knows Low Pro has any feedback on improving this example, I’d love to hear it.

