Feb 13 2009

1

Visual Sorting

Category: Mootools, UtilitiesTags: , , ,

As promised I have been cleaning up the code to my most recent demo. I will be releasing a much more polished API along with documentation in the near future. Stay tuned.

I just completed one of the biggest headaches. Visual sorting. This allows DOM elements to be sorted in the same way humans would visually. I tried to make this as simple as possible to use.

I extended ‘Elements’ with a new method ‘visualSort’. The tricky part with a visual sort is the fuzzy logic needed to handle elements being offset. If you play with the demo you will get a feel for what I am talking about. In the demo, there is no need for pixel perfect alignment of elements to be considered on the same row. To require this would make the UI completely useless. To have this kind of fuzzy range matching ‘visualSort’ has a tolerance parameter. This allows you to define how much elements can be offset before it is considered a new ‘row’. Currently, tolerance defaults to .5 (50%). I also established a second parameter ‘flatten’. If set to true the sorted list will be flattened and returned as an Elements object. Currently ‘visualSort’ defaults to false which returns a multidimensional array.

In writing this code I tried to optimize the sorting as much as possible. I see a few places that can be tweaked but overall it should be fast. I didn’t use any sort() methods. I handle all my own sorting as I iterate through the elements. Feel free to ask questions about the logic or code.

Enjoy! My Brain still hurts.

 
Elements.implement({
 
	visualSort : function(tolerance,flatten){
 
		var tolerance = (tolerance) || .5;
		var idx = [], el, c1, c2, placed;
 
		for(var i = 0, l = this.length; i < l; i++){
			el = this[i]; c1 = el.getCoordinates();
			if(!i) idx[0] = [el, c1];
			else {
				j = 0; placed = false;
				while(j < i && !placed ){
					c2 = idx[j][1];
					if(c1.top < c2.top) placed = true;
					else j++;
				}
				idx.splice(j,0,[el,c1]);
			}
		}
 
		var rows = [], row = 0, sorted = [], slen, threshold;
		for(i = 0; i < l; i++){
			c1 = idx[i][1];
			if(!i){
				rows[row] = [c1.top,(c1.top + c1.height*tolerance)];
				sorted[row] = [ idx[i] ];
			}
			else {
				threshold = rows[row];
				if((threshold[0] <= c1.top) && (c1.top <= threshold[1]) ){
					j = 0; placed = false; slen = sorted[row].length;
					while(j < slen && !placed){
						c2 = sorted[row][j][1];
						if(c1.left < c2.left) placed = true;
						else j++
					}
					sorted[row].splice(j,0,idx[i]);
				} else {
					row++;
					rows[row] = [c1.top,(c1.top + c1.height*tolerance)];
					sorted[row] = [idx[i]];
				}
			}
		}
 
		var result = [];
		for(i = 0, l = sorted.length; i < l; i++){
			result[i] = [];
			for(j = 0, len = sorted[i].length; j < len; j++){
				result[i][j] = sorted[i][j][0];
			}
		}
 
		if(flatten) return $$(result.flatten());
		return result;
 
	}
 
});

Example Usage:

var sorted = $$('your selector').visualSort(.7);

I believe the value of this will be seen in Drag and Drop interfaces and layout managers. It could have some potential use for serializing specific components. If you find a use for it please share.

The demo has been updated with this code, it works in IE now.

Tags: , , ,

One Response to “Visual Sorting”

  1. Visual Sorting DOM elements Explained | nwhite.net says:

    [...] am getting the impression that my previous post was a bit esoteric. It has some valid uses and I want to help visualize how you might use the [...]

Leave a Reply