A fine example

13 May 2011 · by David DeSandro

Recently, some of my favorite people have taken the time to point out how Isotope is a fine example of developing for the best of what's available.

Trigger CSS3 Animations with jQuery by Thomas Reynolds

Thomas was awesome enough to properly explain one of the coolest features of Isotope -- how it handles CSS3 transforms within jQuery. Implementing transforms via JavaScript is a bit kludgy, as all the various functions -- translate(10px, 20px) and scale(0.5) -- get passed in as one string. This can be problematic when you only want to change one of those functional notations, and leave the other in tact. Isotope utilizes the CSS hooks introduced in jQuery 1.4.3 to keep track of the transforms. This article details how you can use this feature to your own advantage.

Bring your apps to life with CSS by Divya Manian

I'm a big fan of Divya's because she draws a clear line when it comes to best practices. So I was all the more delighted to find Isotope get a mention in a recent talk.

HTML5, CSS3, and DOM Performance by Paul Irish

Isotope portion starts at 9:53

Paul uses Isotope to talk about hardware acceleration. Getting the plugin to use hardware acceleration was no easy task, as I needed to develop all the stuff that Thomas talks about.

It's fantastic to see Isotope get this sort of recognition. I find it encouraging that each of the above mentions discuss not just Isotope's features, but how it has a series of fallbacks and intelligence built into it to enable its features in the best manner possible.

What you can expect with support

27 Apr 2011 · by David DeSandro

Just yesterday, Mr. Angel Marino pinged me for some help via the Isotope GitHub issue tracker. Most support requests come to me via the email mechanism I put in place with the support license. I recommend that customers looking for support to use email over GitHub issues or Twitter for the sake of confidentiality.

In this case, I got the impression that Angel was comfortable with openness, so now I have a good example of a typical support request process.

Here's how it went down.

Most importantly, he provided a live URL for me to look at. This is required for debugging. With that I got to work, running through my support routine.

  • Basic diagnostics. Making sure there are no JS errors and that the Isotope script is properly linked.
  • I then save a copy of the page locally and start developing on it.
  • Diagnose the problem. Revise any custom scripts. Resolve the problem.
  • Revise the script for best practices.
  • I then FTP my local copy to a publicly-viewable URL, so the customer can at least witness that it works.
  • Follow up with a response, pointing to the revised script I wrote.

When it comes to how I approach support, I'm trying to be as fair as I can with my customers and with myself. I realize implementing Isotope isn't as easy as most plugins. Naturally, there are going to be issues ran into by users with all levels of expertise. If you're paying to use Isotope, there's some accountability on my part.

But that's not to say that I am going to bend over backwards to resolve every issue that comes my way. I haven't put any sort of service-levels or promises up-front for a reason. Personally debugging others' issues can be especially time consuming, even for simpler implementations. I've priced the licenses so that I am rewarded for the work I put into the plugins, but also low enough that potential customers don't feel ripped off if I can't resolve their issue.

Support is still the trickiest part of running this business. I want my plugins to be used and enjoyed in a variety of implementations. I want my customers to get the best support possible, which is why I put my own personal time on the line, rather than recommending Stack Overflow or tweeting for help. But this comes at the cost of time, which the most expensive commodity I have to offer.

The mythical drag n’ drop multi-column grid plugin

31 Mar 2011 · by David DeSandro

Ciprian Mocanu on Stack Overflow asks:

I have elements of different sizes that are arranged somewhat according to a grid (like in the image below) and I want to drag and drop properly those elements. Is there a plugin that would do that? Sortable does not do it properly...

Ah yes, the mythical drag n' drop multi-column grid plugin. This is perhaps the number one requested feature for Masonry and Isotope. Users enjoy the animations and the intelligent layouts. Why not just add a touch of drag n' drop spice to the recipe? Turns out it's a bit easier said than done.

To date, the best implementation I've seen is Geckoboard, which uses jQuery UI Sortable. Looking at Masonry, Tyler Boyd made a brave a attempt to merge jQuery UI Draggable with Masonry. But I was never satisfied with the way it functioned. Dragging an item to a destination feels awkward. Check out my notes in the open issue for Masonry and Draggable.

When I was building Isotope, I had considered trying to implement some drag and drop functionality, but eventually decided against it.

As the layout is a grid, the logic behind determining order is in two dimensions. This is a complex problem to solve for. When moving an item, the plugin needs to evaluate both X and Y coordinates and how to interpret what elements are laid out after that point, and what elements are laid out after. If the layout is one-dimensional (like a vertical or horizontal list) or even a simplified grid, with items of equal size, the draggable position logic is fairly straight forward (no pun intended).

Clearly, there's a demand for this plugin. I do have some ideas floating in the back of my head as to how to go about it. I'd love to see it come to life, but alas, who has the time? Well if you do, hit me up and maybe we can hash it out. We could be heroes!

New demo - Combination filters

29 Mar 2011 · by David DeSandro

I just added a new Isotope demo for a highly-requested feature -- combination filters. Filtering with a single filter is fairly easy, just pass in a basic selector like { filter: '.red' } or { filter: '.tall' }. But if you wanted to filter for items that are both red and tall, you would need to combine these as one selector: { filter: '.red.tall' }. This demo shows you how to build an interface that will allow for such an interaction.

Check it out in all its Playskool glory!

Isotope Combination filters demo screenshot

The JS isn't too heavy. I'm using an object to store the filter for each group. Then when a new item is clicked, I update the object, compile an array of the filters, and then merge them together as one string. To allow a filter of nothing for each group, I assign an empty string for that group.

var $container = $('#container'),
    filters = {};

// filter buttons
$('.filter a').click(function(){
  var $this = $(this),
      isoFilters = [],
      prop, selector;
  // store filter value in object
  // i.e. filters.color = 'red'
  filters[ $this.data('group') ] = $this.data('filter');

  for ( prop in filters ) {
    isoFilters.push( filters[ prop ] )
  }
  selector = isoFilters.join('');
  $container.isotope({ filter: selector });

  return false;
});

Targeting first item after sorting

24 Mar 2011 · by David DeSandro

after a sort/filter, I'd like to apply special styling to the item in the new 'first' position. Is there an existing method for getting items by their post-isotope position index (which is now different than their DOM ordering)?

Yes, there's a way!

As previously mentioned, you can tap into Isotope's internal properties and settings with .data('isotope'). For this issue, we are interested in getting the items within Isotope that correlate to what the user sees. There are two jQuery objects in the properties $allAtoms and $filteredAtoms. As you can guess, $allAtoms are all the items that Isotope affects, while $filteredAtoms are the items that have been filtered and/or sorted.

var $sortedItems = $container.data('isotope').$filteredAtoms;

Once you have that jQuery object, you can use it just like any other. For this example, I am highlighting the appropriate first and last item after a sort.

View Isotope - target first / last item sorting on jsFiddle

Adding featured Isotope sites

22 Mar 2011 · by David DeSandro

Now that Isotope is crawling out of its infancy, I've started recording some of its more spectacular uses. See the Isotope Collection on Ember App. Over the weekend, I've integrated this feed into the Isotope homepage. which is pulled in dynamically via Ember's API.

I've only tiptoed around AJAX previously, so this is an awesome win for me. I no longer have to manage the images and mark-up associated with featured examples, as I've previously had to do with Masonry. The latest examples will be readily viewable as soon as I post them to Ember. Yay internets!

var ajaxError = function(){
  $sitesTitle.removeClass('loading').addClass('error')
    .text('Could not load sites using Isotope :(');
};

// dynamically load sites using Isotope from Ember app
$.getJSON('http://api.emberapp.com/users/view/' + 
            'desandro/collections/view/isotope.json?callback=?')
  .error( ajaxError )
  .success(function( data ){
    // proceed only if we have images
    if ( !data.response || !data.response.images ) {
      ajaxError();
      return;
    }
    // successful stuff follows...
  });

I'm taking advantage of jQuery 1.5's Promise Interface, chaining the .success() and .error() methods on to $.getJSON(). Rebecca Murphey put together a solid video on the new $.ajax hotness which helped me understand how to use the new methods.

The featured example sites is also an opportunity to show off the cellsByRow layout mode. It's nice because it vertically centers items within rows, allowing items of varying height to flow together within a strict grid.

$sitesList.isotope({
  layoutMode: 'cellsByRow',
  cellsByRow: {
    columnWidth: 290,
    rowHeight: 400
  }
});