Source: maps/limbs/layout/ZShiftedLayoutStrategy.js


/**
 * @class
 * A strategy that orders the z-index of any LIMBs that are overlapping.
 * LIMBs representing targets that are closest to the map will be shown above those that are further away.
 * 
 * @constructor
 * @param {lucid.maps.limbs.layout.ZShiftedLayoutStrategyOptions} options  The options controlling the layout.
 */
lucid.maps.limbs.layout.ZShiftedLayoutStrategy = function( options )
{
	lucid.maps.limbs.layout.LayoutStrategy.apply( this, [options] );

	
	var limbs;
	var super_ = this.createSuperReferences();
	
	
	this.layout = function( div, position, mapDetails )
	{
		super_.layout( div, position, mapDetails );
		
		limbs[limbs.length] = { element: div,
		                        position: position,
		                        mapDetails: mapDetails };
	};
	
	this.init = function()
	{
		super_.init();
		
		limbs = [];
	};
	
	this.complete = function()
	{
		var zIndexMin = this.getMinZIndex();
		var zIndexMax = this.getMaxZIndex();
		var zIndexRange = zIndexMax - zIndexMin;
		var zIndexDistanceRatio;
		
		var overlappingLimbs;
		
		for (var i=0; i<limbs.length; i++)
		{
			var limb = limbs[i];
			if (limb !== null)
			{
				// For each LIMB we're going to look for overlapping LIMBs.
				
				overlappingLimbs = [];
				
				// Remove the original LIMB from the array now.
				// Otherwise we will encounter infinite recursion when we look for LIMBs that overlap the overlapping LIMBs.
				moveLimbIntoOverlappingArray( limb, i );
				
				lookForOverlappingLimbs( limb );
				
				if (overlappingLimbs.length === 1)
				{
					// No overlapping LIMBs. The basic position is fine.
					
					limb.element.css( "left", limb.position.x );
					limb.element.css( "top", limb.position.y );
				}
				else
				{
					computeZIndexDistanceRatio();
					
					for (var j=0; j<overlappingLimbs.length; j++)
					{
						var overlappingLimb = overlappingLimbs[j];
						
						overlappingLimb.element.css( "left", overlappingLimb.position.x );
						overlappingLimb.element.css( "top", overlappingLimb.position.y );
						overlappingLimb.element.css( "zIndex", computeLimbElementZIndex( overlappingLimb.distance ) );
					}
				}
			}
		}
		
		limbs = null;
		
		super_.complete();
		
		
		function lookForOverlappingLimbs( limb )
		{
			for (var i=0; i<limbs.length; i++)
			{
				var otherLimb = limbs[i];
				if (otherLimb !== null)
				{
					if (isOverlappingLimb( limb.element, otherLimb.element ))
					{
						moveLimbIntoOverlappingArray( otherLimb, i );
						
						lookForOverlappingLimbs( otherLimb );
					}
				}
			}
		}
		
		function isOverlappingLimb( limb, otherLimb )
		{
			// http://stackoverflow.com/questions/14012766/detecting-whether-two-divs-overlap
		      var x1 = limb.offset().left;
		      var y1 = limb.offset().top;
		      var h1 = limb.outerHeight(true);
		      var w1 = limb.outerWidth(true);
		      var b1 = y1 + h1;
		      var r1 = x1 + w1;
		      var x2 = otherLimb.offset().left;
		      var y2 = otherLimb.offset().top;
		      var h2 = otherLimb.outerHeight(true);
		      var w2 = otherLimb.outerWidth(true);
		      var b2 = y2 + h2;
		      var r2 = x2 + w2;

		      if (b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2) return false;
		      return true;
		}
		
		function moveLimbIntoOverlappingArray( limb, limbIndex )
		{
			limbs[limbIndex] = null;
			overlappingLimbs[overlappingLimbs.length] = limb;
		}
		
		function computeZIndexDistanceRatio()
		{
			var maxDistance = 0;
			
			for (var i=0; i<overlappingLimbs.length; i++)
			{
				var limb = overlappingLimbs[i];
				
				limb.distance = google.maps.geometry.spherical.computeDistanceBetween( limb.mapDetails.viewCentre, limb.mapDetails.targetLocation );
				
				if (limb.distance > maxDistance)
				{
					maxDistance = limb.distance;
				}
			}
			
			zIndexDistanceRatio = zIndexRange / maxDistance;
		}
		
		function computeLimbElementZIndex( distance )
		{
			return Math.floor( zIndexMax - (zIndexDistanceRatio * distance) );
		}
	};
	
};


/**
 * @type {object}
 * @augments lucid.maps.limbs.layout.LayoutStrategyOptions
 */
lucid.maps.limbs.layout.ZShiftedLayoutStrategyOptions = {};