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.

Advertisements

Actions

Information

2 responses

23 06 2010
diviak

Hi,
Nice done, but one note needs to be made, and that’s the problem with variable named ‘item’. Internet Explorer (IE) has reserved the word ‘item’ and your code throws ‘Object doesn’t support this action’ error which is done by the ‘item’ variable. Solution is simple, rename ‘item’ to ‘eitem’ or whatever you want and it will work also in IE.
Cheers.

6 12 2010
Jim

Thanks for posting this strategy. I made 2 additional changes so it would work properly in my application:

1. Change the z-indexes on a hover to eliminate undesired bleed-through of other hover-effect images that overlap when an image is zoomed:
in popIn() add:
$(item.id).setStyle({ zIndex:’1001′ });
in popOut() add:
$(item.id).setStyle({ zIndex:’1000′});

2. When the page is resized, the absolutize() was messing up the resultant page, so I added the following handler on page re-size which converts all images back to relative, then to absolute again in the new location:

window.onresize = function () {
z.each(function(n) {
n.relativize();
n.absolutize();
})
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: