Scriptaculous Image Hover Effect

16 06 2009

I’ll start with my editorializing; perhaps we (earlier Symfony/RoR users) chose poorly when integrating Prototype and Scriptaculous into the framework. It seems that jQuery is taking over, and a look at some of the Plugins being made for Symfony 1.2 are recognizing this, and moving some of the “Protaculous” functions out of the core and developing for jQuery. A search for specific Scriptaculous snippets provide fewer or no results relative to the same search for a jQuery snippet. Live and Learn.

Anyway, I was hoping to add some animation/effects to my otherwise very static website, and thought a simple hover-popup on the profile images could provide a small yet effective effect to give the site some modern motion. Here’s how I did it with the latest attempt for Scriptaculous Effects.

Based on these functions mentioned in the question here, I created these still simple functions:

var z1=0;
function popIn(ev) {
  item = Event.element(ev);
  if(!item.id)item.id='pop_'+(++z1);
  new Effect.Scale(item, 110, {scaleFromCenter:true,
    duration: .4, queue:{ position: 'end', scope: item.id }});
}

function popOut(ev) {
  item = Event.element(ev);
  new Effect.Scale(item, 91, {scaleFromCenter:true,
    duration: .4, queue:{ position: 'end', scope: item.id }});
}

For some brief explanation, these functions to be called on moveover/out events identify the item, if the item has no id, it creates one for it. The Scale effect “smoothly” zooms the element, and uses a scoped queue so that the zoom out will only be triggered after the zoom in completes, but multiple images can be zooming at once.

The effects can be attached with a call such as:

z=$$('.profile img');
z.each(function(n) {
  n.absolutize();
  n.observe('mouseover', popIn);
  n.observe('mouseout', popOut);
});

[Editor’s note: it was brought to my attention that the above call might fail if the images (when attaching to images) were not yet loaded. As such, we should wrap the above call in a

Event.observe(window, 'load', function() {...});

if the images are loaded with the document, or if they’re loaded later (e.g. AJAX), deal with both cases, when the images are and are not yet loaded:

z=$$('.profile img');
z.each(function(n) {
  if(n.complete){
    n.absolutize();
    n.observe('mouseover', popIn);
    n.observe('mouseout', popOut);
  }else{
    n.observe('load', function(ev) {
      n=Event.element(ev);n.absolutize();
      n.observe('mouseover', popIn);
      n.observe('mouseout', popOut);
    });
  }
});

]

Use the selector to find the elements to zoom, and attach the event observers to each.
Place this code after the elements are loaded, and BAM, you’re good to go. It’s nothing too fancy, but it works.

There’s a similar effect with jQuery found here which uses more CSS and seems prettier. I’m open to improvements to this snippet.

As an aside, the only decent site I’ve found with a few custom-made snippets is the Script.aculo.us Samplr (see the sidebar, not the main area). If only there were more of these, Scriptaculous might have a chance for survival.