LeftAxisLayout.js revision cc21b565833307c2b0b06deb4e3ab22c2a94be3e
/**
* Algorithmic strategy for rendering a left axis.
*
* @class LeftAxisLayout
* @extends Base
* @param {Object} config
* @constructor
*/
function LeftAxisLayout(config)
{
LeftAxisLayout.superclass.constructor.apply(this, arguments);
}
LeftAxisLayout.ATTRS = {
/**
* Reference to the <code>Axis</code> using the strategy.
*
* @attribute axisRenderer
* @type Axis
* @protected
*/
axisRenderer: {
value: null
},
/**
* @private
*/
maxLabelSize: {
value: 0
}
};
Y.extend(LeftAxisLayout, Y.Base, {
/**
* Sets the length of the tick on either side of the axis line.
*
* @method setTickOffset
* @protected
*/
setTickOffsets: function()
{
var ar = this.get("axisRenderer"),
majorTicks = ar.get("styles").majorTicks,
tickLength = majorTicks.length,
halfTick = tickLength * 0.5,
display = majorTicks.display;
ar.set("topTickOffset", 0);
ar.set("bottomTickOffset", 0);
switch(display)
{
case "inside" :
ar.set("rightTickOffset", tickLength);
ar.set("leftTickOffset", 0);
break;
case "outside" :
ar.set("rightTickOffset", 0);
ar.set("leftTickOffset", tickLength);
break;
case "cross":
ar.set("rightTickOffset", halfTick);
ar.set("leftTickOffset", halfTick);
break;
default:
ar.set("rightTickOffset", 0);
ar.set("leftTickOffset", 0);
break;
}
},
/**
* Draws a tick
*
* @method drawTick
* @param {Object} pt Point on the axis in which the tick will intersect.
* @param {Object) tickStyle Hash of properties to apply to the tick.
* @protected
*/
drawTick: function(pt, tickStyles)
{
var ar = this.get("axisRenderer"),
style = ar.get("styles"),
padding = style.padding,
tickLength = tickStyles.length,
start = {x:padding.left, y:pt.y},
end = {x:tickLength + padding.left, y:pt.y};
ar.drawLine(start, end, tickStyles);
},
/**
* Calculates the coordinates for the first point on an axis.
*
* @method getLineStart
* @return {Object}
* @protected
*/
getLineStart: function()
{
var ar = this.get("axisRenderer"),
style = ar.get("styles"),
padding = style.padding,
majorTicks = style.majorTicks,
tickLength = majorTicks.length,
display = majorTicks.display,
pt = {x:padding.left, y:0};
if(display === "outside")
{
pt.x += tickLength;
}
else if(display === "cross")
{
pt.x += tickLength/2;
}
return pt;
},
/**
* Calculates the point for a label.
*
* @method getLabelPoint
* @param {Object} point Point on the axis in which the tick will intersect.
* @return {Object}
* @protected
*/
getLabelPoint: function(point)
{
var ar = this.get("axisRenderer");
return {x:point.x - ar.get("leftTickOffset"), y:point.y};
},
/**
* Updates the value for the <code>maxLabelSize</code> for use in calculating total size.
*
* @method updateMaxLabelSize
* @param {HTMLElement} label to measure
* @protected
*/
updateMaxLabelSize: function(label)
{
var ar = this.get("axisRenderer"),
style = ar.get("styles").label,
rot = Math.min(90, Math.max(-90, style.rotation)),
absRot = Math.abs(rot),
radCon = Math.PI/180,
sinRadians = parseFloat(parseFloat(Math.sin(absRot * radCon)).toFixed(8)),
cosRadians = parseFloat(parseFloat(Math.cos(absRot * radCon)).toFixed(8)),
m11 = cosRadians,
m12 = rot > 0 ? -sinRadians : sinRadians,
m21 = -m12,
m22 = m11,
max;
if(!document.createElementNS)
{
label.style.filter = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + m11 + ' M12=' + m12 + ' M21=' + m21 + ' M22=' + m22 + ' sizingMethod="auto expand")';
this.set("maxLabelSize", Math.max(this.get("maxLabelSize"), label.offsetWidth));
}
else
{
label.style.msTransform = "rotate(0deg)";
if(rot === 0)
{
max = label.offsetWidth;
}
else if(absRot === 90)
{
max = label.offsetHeight;
}
else
{
max = (cosRadians * label.offsetWidth) + (sinRadians * label.offsetHeight);
}
this.set("maxLabelSize", Math.max(this.get("maxLabelSize"), max));
}
},
/**
* Rotate and position labels.
*
* @method positionLabel
* @param {HTMLElement} label to rotate position
* @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
* against.
* @protected
*/
positionLabel: function(label, pt)
{
var ar = this.get("axisRenderer"),
tickOffset = ar.get("leftTickOffset"),
style = ar.get("styles").label,
labelAlpha = style.alpha,
filterString,
margin = 0,
leftOffset = pt.x,
topOffset = pt.y,
rot = Math.min(90, Math.max(-90, style.rotation)),
absRot = Math.abs(rot),
radCon = Math.PI/180,
sinRadians = parseFloat(parseFloat(Math.sin(absRot * radCon)).toFixed(8)),
cosRadians = parseFloat(parseFloat(Math.cos(absRot * radCon)).toFixed(8)),
m11 = cosRadians,
m12 = rot > 0 ? -sinRadians : sinRadians,
m21 = -m12,
m22 = m11,
maxLabelSize = this.get("maxLabelSize"),
labelWidth = Math.round(label.offsetWidth),
labelHeight = Math.round(label.offsetHeight);
if(style.margin && style.margin.right)
{
margin = style.margin.right;
}
if(!document.createElementNS)
{
label.style.filter = null;
labelWidth = Math.round(label.offsetWidth);
labelHeight = Math.round(label.offsetHeight);
if(rot === 0)
{
leftOffset = labelWidth;
topOffset -= labelHeight * 0.5;
}
else if(absRot === 90)
{
leftOffset = labelHeight;
topOffset -= labelWidth * 0.5;
}
else if(rot > 0)
{
leftOffset = (cosRadians * labelWidth) + (labelHeight * rot/90);
topOffset -= (sinRadians * labelWidth) + (cosRadians * (labelHeight * 0.5));
}
else
{
leftOffset = (cosRadians * labelWidth) + (absRot/90 * labelHeight);
topOffset -= cosRadians * (labelHeight * 0.5);
}
leftOffset += tickOffset;
label.style.left = ((pt.x + maxLabelSize) - leftOffset) + "px";
label.style.top = topOffset + "px";
if(filterString)
{
filterString += " ";
}
if(Y.Lang.isNumber(labelAlpha) && labelAlpha < 1 && labelAlpha > -1 && !isNaN(labelAlpha))
{
filterString = "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + Math.round(labelAlpha * 100) + ")";
}
if(rot !== 0)
{
if(filterString)
{
filterString += " ";
}
else
{
filterString = "";
}
filterString += 'progid:DXImageTransform.Microsoft.Matrix(M11=' + m11 + ' M12=' + m12 + ' M21=' + m21 + ' M22=' + m22 + ' sizingMethod="auto expand")';
}
if(filterString)
{
label.style.filter = filterString;
}
return;
}
label.style.msTransform = "rotate(0deg)";
labelWidth = Math.round(label.offsetWidth);
labelHeight = Math.round(label.offsetHeight);
if(rot === 0)
{
leftOffset -= labelWidth;
topOffset -= labelHeight * 0.5;
}
else if(rot === 90)
{
topOffset -= labelWidth * 0.5;
}
else if(rot === -90)
{
leftOffset -= labelHeight;
topOffset += labelWidth * 0.5;
}
else
{
if(rot < 0)
{
leftOffset -= (cosRadians * labelWidth) + (sinRadians * labelHeight);
topOffset += (sinRadians * labelWidth) - (cosRadians * (labelHeight * 0.6));
}
else
{
leftOffset -= (cosRadians * labelWidth);
topOffset -= (sinRadians * labelWidth) + (cosRadians * (labelHeight * 0.6));
}
}
leftOffset -= tickOffset;
label.style.left = (this.get("maxLabelSize") + leftOffset) + "px";
label.style.top = topOffset + "px";
label.style.MozTransformOrigin = "0 0";
label.style.MozTransform = "rotate(" + rot + "deg)";
label.style.webkitTransformOrigin = "0 0";
label.style.webkitTransform = "rotate(" + rot + "deg)";
label.style.msTransformOrigin = "0 0";
label.style.msTransform = "rotate(" + rot + "deg)";
label.style.OTransformOrigin = "0 0";
label.style.OTransform = "rotate(" + rot + "deg)";
},
/**
* @protected
*
* Calculates the size and positions the content elements.
*
* @method setSizeAndPosition
* @protected
*/
setSizeAndPosition: function()
{
var labelSize = this.get("maxLabelSize"),
ar = this.get("axisRenderer"),
style = ar.get("styles"),
leftTickOffset = ar.get("leftTickOffset"),
sz = labelSize + leftTickOffset,
path = ar.get("graphic"),
margin = style.label.margin;
if(margin && margin.right)
{
sz += margin.right;
}
sz = Math.round(sz);
ar.set("width", sz);
ar.get("contentBox").setStyle("width", sz);
path.set("x", labelSize + margin.right);
},
/**
* Adjust the position of the Axis widget's content box for internal axes.
*
* @method offsetNodeForTick
* @param {Node} cb Content box of the Axis.
* @protected
*/
offsetNodeForTick: function(cb)
{
},
/**
* Sets the width of the axis based on its contents.
*
* @method setCalculatedSize
* @protected
*/
setCalculatedSize: function()
{
var ar = this.get("axisRenderer"),
style = ar.get("styles"),
label = style.label,
tickOffset = ar.get("leftTickOffset"),
max = this.get("maxLabelSize"),
ttl = Math.round(tickOffset + max + label.margin.right);
ar.get("contentBox").setStyle("width", ttl);
ar.set("width", ttl);
}
});
Y.LeftAxisLayout = LeftAxisLayout;