/**
* @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 = {};