The Blog formerly known as "Flight of the Pigeon". A lot of Web, Plone and Python, with other occasional topics such as education and running.

Monday, June 10, 2013

A vertical image slider with jQuery and Plone's Products.Carousel

My goal was to create a vertical sliding effect to allow a visitor to experience tall images in a small area.
The images were made too tall for the viewing area and then, using jQuery's animate, were made to slide upwards through the viewing area. I used Products.Carousel but I'm sure a similar effect could be achieved with collective.carousel.

Products.Carousel is a Plone add-on that provides a point and click interface for managing banners, this makes it possible to appoint non-technical persons as banner administrators. Products.Carousel also builds on Plone's built-in workflow support so banners can be scheduled for publication and expiration among other things.

The Structure

The viewing area is wrapped with the css selector span.carousel-image
The carousel images can be selected based on a general selector such as .carousel img or based on the unique id associated with the slider

The Implementation

The key ideas are as follows:

We add custom css to match the viewing area class (called "carousel-image") to size we configure for the carousel.

We make the source images taller than the carousel viewing area.

We add custom css that enforces the height of the carousel images so they inherit the viewing area size.

We add custom javascript which will slide the image through the viewing area and is triggered upon changing of slides.

The CSS

To save on further explanation I've included annotations that explain the key CSS (There is other supporting CSS but it is more incidental to the functionality). In this example the carousel has the unique id "carousel-14937891799".

/*
rule for image, overrides the default image size and enforces
the height of the carousel images to 400px tall
*/
#carousel-1493789179 img {
width: 961px;
height: 400px;
position:relative;
}
/* rule for the span on top of the image.
switches it to behave like a block then makes the viewing area only
200px tall while preventing overflow
*/
.carousel-image {
height: 200px;
overflow: hidden;
display: block;
}

The Javascript

I had to use a CSS Inspector (the one that comes with Chrome) to determine the ideal displacement of the image which worked out to be 197px. Here's the jQuery animate syntax.

jQuery('.carousel img').animate({top:"-=197px"},9000);

A simple and complete script might look like this (In my case I just added the line to a existing jquery custom script that runs on load).:

jQuery(document).ready(function () {

jQuery('.carousel img').animate({top:"-=197px"},9000);

)};

update: I decided to make use of Products.Carousel's event system, as a result I added the following lines of code to my custom javascript:

jQuery(document).ready(function () {

$("#carousel-1493789179 img").animate({top: "-=197px"})
/* reset the slides to the top just before animation */
$('.carousel').bind('beforeAnimate',

function () {

jQuery('.carousel img').css('top','0px');

});

/* initiate slide up animation after a new slide has been displayed (ie. on new animation) */

$('.carousel').bind('afterAnimate',

function () {

jQuery('.carousel img').animate({top:"-=197px"},6000);

});

)};

Parting Thoughts

There are some weaknesses with this approach, for example it assumes that all banner images will always be 400px high. When there are multiple images in the Carousel the sliding up effect is lessened, this can be improved by tying the slide up effect to a Carousel event. It would also be good to add some easing for a smoother scroll effect.

Currently the script is fired even if there is no carousel present, making it detect the presence of a carousel first is a sensible next feature.

It might be useful to package this as an add-on for Products.Carousel so that it is 100% site administrator friendly in the future.

For the record, this was easier to do, back in the day with Flash, but then Android and iOS users would not be able to see it, plus my primary machine is now a Chromebook so there isn't much of an option for using the Flash IDE anyway. I would still be left to do the integration work so that mortals could manage the system when we're done.