You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3180 lines
92 KiB
3180 lines
92 KiB
/*
|
|
YUI 3.17.2 (build 9c3c78e)
|
|
Copyright 2014 Yahoo! Inc. All rights reserved.
|
|
Licensed under the BSD License.
|
|
http://yuilibrary.com/license/
|
|
*/
|
|
|
|
YUI.add('axis', function (Y, NAME) {
|
|
|
|
/**
|
|
* Provides base functionality for drawing chart axes.
|
|
*
|
|
* @module charts
|
|
* @submodule axis
|
|
*/
|
|
var CONFIG = Y.config,
|
|
DOCUMENT = CONFIG.doc,
|
|
Y_Lang = Y.Lang,
|
|
IS_STRING = Y_Lang.isString,
|
|
Y_DOM = Y.DOM,
|
|
LeftAxisLayout,
|
|
RightAxisLayout,
|
|
BottomAxisLayout,
|
|
TopAxisLayout;
|
|
/**
|
|
* Algorithmic strategy for rendering a left axis.
|
|
*
|
|
* @class LeftAxisLayout
|
|
* @constructor
|
|
* @submodule axis
|
|
*/
|
|
LeftAxisLayout = function() {};
|
|
|
|
LeftAxisLayout.prototype = {
|
|
/**
|
|
* Default margins for text fields.
|
|
*
|
|
* @private
|
|
* @method _getDefaultMargins
|
|
* @return Object
|
|
*/
|
|
_getDefaultMargins: function()
|
|
{
|
|
return {
|
|
top: 0,
|
|
left: 0,
|
|
right: 4,
|
|
bottom: 0
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Sets the length of the tick on either side of the axis line.
|
|
*
|
|
* @method setTickOffset
|
|
* @protected
|
|
*/
|
|
setTickOffsets: function()
|
|
{
|
|
var host = this,
|
|
majorTicks = host.get("styles").majorTicks,
|
|
tickLength = majorTicks.length,
|
|
halfTick = tickLength * 0.5,
|
|
display = majorTicks.display;
|
|
host.set("topTickOffset", 0);
|
|
host.set("bottomTickOffset", 0);
|
|
|
|
switch(display)
|
|
{
|
|
case "inside" :
|
|
host.set("rightTickOffset", tickLength);
|
|
host.set("leftTickOffset", 0);
|
|
break;
|
|
case "outside" :
|
|
host.set("rightTickOffset", 0);
|
|
host.set("leftTickOffset", tickLength);
|
|
break;
|
|
case "cross":
|
|
host.set("rightTickOffset", halfTick);
|
|
host.set("leftTickOffset", halfTick);
|
|
break;
|
|
default:
|
|
host.set("rightTickOffset", 0);
|
|
host.set("leftTickOffset", 0);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Draws a tick
|
|
*
|
|
* @method drawTick
|
|
* @param {Path} path reference to the path `Path` element in which to draw the tick.
|
|
* @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(path, pt, tickStyles)
|
|
{
|
|
var host = this,
|
|
style = host.get("styles"),
|
|
padding = style.padding,
|
|
tickLength = tickStyles.length,
|
|
start = {x:padding.left, y:pt.y},
|
|
end = {x:tickLength + padding.left, y:pt.y};
|
|
host.drawLine(path, start, end);
|
|
},
|
|
|
|
/**
|
|
* Calculates the coordinates for the first point on an axis.
|
|
*
|
|
* @method getLineStart
|
|
* @return {Object}
|
|
* @protected
|
|
*/
|
|
getLineStart: function()
|
|
{
|
|
var style = this.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)
|
|
{
|
|
return {x:point.x - this.get("leftTickOffset"), y:point.y};
|
|
},
|
|
|
|
/**
|
|
* Updates the value for the `maxLabelSize` for use in calculating total size.
|
|
*
|
|
* @method updateMaxLabelSize
|
|
* @param {HTMLElement} label to measure
|
|
* @protected
|
|
*/
|
|
updateMaxLabelSize: function(labelWidth, labelHeight)
|
|
{
|
|
var host = this,
|
|
props = this._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
sinRadians = props.sinRadians,
|
|
cosRadians = props.cosRadians,
|
|
max;
|
|
if(rot === 0)
|
|
{
|
|
max = labelWidth;
|
|
}
|
|
else if(absRot === 90)
|
|
{
|
|
max = labelHeight;
|
|
}
|
|
else
|
|
{
|
|
max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
|
|
}
|
|
host._maxLabelSize = Math.max(host._maxLabelSize, max);
|
|
},
|
|
|
|
/**
|
|
* Determines the available label width when the axis width has been explicitly set.
|
|
*
|
|
* @method getExplicitlySized
|
|
* @return Boolean
|
|
* @protected
|
|
*/
|
|
getExplicitlySized: function(styles)
|
|
{
|
|
if(this._explicitWidth)
|
|
{
|
|
var host = this,
|
|
w = host._explicitWidth,
|
|
totalTitleSize = host._totalTitleSize,
|
|
leftTickOffset = host.get("leftTickOffset"),
|
|
margin = styles.label.margin.right;
|
|
host._maxLabelSize = w - (leftTickOffset + margin + totalTitleSize);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Rotate and position title.
|
|
*
|
|
* @method positionTitle
|
|
* @param {HTMLElement} label to rotate position
|
|
* @protected
|
|
*/
|
|
positionTitle: function(label)
|
|
{
|
|
var host = this,
|
|
bounds = host._titleBounds,
|
|
margin = host.get("styles").title.margin,
|
|
props = host._titleRotationProps,
|
|
w = bounds.right - bounds.left,
|
|
labelWidth = label.offsetWidth,
|
|
labelHeight = label.offsetHeight,
|
|
x = (labelWidth * -0.5) + (w * 0.5),
|
|
y = (host.get("height") * 0.5) - (labelHeight * 0.5);
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
if(margin && margin.left)
|
|
{
|
|
x += margin.left;
|
|
}
|
|
props.x = x;
|
|
props.y = y;
|
|
props.transformOrigin = [0.5, 0.5];
|
|
host._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* 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, styles, i)
|
|
{
|
|
var host = this,
|
|
offset = parseFloat(styles.label.offset),
|
|
tickOffset = host.get("leftTickOffset"),
|
|
totalTitleSize = this._totalTitleSize,
|
|
leftOffset = pt.x + totalTitleSize - tickOffset,
|
|
topOffset = pt.y,
|
|
props = this._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
maxLabelSize = host._maxLabelSize,
|
|
labelWidth = this._labelWidths[i],
|
|
labelHeight = this._labelHeights[i];
|
|
if(rot === 0)
|
|
{
|
|
leftOffset -= labelWidth;
|
|
topOffset -= labelHeight * offset;
|
|
}
|
|
else if(rot === 90)
|
|
{
|
|
leftOffset -= labelWidth * 0.5;
|
|
topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
|
|
}
|
|
else if(rot === -90)
|
|
{
|
|
leftOffset -= labelWidth * 0.5;
|
|
topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
|
|
}
|
|
else
|
|
{
|
|
leftOffset -= labelWidth + (labelHeight * absRot/360);
|
|
topOffset -= labelHeight * offset;
|
|
}
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
props.x = Math.round(maxLabelSize + leftOffset);
|
|
props.y = Math.round(topOffset);
|
|
this._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* Adjusts the coordinates of an axis label based on the rotation.
|
|
*
|
|
* @method _setRotationCoords
|
|
* @param {Object} props Coordinates, dimension and rotation properties of the label.
|
|
* @protected
|
|
*/
|
|
_setRotationCoords: function(props)
|
|
{
|
|
var rot = props.rot,
|
|
absRot = props.absRot,
|
|
leftOffset,
|
|
topOffset,
|
|
labelWidth = props.labelWidth,
|
|
labelHeight = props.labelHeight;
|
|
if(rot === 0)
|
|
{
|
|
leftOffset = labelWidth;
|
|
topOffset = labelHeight * 0.5;
|
|
}
|
|
else if(rot === 90)
|
|
{
|
|
topOffset = 0;
|
|
leftOffset = labelWidth * 0.5;
|
|
}
|
|
else if(rot === -90)
|
|
{
|
|
leftOffset = labelWidth * 0.5;
|
|
topOffset = labelHeight;
|
|
}
|
|
else
|
|
{
|
|
leftOffset = labelWidth + (labelHeight * absRot/360);
|
|
topOffset = labelHeight * 0.5;
|
|
}
|
|
props.x -= leftOffset;
|
|
props.y -= topOffset;
|
|
},
|
|
|
|
/**
|
|
* Returns the transformOrigin to use for an axis label based on the position of the axis
|
|
* and the rotation of the label.
|
|
*
|
|
* @method _getTransformOrigin
|
|
* @param {Number} rot The rotation (in degrees) of the label.
|
|
* @return Array
|
|
* @protected
|
|
*/
|
|
_getTransformOrigin: function(rot)
|
|
{
|
|
var transformOrigin;
|
|
if(rot === 0)
|
|
{
|
|
transformOrigin = [0, 0];
|
|
}
|
|
else if(rot === 90)
|
|
{
|
|
transformOrigin = [0.5, 0];
|
|
}
|
|
else if(rot === -90)
|
|
{
|
|
transformOrigin = [0.5, 1];
|
|
}
|
|
else
|
|
{
|
|
transformOrigin = [1, 0.5];
|
|
}
|
|
return transformOrigin;
|
|
},
|
|
|
|
/**
|
|
* Adjust the position of the Axis widget's content box for internal axes.
|
|
*
|
|
* @method offsetNodeForTick
|
|
* @param {Node} cb contentBox of the axis
|
|
* @protected
|
|
*/
|
|
offsetNodeForTick: function()
|
|
{
|
|
},
|
|
|
|
/**
|
|
* Sets the width of the axis based on its contents.
|
|
*
|
|
* @method setCalculatedSize
|
|
* @protected
|
|
*/
|
|
setCalculatedSize: function()
|
|
{
|
|
var host = this,
|
|
graphic = this.get("graphic"),
|
|
style = host.get("styles"),
|
|
label = style.label,
|
|
tickOffset = host.get("leftTickOffset"),
|
|
max = host._maxLabelSize,
|
|
totalTitleSize = this._totalTitleSize,
|
|
ttl = Math.round(totalTitleSize + tickOffset + max + label.margin.right);
|
|
if(this._explicitWidth)
|
|
{
|
|
ttl = this._explicitWidth;
|
|
}
|
|
this.set("calculatedWidth", ttl);
|
|
graphic.set("x", ttl - tickOffset);
|
|
}
|
|
};
|
|
|
|
Y.LeftAxisLayout = LeftAxisLayout;
|
|
/**
|
|
* RightAxisLayout contains algorithms for rendering a right axis.
|
|
*
|
|
* @class RightAxisLayout
|
|
* @constructor
|
|
* @submodule axis
|
|
*/
|
|
RightAxisLayout = function(){};
|
|
|
|
RightAxisLayout.prototype = {
|
|
/**
|
|
* Default margins for text fields.
|
|
*
|
|
* @private
|
|
* @method _getDefaultMargins
|
|
* @return Object
|
|
*/
|
|
_getDefaultMargins: function()
|
|
{
|
|
return {
|
|
top: 0,
|
|
left: 4,
|
|
right: 0,
|
|
bottom: 0
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Sets the length of the tick on either side of the axis line.
|
|
*
|
|
* @method setTickOffset
|
|
* @protected
|
|
*/
|
|
setTickOffsets: function()
|
|
{
|
|
var host = this,
|
|
majorTicks = host.get("styles").majorTicks,
|
|
tickLength = majorTicks.length,
|
|
halfTick = tickLength * 0.5,
|
|
display = majorTicks.display;
|
|
host.set("topTickOffset", 0);
|
|
host.set("bottomTickOffset", 0);
|
|
|
|
switch(display)
|
|
{
|
|
case "inside" :
|
|
host.set("leftTickOffset", tickLength);
|
|
host.set("rightTickOffset", 0);
|
|
break;
|
|
case "outside" :
|
|
host.set("leftTickOffset", 0);
|
|
host.set("rightTickOffset", tickLength);
|
|
break;
|
|
case "cross" :
|
|
host.set("rightTickOffset", halfTick);
|
|
host.set("leftTickOffset", halfTick);
|
|
break;
|
|
default:
|
|
host.set("leftTickOffset", 0);
|
|
host.set("rightTickOffset", 0);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Draws a tick
|
|
*
|
|
* @method drawTick
|
|
* @param {Path} path reference to the path `Path` element in which to draw the tick.
|
|
* @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(path, pt, tickStyles)
|
|
{
|
|
var host = this,
|
|
style = host.get("styles"),
|
|
padding = style.padding,
|
|
tickLength = tickStyles.length,
|
|
start = {x:padding.left, y:pt.y},
|
|
end = {x:padding.left + tickLength, y:pt.y};
|
|
host.drawLine(path, start, end);
|
|
},
|
|
|
|
/**
|
|
* Calculates the coordinates for the first point on an axis.
|
|
*
|
|
* @method getLineStart
|
|
* @return {Object}
|
|
* @protected
|
|
*/
|
|
getLineStart: function()
|
|
{
|
|
var host = this,
|
|
style = host.get("styles"),
|
|
padding = style.padding,
|
|
majorTicks = style.majorTicks,
|
|
tickLength = majorTicks.length,
|
|
display = majorTicks.display,
|
|
pt = {x:padding.left, y:padding.top};
|
|
if(display === "inside")
|
|
{
|
|
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)
|
|
{
|
|
return {x:point.x + this.get("rightTickOffset"), y:point.y};
|
|
},
|
|
|
|
/**
|
|
* Updates the value for the `maxLabelSize` for use in calculating total size.
|
|
*
|
|
* @method updateMaxLabelSize
|
|
* @param {HTMLElement} label to measure
|
|
* @protected
|
|
*/
|
|
updateMaxLabelSize: function(labelWidth, labelHeight)
|
|
{
|
|
var host = this,
|
|
props = this._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
sinRadians = props.sinRadians,
|
|
cosRadians = props.cosRadians,
|
|
max;
|
|
if(rot === 0)
|
|
{
|
|
max = labelWidth;
|
|
}
|
|
else if(absRot === 90)
|
|
{
|
|
max = labelHeight;
|
|
}
|
|
else
|
|
{
|
|
max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
|
|
}
|
|
host._maxLabelSize = Math.max(host._maxLabelSize, max);
|
|
},
|
|
|
|
/**
|
|
* Determines the available label width when the axis width has been explicitly set.
|
|
*
|
|
* @method getExplicitlySized
|
|
* @return Boolean
|
|
* @protected
|
|
*/
|
|
getExplicitlySized: function(styles)
|
|
{
|
|
if(this._explicitWidth)
|
|
{
|
|
var host = this,
|
|
w = host._explicitWidth,
|
|
totalTitleSize = this._totalTitleSize,
|
|
rightTickOffset = host.get("rightTickOffset"),
|
|
margin = styles.label.margin.right;
|
|
host._maxLabelSize = w - (rightTickOffset + margin + totalTitleSize);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Rotate and position title.
|
|
*
|
|
* @method positionTitle
|
|
* @param {HTMLElement} label to rotate position
|
|
* @protected
|
|
*/
|
|
positionTitle: function(label)
|
|
{
|
|
var host = this,
|
|
bounds = host._titleBounds,
|
|
margin = host.get("styles").title.margin,
|
|
props = host._titleRotationProps,
|
|
labelWidth = label.offsetWidth,
|
|
labelHeight = label.offsetHeight,
|
|
w = bounds.right - bounds.left,
|
|
x = this.get("width") - (labelWidth * 0.5) - (w * 0.5),
|
|
y = (host.get("height") * 0.5) - (labelHeight * 0.5);
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
if(margin && margin.right)
|
|
{
|
|
x -= margin.left;
|
|
}
|
|
props.x = x;
|
|
props.y = y;
|
|
props.transformOrigin = [0.5, 0.5];
|
|
host._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* 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, styles, i)
|
|
{
|
|
var host = this,
|
|
offset = parseFloat(styles.label.offset),
|
|
tickOffset = host.get("rightTickOffset"),
|
|
labelStyles = styles.label,
|
|
margin = 0,
|
|
leftOffset = pt.x,
|
|
topOffset = pt.y,
|
|
props = this._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
labelWidth = this._labelWidths[i],
|
|
labelHeight = this._labelHeights[i];
|
|
if(labelStyles.margin && labelStyles.margin.left)
|
|
{
|
|
margin = labelStyles.margin.left;
|
|
}
|
|
if(rot === 0)
|
|
{
|
|
topOffset -= labelHeight * offset;
|
|
}
|
|
else if(rot === 90)
|
|
{
|
|
leftOffset -= labelWidth * 0.5;
|
|
topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
|
|
}
|
|
else if(rot === -90)
|
|
{
|
|
topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
|
|
leftOffset -= labelWidth * 0.5;
|
|
}
|
|
else
|
|
{
|
|
topOffset -= labelHeight * offset;
|
|
leftOffset += labelHeight/2 * absRot/90;
|
|
}
|
|
leftOffset += margin;
|
|
leftOffset += tickOffset;
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
props.x = Math.round(leftOffset);
|
|
props.y = Math.round(topOffset);
|
|
this._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* Adjusts the coordinates of an axis label based on the rotation.
|
|
*
|
|
* @method _setRotationCoords
|
|
* @param {Object} props Coordinates, dimension and rotation properties of the label.
|
|
* @protected
|
|
*/
|
|
_setRotationCoords: function(props)
|
|
{
|
|
var rot = props.rot,
|
|
absRot = props.absRot,
|
|
leftOffset = 0,
|
|
topOffset = 0,
|
|
labelWidth = props.labelWidth,
|
|
labelHeight = props.labelHeight;
|
|
if(rot === 0)
|
|
{
|
|
topOffset = labelHeight * 0.5;
|
|
}
|
|
else if(rot === 90)
|
|
{
|
|
leftOffset = labelWidth * 0.5;
|
|
topOffset = labelHeight;
|
|
}
|
|
else if(rot === -90)
|
|
{
|
|
leftOffset = labelWidth * 0.5;
|
|
}
|
|
else
|
|
{
|
|
topOffset = labelHeight * 0.5;
|
|
leftOffset = labelHeight/2 * absRot/90;
|
|
}
|
|
props.x -= leftOffset;
|
|
props.y -= topOffset;
|
|
},
|
|
|
|
/**
|
|
* Returns the transformOrigin to use for an axis label based on the position of the axis
|
|
* and the rotation of the label.
|
|
*
|
|
* @method _getTransformOrigin
|
|
* @param {Number} rot The rotation (in degrees) of the label.
|
|
* @return Array
|
|
* @protected
|
|
*/
|
|
_getTransformOrigin: function(rot)
|
|
{
|
|
var transformOrigin;
|
|
if(rot === 0)
|
|
{
|
|
transformOrigin = [0, 0];
|
|
}
|
|
else if(rot === 90)
|
|
{
|
|
transformOrigin = [0.5, 1];
|
|
}
|
|
else if(rot === -90)
|
|
{
|
|
transformOrigin = [0.5, 0];
|
|
}
|
|
else
|
|
{
|
|
transformOrigin = [0, 0.5];
|
|
}
|
|
return transformOrigin;
|
|
},
|
|
|
|
/**
|
|
* Adjusts position for inner ticks.
|
|
*
|
|
* @method offsetNodeForTick
|
|
* @param {Node} cb contentBox of the axis
|
|
* @protected
|
|
*/
|
|
offsetNodeForTick: function(cb)
|
|
{
|
|
var host = this,
|
|
tickOffset = host.get("leftTickOffset"),
|
|
offset = 0 - tickOffset;
|
|
cb.setStyle("left", offset);
|
|
},
|
|
|
|
/**
|
|
* Assigns a height based on the size of the contents.
|
|
*
|
|
* @method setCalculatedSize
|
|
* @protected
|
|
*/
|
|
setCalculatedSize: function()
|
|
{
|
|
var host = this,
|
|
styles = host.get("styles"),
|
|
labelStyle = styles.label,
|
|
totalTitleSize = this._totalTitleSize,
|
|
ttl = Math.round(host.get("rightTickOffset") + host._maxLabelSize + totalTitleSize + labelStyle.margin.left);
|
|
if(this._explicitWidth)
|
|
{
|
|
ttl = this._explicitWidth;
|
|
}
|
|
host.set("calculatedWidth", ttl);
|
|
host.get("contentBox").setStyle("width", ttl);
|
|
}
|
|
};
|
|
|
|
Y.RightAxisLayout = RightAxisLayout;
|
|
/**
|
|
* Contains algorithms for rendering a bottom axis.
|
|
*
|
|
* @class BottomAxisLayout
|
|
* @Constructor
|
|
* @submodule axis
|
|
*/
|
|
BottomAxisLayout = function(){};
|
|
|
|
BottomAxisLayout.prototype = {
|
|
/**
|
|
* Default margins for text fields.
|
|
*
|
|
* @private
|
|
* @method _getDefaultMargins
|
|
* @return Object
|
|
*/
|
|
_getDefaultMargins: function()
|
|
{
|
|
return {
|
|
top: 4,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Sets the length of the tick on either side of the axis line.
|
|
*
|
|
* @method setTickOffsets
|
|
* @protected
|
|
*/
|
|
setTickOffsets: function()
|
|
{
|
|
var host = this,
|
|
majorTicks = host.get("styles").majorTicks,
|
|
tickLength = majorTicks.length,
|
|
halfTick = tickLength * 0.5,
|
|
display = majorTicks.display;
|
|
host.set("leftTickOffset", 0);
|
|
host.set("rightTickOffset", 0);
|
|
|
|
switch(display)
|
|
{
|
|
case "inside" :
|
|
host.set("topTickOffset", tickLength);
|
|
host.set("bottomTickOffset", 0);
|
|
break;
|
|
case "outside" :
|
|
host.set("topTickOffset", 0);
|
|
host.set("bottomTickOffset", tickLength);
|
|
break;
|
|
case "cross":
|
|
host.set("topTickOffset", halfTick);
|
|
host.set("bottomTickOffset", halfTick);
|
|
break;
|
|
default:
|
|
host.set("topTickOffset", 0);
|
|
host.set("bottomTickOffset", 0);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Calculates the coordinates for the first point on an axis.
|
|
*
|
|
* @method getLineStart
|
|
* @protected
|
|
*/
|
|
getLineStart: function()
|
|
{
|
|
var style = this.get("styles"),
|
|
padding = style.padding,
|
|
majorTicks = style.majorTicks,
|
|
tickLength = majorTicks.length,
|
|
display = majorTicks.display,
|
|
pt = {x:0, y:padding.top};
|
|
if(display === "inside")
|
|
{
|
|
pt.y += tickLength;
|
|
}
|
|
else if(display === "cross")
|
|
{
|
|
pt.y += tickLength/2;
|
|
}
|
|
return pt;
|
|
},
|
|
|
|
/**
|
|
* Draws a tick
|
|
*
|
|
* @method drawTick
|
|
* @param {Path} path reference to the path `Path` element in which to draw the tick.
|
|
* @param {Object} pt hash containing x and y coordinates
|
|
* @param {Object} tickStyles hash of properties used to draw the tick
|
|
* @protected
|
|
*/
|
|
drawTick: function(path, pt, tickStyles)
|
|
{
|
|
var host = this,
|
|
style = host.get("styles"),
|
|
padding = style.padding,
|
|
tickLength = tickStyles.length,
|
|
start = {x:pt.x, y:padding.top},
|
|
end = {x:pt.x, y:tickLength + padding.top};
|
|
host.drawLine(path, start, end);
|
|
},
|
|
|
|
/**
|
|
* Calculates the point for a label.
|
|
*
|
|
* @method getLabelPoint
|
|
* @param {Object} pt Object containing x and y coordinates
|
|
* @return Object
|
|
* @protected
|
|
*/
|
|
getLabelPoint: function(point)
|
|
{
|
|
return {x:point.x, y:point.y + this.get("bottomTickOffset")};
|
|
},
|
|
|
|
/**
|
|
* Updates the value for the `maxLabelSize` for use in calculating total size.
|
|
*
|
|
* @method updateMaxLabelSize
|
|
* @param {HTMLElement} label to measure
|
|
* @protected
|
|
*/
|
|
updateMaxLabelSize: function(labelWidth, labelHeight)
|
|
{
|
|
var host = this,
|
|
props = this._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
sinRadians = props.sinRadians,
|
|
cosRadians = props.cosRadians,
|
|
max;
|
|
if(rot === 0)
|
|
{
|
|
max = labelHeight;
|
|
}
|
|
else if(absRot === 90)
|
|
{
|
|
max = labelWidth;
|
|
}
|
|
else
|
|
{
|
|
max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
|
|
}
|
|
host._maxLabelSize = Math.max(host._maxLabelSize, max);
|
|
},
|
|
|
|
/**
|
|
* Determines the available label height when the axis width has been explicitly set.
|
|
*
|
|
* @method getExplicitlySized
|
|
* @return Boolean
|
|
* @protected
|
|
*/
|
|
getExplicitlySized: function(styles)
|
|
{
|
|
if(this._explicitHeight)
|
|
{
|
|
var host = this,
|
|
h = host._explicitHeight,
|
|
totalTitleSize = host._totalTitleSize,
|
|
bottomTickOffset = host.get("bottomTickOffset"),
|
|
margin = styles.label.margin.right;
|
|
host._maxLabelSize = h - (bottomTickOffset + margin + totalTitleSize);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Rotate and position title.
|
|
*
|
|
* @method positionTitle
|
|
* @param {HTMLElement} label to rotate position
|
|
* @protected
|
|
*/
|
|
positionTitle: function(label)
|
|
{
|
|
var host = this,
|
|
bounds = host._titleBounds,
|
|
margin = host.get("styles").title.margin,
|
|
props = host._titleRotationProps,
|
|
h = bounds.bottom - bounds.top,
|
|
labelWidth = label.offsetWidth,
|
|
labelHeight = label.offsetHeight,
|
|
x = (host.get("width") * 0.5) - (labelWidth * 0.5),
|
|
y = host.get("height") - labelHeight/2 - h/2;
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
if(margin && margin.bottom)
|
|
{
|
|
y -= margin.bottom;
|
|
}
|
|
props.x = x;
|
|
props.y = y;
|
|
props.transformOrigin = [0.5, 0.5];
|
|
host._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* 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, styles, i)
|
|
{
|
|
var host = this,
|
|
offset = parseFloat(styles.label.offset),
|
|
tickOffset = host.get("bottomTickOffset"),
|
|
labelStyles = styles.label,
|
|
margin = 0,
|
|
props = host._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
leftOffset = Math.round(pt.x),
|
|
topOffset = Math.round(pt.y),
|
|
labelWidth = host._labelWidths[i],
|
|
labelHeight = host._labelHeights[i];
|
|
if(labelStyles.margin && labelStyles.margin.top)
|
|
{
|
|
margin = labelStyles.margin.top;
|
|
}
|
|
if(rot === 90)
|
|
{
|
|
topOffset -= labelHeight/2 * rot/90;
|
|
leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
|
|
}
|
|
else if(rot === -90)
|
|
{
|
|
topOffset -= labelHeight/2 * absRot/90;
|
|
leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
|
|
}
|
|
else if(rot > 0)
|
|
{
|
|
leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
|
|
topOffset -= labelHeight/2 * rot/90;
|
|
}
|
|
else if(rot < 0)
|
|
{
|
|
leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
|
|
topOffset -= labelHeight/2 * absRot/90;
|
|
}
|
|
else
|
|
{
|
|
leftOffset -= labelWidth * offset;
|
|
}
|
|
topOffset += margin;
|
|
topOffset += tickOffset;
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
props.x = leftOffset;
|
|
props.y = topOffset;
|
|
host._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* Adjusts the coordinates of an axis label based on the rotation.
|
|
*
|
|
* @method _setRotationCoords
|
|
* @param {Object} props Coordinates, dimension and rotation properties of the label.
|
|
* @protected
|
|
*/
|
|
_setRotationCoords: function(props)
|
|
{
|
|
var rot = props.rot,
|
|
absRot = props.absRot,
|
|
labelWidth = props.labelWidth,
|
|
labelHeight = props.labelHeight,
|
|
leftOffset,
|
|
topOffset;
|
|
|
|
if(rot > 0)
|
|
{
|
|
leftOffset = 0;
|
|
topOffset = labelHeight/2 * rot/90;
|
|
}
|
|
else if(rot < 0)
|
|
{
|
|
leftOffset = labelWidth;
|
|
topOffset = labelHeight/2 * absRot/90;
|
|
}
|
|
else
|
|
{
|
|
leftOffset = labelWidth * 0.5;
|
|
topOffset = 0;
|
|
}
|
|
props.x -= leftOffset;
|
|
props.y -= topOffset;
|
|
},
|
|
|
|
/**
|
|
* Returns the transformOrigin to use for an axis label based on the position of the axis
|
|
* and the rotation of the label.
|
|
*
|
|
* @method _getTransformOrigin
|
|
* @param {Number} rot The rotation (in degrees) of the label.
|
|
* @return Array
|
|
* @protected
|
|
*/
|
|
_getTransformOrigin: function(rot)
|
|
{
|
|
var transformOrigin;
|
|
if(rot > 0)
|
|
{
|
|
transformOrigin = [0, 0.5];
|
|
}
|
|
else if(rot < 0)
|
|
{
|
|
transformOrigin = [1, 0.5];
|
|
}
|
|
else
|
|
{
|
|
transformOrigin = [0, 0];
|
|
}
|
|
return transformOrigin;
|
|
},
|
|
|
|
/**
|
|
* Adjusts position for inner ticks.
|
|
*
|
|
* @method offsetNodeForTick
|
|
* @param {Node} cb contentBox of the axis
|
|
* @protected
|
|
*/
|
|
offsetNodeForTick: function(cb)
|
|
{
|
|
var host = this;
|
|
cb.setStyle("top", 0 - host.get("topTickOffset"));
|
|
},
|
|
|
|
/**
|
|
* Assigns a height based on the size of the contents.
|
|
*
|
|
* @method setCalculatedSize
|
|
* @protected
|
|
*/
|
|
setCalculatedSize: function()
|
|
{
|
|
var host = this,
|
|
styles = host.get("styles"),
|
|
labelStyle = styles.label,
|
|
totalTitleSize = host._totalTitleSize,
|
|
ttl = Math.round(host.get("bottomTickOffset") + host._maxLabelSize + labelStyle.margin.top + totalTitleSize);
|
|
if(host._explicitHeight)
|
|
{
|
|
ttl = host._explicitHeight;
|
|
}
|
|
host.set("calculatedHeight", ttl);
|
|
}
|
|
};
|
|
Y.BottomAxisLayout = BottomAxisLayout;
|
|
/**
|
|
* Contains algorithms for rendering a top axis.
|
|
*
|
|
* @class TopAxisLayout
|
|
* @constructor
|
|
* @submodule axis
|
|
*/
|
|
TopAxisLayout = function(){};
|
|
|
|
TopAxisLayout.prototype = {
|
|
/**
|
|
* Default margins for text fields.
|
|
*
|
|
* @private
|
|
* @method _getDefaultMargins
|
|
* @return Object
|
|
*/
|
|
_getDefaultMargins: function()
|
|
{
|
|
return {
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 4
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Sets the length of the tick on either side of the axis line.
|
|
*
|
|
* @method setTickOffsets
|
|
* @protected
|
|
*/
|
|
setTickOffsets: function()
|
|
{
|
|
var host = this,
|
|
majorTicks = host.get("styles").majorTicks,
|
|
tickLength = majorTicks.length,
|
|
halfTick = tickLength * 0.5,
|
|
display = majorTicks.display;
|
|
host.set("leftTickOffset", 0);
|
|
host.set("rightTickOffset", 0);
|
|
switch(display)
|
|
{
|
|
case "inside" :
|
|
host.set("bottomTickOffset", tickLength);
|
|
host.set("topTickOffset", 0);
|
|
break;
|
|
case "outside" :
|
|
host.set("bottomTickOffset", 0);
|
|
host.set("topTickOffset", tickLength);
|
|
break;
|
|
case "cross" :
|
|
host.set("topTickOffset", halfTick);
|
|
host.set("bottomTickOffset", halfTick);
|
|
break;
|
|
default:
|
|
host.set("topTickOffset", 0);
|
|
host.set("bottomTickOffset", 0);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Calculates the coordinates for the first point on an axis.
|
|
*
|
|
* @method getLineStart
|
|
* @protected
|
|
*/
|
|
getLineStart: function()
|
|
{
|
|
var host = this,
|
|
style = host.get("styles"),
|
|
padding = style.padding,
|
|
majorTicks = style.majorTicks,
|
|
tickLength = majorTicks.length,
|
|
display = majorTicks.display,
|
|
pt = {x:0, y:padding.top};
|
|
if(display === "outside")
|
|
{
|
|
pt.y += tickLength;
|
|
}
|
|
else if(display === "cross")
|
|
{
|
|
pt.y += tickLength/2;
|
|
}
|
|
return pt;
|
|
},
|
|
|
|
/**
|
|
* Draws a tick
|
|
*
|
|
* @method drawTick
|
|
* @param {Path} path reference to the path `Path` element in which to draw the tick.
|
|
* @param {Object} pt hash containing x and y coordinates
|
|
* @param {Object} tickStyles hash of properties used to draw the tick
|
|
* @protected
|
|
*/
|
|
drawTick: function(path, pt, tickStyles)
|
|
{
|
|
var host = this,
|
|
style = host.get("styles"),
|
|
padding = style.padding,
|
|
tickLength = tickStyles.length,
|
|
start = {x:pt.x, y:padding.top},
|
|
end = {x:pt.x, y:tickLength + padding.top};
|
|
host.drawLine(path, start, end);
|
|
},
|
|
|
|
/**
|
|
* Calculates the point for a label.
|
|
*
|
|
* @method getLabelPoint
|
|
* @param {Object} pt hash containing x and y coordinates
|
|
* @return Object
|
|
* @protected
|
|
*/
|
|
getLabelPoint: function(pt)
|
|
{
|
|
return {x:pt.x, y:pt.y - this.get("topTickOffset")};
|
|
},
|
|
|
|
/**
|
|
* Updates the value for the `maxLabelSize` for use in calculating total size.
|
|
*
|
|
* @method updateMaxLabelSize
|
|
* @param {HTMLElement} label to measure
|
|
* @protected
|
|
*/
|
|
updateMaxLabelSize: function(labelWidth, labelHeight)
|
|
{
|
|
var host = this,
|
|
props = this._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
sinRadians = props.sinRadians,
|
|
cosRadians = props.cosRadians,
|
|
max;
|
|
if(rot === 0)
|
|
{
|
|
max = labelHeight;
|
|
}
|
|
else if(absRot === 90)
|
|
{
|
|
max = labelWidth;
|
|
}
|
|
else
|
|
{
|
|
max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
|
|
}
|
|
host._maxLabelSize = Math.max(host._maxLabelSize, max);
|
|
},
|
|
|
|
/**
|
|
* Determines the available label height when the axis width has been explicitly set.
|
|
*
|
|
* @method getExplicitlySized
|
|
* @return Boolean
|
|
* @protected
|
|
*/
|
|
getExplicitlySized: function(styles)
|
|
{
|
|
if(this._explicitHeight)
|
|
{
|
|
var host = this,
|
|
h = host._explicitHeight,
|
|
totalTitleSize = host._totalTitleSize,
|
|
topTickOffset = host.get("topTickOffset"),
|
|
margin = styles.label.margin.right;
|
|
host._maxLabelSize = h - (topTickOffset + margin + totalTitleSize);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Rotate and position title.
|
|
*
|
|
* @method positionTitle
|
|
* @param {HTMLElement} label to rotate position
|
|
* @protected
|
|
*/
|
|
positionTitle: function(label)
|
|
{
|
|
var host = this,
|
|
bounds = host._titleBounds,
|
|
margin = host.get("styles").title.margin,
|
|
props = host._titleRotationProps,
|
|
labelWidth = label.offsetWidth,
|
|
labelHeight = label.offsetHeight,
|
|
h = bounds.bottom - bounds.top,
|
|
x = (host.get("width") * 0.5) - (labelWidth * 0.5),
|
|
y = h/2 - labelHeight/2;
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
if(margin && margin.top)
|
|
{
|
|
y += margin.top;
|
|
}
|
|
props.x = x;
|
|
props.y = y;
|
|
props.transformOrigin = [0.5, 0.5];
|
|
host._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* 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, styles, i)
|
|
{
|
|
var host = this,
|
|
offset = parseFloat(styles.label.offset),
|
|
totalTitleSize = this._totalTitleSize,
|
|
maxLabelSize = host._maxLabelSize,
|
|
leftOffset = pt.x,
|
|
topOffset = pt.y + totalTitleSize + maxLabelSize,
|
|
props = this._labelRotationProps,
|
|
rot = props.rot,
|
|
absRot = props.absRot,
|
|
labelWidth = this._labelWidths[i],
|
|
labelHeight = this._labelHeights[i];
|
|
if(rot === 0)
|
|
{
|
|
leftOffset -= labelWidth * offset;
|
|
topOffset -= labelHeight;
|
|
}
|
|
else
|
|
{
|
|
if(rot === 90)
|
|
{
|
|
leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
|
|
topOffset -= (labelHeight * 0.5);
|
|
}
|
|
else if (rot === -90)
|
|
{
|
|
leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
|
|
topOffset -= (labelHeight * 0.5);
|
|
}
|
|
else if(rot > 0)
|
|
{
|
|
leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
|
|
topOffset -= labelHeight - (labelHeight * rot/180);
|
|
}
|
|
else
|
|
{
|
|
leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
|
|
topOffset -= labelHeight - (labelHeight * absRot/180);
|
|
}
|
|
}
|
|
props.x = Math.round(leftOffset);
|
|
props.y = Math.round(topOffset);
|
|
props.labelWidth = labelWidth;
|
|
props.labelHeight = labelHeight;
|
|
this._rotate(label, props);
|
|
},
|
|
|
|
/**
|
|
* Adjusts the coordinates of an axis label based on the rotation.
|
|
*
|
|
* @method _setRotationCoords
|
|
* @param {Object} props Coordinates, dimension and rotation properties of the label.
|
|
* @protected
|
|
*/
|
|
_setRotationCoords: function(props)
|
|
{
|
|
var rot = props.rot,
|
|
absRot = props.absRot,
|
|
labelWidth = props.labelWidth,
|
|
labelHeight = props.labelHeight,
|
|
leftOffset,
|
|
topOffset;
|
|
if(rot === 0)
|
|
{
|
|
leftOffset = labelWidth * 0.5;
|
|
topOffset = labelHeight;
|
|
}
|
|
else
|
|
{
|
|
if(rot === 90)
|
|
{
|
|
leftOffset = labelWidth;
|
|
topOffset = (labelHeight * 0.5);
|
|
}
|
|
else if (rot === -90)
|
|
{
|
|
topOffset = (labelHeight * 0.5);
|
|
}
|
|
else if(rot > 0)
|
|
{
|
|
leftOffset = labelWidth;
|
|
topOffset = labelHeight - (labelHeight * rot/180);
|
|
}
|
|
else
|
|
{
|
|
topOffset = labelHeight - (labelHeight * absRot/180);
|
|
}
|
|
}
|
|
props.x -= leftOffset;
|
|
props.y -= topOffset;
|
|
},
|
|
|
|
/**
|
|
* Returns the transformOrigin to use for an axis label based on the position of the axis
|
|
* and the rotation of the label.
|
|
*
|
|
* @method _getTransformOrigin
|
|
* @param {Number} rot The rotation (in degrees) of the label.
|
|
* @return Array
|
|
* @protected
|
|
*/
|
|
_getTransformOrigin: function(rot)
|
|
{
|
|
var transformOrigin;
|
|
if(rot === 0)
|
|
{
|
|
transformOrigin = [0, 0];
|
|
}
|
|
else
|
|
{
|
|
if(rot === 90)
|
|
{
|
|
transformOrigin = [1, 0.5];
|
|
}
|
|
else if (rot === -90)
|
|
{
|
|
transformOrigin = [0, 0.5];
|
|
}
|
|
else if(rot > 0)
|
|
{
|
|
transformOrigin = [1, 0.5];
|
|
}
|
|
else
|
|
{
|
|
transformOrigin = [0, 0.5];
|
|
}
|
|
}
|
|
return transformOrigin;
|
|
},
|
|
|
|
/**
|
|
* Adjusts position for inner ticks.
|
|
*
|
|
* @method offsetNodeForTick
|
|
* @param {Node} cb contentBox of the axis
|
|
* @protected
|
|
*/
|
|
offsetNodeForTick: function()
|
|
{
|
|
},
|
|
|
|
/**
|
|
* Assigns a height based on the size of the contents.
|
|
*
|
|
* @method setCalculatedSize
|
|
* @protected
|
|
*/
|
|
setCalculatedSize: function()
|
|
{
|
|
var host = this,
|
|
graphic = host.get("graphic"),
|
|
styles = host.get("styles"),
|
|
labelMargin = styles.label.margin,
|
|
totalLabelSize = labelMargin.bottom + host._maxLabelSize,
|
|
totalTitleSize = host._totalTitleSize,
|
|
topTickOffset = this.get("topTickOffset"),
|
|
ttl = Math.round(topTickOffset + totalLabelSize + totalTitleSize);
|
|
if(this._explicitHeight)
|
|
{
|
|
ttl = this._explicitHeight;
|
|
}
|
|
host.set("calculatedHeight", ttl);
|
|
graphic.set("y", ttl - topTickOffset);
|
|
}
|
|
};
|
|
Y.TopAxisLayout = TopAxisLayout;
|
|
|
|
/**
|
|
* An abstract class that provides the core functionality for draw a chart axis. Axis is used by the following classes:
|
|
* <ul>
|
|
* <li>{{#crossLink "CategoryAxis"}}{{/crossLink}}</li>
|
|
* <li>{{#crossLink "NumericAxis"}}{{/crossLink}}</li>
|
|
* <li>{{#crossLink "StackedAxis"}}{{/crossLink}}</li>
|
|
* <li>{{#crossLink "TimeAxis"}}{{/crossLink}}</li>
|
|
* </ul>
|
|
*
|
|
* @class Axis
|
|
* @extends Widget
|
|
* @uses AxisBase
|
|
* @uses TopAxisLayout
|
|
* @uses RightAxisLayout
|
|
* @uses BottomAxisLayout
|
|
* @uses LeftAxisLayout
|
|
* @constructor
|
|
* @param {Object} config (optional) Configuration parameters.
|
|
* @submodule axis
|
|
*/
|
|
Y.Axis = Y.Base.create("axis", Y.Widget, [Y.AxisBase], {
|
|
/**
|
|
* Calculates and returns a value based on the number of labels and the index of
|
|
* the current label.
|
|
*
|
|
* @method getLabelByIndex
|
|
* @param {Number} i Index of the label.
|
|
* @param {Number} l Total number of labels.
|
|
* @return String
|
|
*/
|
|
getLabelByIndex: function(i, l)
|
|
{
|
|
var position = this.get("position"),
|
|
direction = position === "left" || position === "right" ? "vertical" : "horizontal";
|
|
return this._getLabelByIndex(i, l, direction);
|
|
},
|
|
|
|
/**
|
|
* @method bindUI
|
|
* @private
|
|
*/
|
|
bindUI: function()
|
|
{
|
|
this.after("dataReady", Y.bind(this._dataChangeHandler, this));
|
|
this.after("dataUpdate", Y.bind(this._dataChangeHandler, this));
|
|
this.after("stylesChange", this._updateHandler);
|
|
this.after("overlapGraphChange", this._updateHandler);
|
|
this.after("positionChange", this._positionChangeHandler);
|
|
this.after("widthChange", this._handleSizeChange);
|
|
this.after("heightChange", this._handleSizeChange);
|
|
this.after("calculatedWidthChange", this._handleSizeChange);
|
|
this.after("calculatedHeightChange", this._handleSizeChange);
|
|
},
|
|
/**
|
|
* Storage for calculatedWidth value.
|
|
*
|
|
* @property _calculatedWidth
|
|
* @type Number
|
|
* @private
|
|
*/
|
|
_calculatedWidth: 0,
|
|
|
|
/**
|
|
* Storage for calculatedHeight value.
|
|
*
|
|
* @property _calculatedHeight
|
|
* @type Number
|
|
* @private
|
|
*/
|
|
_calculatedHeight: 0,
|
|
|
|
/**
|
|
* Handles change to the dataProvider
|
|
*
|
|
* @method _dataChangeHandler
|
|
* @param {Object} e Event object
|
|
* @private
|
|
*/
|
|
_dataChangeHandler: function()
|
|
{
|
|
if(this.get("rendered"))
|
|
{
|
|
this._drawAxis();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Handles change to the position attribute
|
|
*
|
|
* @method _positionChangeHandler
|
|
* @param {Object} e Event object
|
|
* @private
|
|
*/
|
|
_positionChangeHandler: function(e)
|
|
{
|
|
this._updateGraphic(e.newVal);
|
|
this._updateHandler();
|
|
},
|
|
|
|
/**
|
|
* Updates the the Graphic instance
|
|
*
|
|
* @method _updateGraphic
|
|
* @param {String} position Position of axis
|
|
* @private
|
|
*/
|
|
_updateGraphic: function(position)
|
|
{
|
|
var graphic = this.get("graphic");
|
|
if(position === "none")
|
|
{
|
|
if(graphic)
|
|
{
|
|
graphic.destroy();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!graphic)
|
|
{
|
|
this._setCanvas();
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Handles changes to axis.
|
|
*
|
|
* @method _updateHandler
|
|
* @param {Object} e Event object
|
|
* @private
|
|
*/
|
|
_updateHandler: function()
|
|
{
|
|
if(this.get("rendered"))
|
|
{
|
|
this._drawAxis();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @method renderUI
|
|
* @private
|
|
*/
|
|
renderUI: function()
|
|
{
|
|
this._updateGraphic(this.get("position"));
|
|
},
|
|
|
|
/**
|
|
* @method syncUI
|
|
* @private
|
|
*/
|
|
syncUI: function()
|
|
{
|
|
var layout = this._layout,
|
|
defaultMargins,
|
|
styles,
|
|
label,
|
|
title,
|
|
i;
|
|
if(layout)
|
|
{
|
|
defaultMargins = layout._getDefaultMargins();
|
|
styles = this.get("styles");
|
|
label = styles.label.margin;
|
|
title =styles.title.margin;
|
|
//need to defaultMargins method to the layout classes.
|
|
for(i in defaultMargins)
|
|
{
|
|
if(defaultMargins.hasOwnProperty(i))
|
|
{
|
|
label[i] = label[i] === undefined ? defaultMargins[i] : label[i];
|
|
title[i] = title[i] === undefined ? defaultMargins[i] : title[i];
|
|
}
|
|
}
|
|
}
|
|
this._drawAxis();
|
|
},
|
|
|
|
/**
|
|
* Creates a graphic instance to be used for the axis line and ticks.
|
|
*
|
|
* @method _setCanvas
|
|
* @private
|
|
*/
|
|
_setCanvas: function()
|
|
{
|
|
var cb = this.get("contentBox"),
|
|
bb = this.get("boundingBox"),
|
|
p = this.get("position"),
|
|
pn = this._parentNode,
|
|
w = this.get("width"),
|
|
h = this.get("height");
|
|
bb.setStyle("position", "absolute");
|
|
bb.setStyle("zIndex", 2);
|
|
w = w ? w + "px" : pn.getStyle("width");
|
|
h = h ? h + "px" : pn.getStyle("height");
|
|
if(p === "top" || p === "bottom")
|
|
{
|
|
cb.setStyle("width", w);
|
|
}
|
|
else
|
|
{
|
|
cb.setStyle("height", h);
|
|
}
|
|
cb.setStyle("position", "relative");
|
|
cb.setStyle("left", "0px");
|
|
cb.setStyle("top", "0px");
|
|
this.set("graphic", new Y.Graphic());
|
|
this.get("graphic").render(cb);
|
|
},
|
|
|
|
/**
|
|
* Gets the default value for the `styles` attribute. Overrides
|
|
* base implementation.
|
|
*
|
|
* @method _getDefaultStyles
|
|
* @return Object
|
|
* @protected
|
|
*/
|
|
_getDefaultStyles: function()
|
|
{
|
|
var axisstyles = {
|
|
majorTicks: {
|
|
display:"inside",
|
|
length:4,
|
|
color:"#dad8c9",
|
|
weight:1,
|
|
alpha:1
|
|
},
|
|
minorTicks: {
|
|
display:"none",
|
|
length:2,
|
|
color:"#dad8c9",
|
|
weight:1
|
|
},
|
|
line: {
|
|
weight:1,
|
|
color:"#dad8c9",
|
|
alpha:1
|
|
},
|
|
majorUnit: {
|
|
determinant:"count",
|
|
count:11,
|
|
distance:75
|
|
},
|
|
top: "0px",
|
|
left: "0px",
|
|
width: "100px",
|
|
height: "100px",
|
|
label: {
|
|
color:"#808080",
|
|
alpha: 1,
|
|
fontSize:"85%",
|
|
rotation: 0,
|
|
offset: 0.5,
|
|
margin: {
|
|
top: undefined,
|
|
right: undefined,
|
|
bottom: undefined,
|
|
left: undefined
|
|
}
|
|
},
|
|
title: {
|
|
color:"#808080",
|
|
alpha: 1,
|
|
fontSize:"85%",
|
|
rotation: undefined,
|
|
margin: {
|
|
top: undefined,
|
|
right: undefined,
|
|
bottom: undefined,
|
|
left: undefined
|
|
}
|
|
},
|
|
hideOverlappingLabelTicks: false
|
|
};
|
|
|
|
return Y.merge(Y.Renderer.prototype._getDefaultStyles(), axisstyles);
|
|
},
|
|
|
|
/**
|
|
* Updates the axis when the size changes.
|
|
*
|
|
* @method _handleSizeChange
|
|
* @param {Object} e Event object.
|
|
* @private
|
|
*/
|
|
_handleSizeChange: function(e)
|
|
{
|
|
var attrName = e.attrName,
|
|
pos = this.get("position"),
|
|
vert = pos === "left" || pos === "right",
|
|
cb = this.get("contentBox"),
|
|
hor = pos === "bottom" || pos === "top";
|
|
cb.setStyle("width", this.get("width"));
|
|
cb.setStyle("height", this.get("height"));
|
|
if((hor && attrName === "width") || (vert && attrName === "height"))
|
|
{
|
|
this._drawAxis();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Maps key values to classes containing layout algorithms
|
|
*
|
|
* @property _layoutClasses
|
|
* @type Object
|
|
* @private
|
|
*/
|
|
_layoutClasses:
|
|
{
|
|
top : TopAxisLayout,
|
|
bottom: BottomAxisLayout,
|
|
left: LeftAxisLayout,
|
|
right : RightAxisLayout
|
|
},
|
|
|
|
/**
|
|
* Draws a line segment between 2 points
|
|
*
|
|
* @method drawLine
|
|
* @param {Object} startPoint x and y coordinates for the start point of the line segment
|
|
* @param {Object} endPoint x and y coordinates for the for the end point of the line segment
|
|
* @param {Object} line styles (weight, color and alpha to be applied to the line segment)
|
|
* @private
|
|
*/
|
|
drawLine: function(path, startPoint, endPoint)
|
|
{
|
|
path.moveTo(startPoint.x, startPoint.y);
|
|
path.lineTo(endPoint.x, endPoint.y);
|
|
},
|
|
|
|
/**
|
|
* Generates the properties necessary for rotating and positioning a text field.
|
|
*
|
|
* @method _getTextRotationProps
|
|
* @param {Object} styles properties for the text field
|
|
* @return Object
|
|
* @private
|
|
*/
|
|
_getTextRotationProps: function(styles)
|
|
{
|
|
if(styles.rotation === undefined)
|
|
{
|
|
switch(this.get("position"))
|
|
{
|
|
case "left" :
|
|
styles.rotation = -90;
|
|
break;
|
|
case "right" :
|
|
styles.rotation = 90;
|
|
break;
|
|
default :
|
|
styles.rotation = 0;
|
|
break;
|
|
}
|
|
}
|
|
var rot = Math.min(90, Math.max(-90, styles.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));
|
|
return {
|
|
rot: rot,
|
|
absRot: absRot,
|
|
radCon: radCon,
|
|
sinRadians: sinRadians,
|
|
cosRadians: cosRadians,
|
|
textAlpha: styles.alpha
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Draws an axis.
|
|
*
|
|
* @method _drawAxis
|
|
* @private
|
|
*/
|
|
_drawAxis: function ()
|
|
{
|
|
if(this._drawing)
|
|
{
|
|
this._callLater = true;
|
|
return;
|
|
}
|
|
this._drawing = true;
|
|
this._callLater = false;
|
|
if(this._layout)
|
|
{
|
|
var styles = this.get("styles"),
|
|
line = styles.line,
|
|
labelStyles = styles.label,
|
|
majorTickStyles = styles.majorTicks,
|
|
drawTicks = majorTickStyles.display !== "none",
|
|
len,
|
|
i = 0,
|
|
layout = this._layout,
|
|
layoutLength,
|
|
lineStart,
|
|
label,
|
|
labelWidth,
|
|
labelHeight,
|
|
labelFunction = this.get("labelFunction"),
|
|
labelFunctionScope = this.get("labelFunctionScope"),
|
|
labelFormat = this.get("labelFormat"),
|
|
graphic = this.get("graphic"),
|
|
path = this.get("path"),
|
|
tickPath,
|
|
explicitlySized,
|
|
position = this.get("position"),
|
|
labelData,
|
|
labelValues,
|
|
point,
|
|
points,
|
|
firstPoint,
|
|
lastPoint,
|
|
firstLabel,
|
|
lastLabel,
|
|
staticCoord,
|
|
dynamicCoord,
|
|
edgeOffset,
|
|
explicitLabels = this._labelValuesExplicitlySet ? this.get("labelValues") : null,
|
|
direction = (position === "left" || position === "right") ? "vertical" : "horizontal";
|
|
this._labelWidths = [];
|
|
this._labelHeights = [];
|
|
graphic.set("autoDraw", false);
|
|
path.clear();
|
|
path.set("stroke", {
|
|
weight: line.weight,
|
|
color: line.color,
|
|
opacity: line.alpha
|
|
});
|
|
this._labelRotationProps = this._getTextRotationProps(labelStyles);
|
|
this._labelRotationProps.transformOrigin = layout._getTransformOrigin(this._labelRotationProps.rot);
|
|
layout.setTickOffsets.apply(this);
|
|
layoutLength = this.getLength();
|
|
|
|
len = this.getTotalMajorUnits();
|
|
edgeOffset = this.getEdgeOffset(len, layoutLength);
|
|
this.set("edgeOffset", edgeOffset);
|
|
lineStart = layout.getLineStart.apply(this);
|
|
|
|
if(direction === "vertical")
|
|
{
|
|
staticCoord = "x";
|
|
dynamicCoord = "y";
|
|
}
|
|
else
|
|
{
|
|
staticCoord = "y";
|
|
dynamicCoord = "x";
|
|
}
|
|
|
|
labelData = this._getLabelData(
|
|
lineStart[staticCoord],
|
|
staticCoord,
|
|
dynamicCoord,
|
|
this.get("minimum"),
|
|
this.get("maximum"),
|
|
edgeOffset,
|
|
layoutLength - edgeOffset - edgeOffset,
|
|
len,
|
|
explicitLabels
|
|
);
|
|
|
|
points = labelData.points;
|
|
labelValues = labelData.values;
|
|
len = points.length;
|
|
if(!this._labelValuesExplicitlySet)
|
|
{
|
|
this.set("labelValues", labelValues, {src: "internal"});
|
|
}
|
|
|
|
//Don't create the last label or tick.
|
|
if(this.get("hideFirstMajorUnit"))
|
|
{
|
|
firstPoint = points.shift();
|
|
firstLabel = labelValues.shift();
|
|
len = len - 1;
|
|
}
|
|
|
|
//Don't create the last label or tick.
|
|
if(this.get("hideLastMajorUnit"))
|
|
{
|
|
lastPoint = points.pop();
|
|
lastLabel = labelValues.pop();
|
|
len = len - 1;
|
|
}
|
|
|
|
if(len < 1)
|
|
{
|
|
this._clearLabelCache();
|
|
}
|
|
else
|
|
{
|
|
this.drawLine(path, lineStart, this.getLineEnd(lineStart));
|
|
if(drawTicks)
|
|
{
|
|
tickPath = this.get("tickPath");
|
|
tickPath.clear();
|
|
tickPath.set("stroke", {
|
|
weight: majorTickStyles.weight,
|
|
color: majorTickStyles.color,
|
|
opacity: majorTickStyles.alpha
|
|
});
|
|
for(i = 0; i < len; i = i + 1)
|
|
{
|
|
point = points[i];
|
|
if(point)
|
|
{
|
|
layout.drawTick.apply(this, [tickPath, points[i], majorTickStyles]);
|
|
}
|
|
}
|
|
}
|
|
this._createLabelCache();
|
|
this._maxLabelSize = 0;
|
|
this._totalTitleSize = 0;
|
|
this._titleSize = 0;
|
|
this._setTitle();
|
|
explicitlySized = layout.getExplicitlySized.apply(this, [styles]);
|
|
for(i = 0; i < len; i = i + 1)
|
|
{
|
|
point = points[i];
|
|
if(point)
|
|
{
|
|
label = this.getLabel(labelStyles);
|
|
this._labels.push(label);
|
|
this.get("appendLabelFunction")(label, labelFunction.apply(labelFunctionScope, [labelValues[i], labelFormat]));
|
|
labelWidth = Math.round(label.offsetWidth);
|
|
labelHeight = Math.round(label.offsetHeight);
|
|
if(!explicitlySized)
|
|
{
|
|
this._layout.updateMaxLabelSize.apply(this, [labelWidth, labelHeight]);
|
|
}
|
|
this._labelWidths.push(labelWidth);
|
|
this._labelHeights.push(labelHeight);
|
|
}
|
|
}
|
|
this._clearLabelCache();
|
|
if(this.get("overlapGraph"))
|
|
{
|
|
layout.offsetNodeForTick.apply(this, [this.get("contentBox")]);
|
|
}
|
|
layout.setCalculatedSize.apply(this);
|
|
if(this._titleTextField)
|
|
{
|
|
this._layout.positionTitle.apply(this, [this._titleTextField]);
|
|
}
|
|
len = this._labels.length;
|
|
for(i = 0; i < len; ++i)
|
|
{
|
|
layout.positionLabel.apply(this, [this.get("labels")[i], points[i], styles, i]);
|
|
}
|
|
if(firstPoint)
|
|
{
|
|
points.unshift(firstPoint);
|
|
}
|
|
if(lastPoint)
|
|
{
|
|
points.push(lastPoint);
|
|
}
|
|
if(firstLabel)
|
|
{
|
|
labelValues.unshift(firstLabel);
|
|
}
|
|
if(lastLabel)
|
|
{
|
|
labelValues.push(lastLabel);
|
|
}
|
|
this._tickPoints = points;
|
|
}
|
|
}
|
|
this._drawing = false;
|
|
if(this._callLater)
|
|
{
|
|
this._drawAxis();
|
|
}
|
|
else
|
|
{
|
|
this._updatePathElement();
|
|
this.fire("axisRendered");
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Calculates and sets the total size of a title.
|
|
*
|
|
* @method _setTotalTitleSize
|
|
* @param {Object} styles Properties for the title field.
|
|
* @private
|
|
*/
|
|
_setTotalTitleSize: function(styles)
|
|
{
|
|
var title = this._titleTextField,
|
|
w = title.offsetWidth,
|
|
h = title.offsetHeight,
|
|
rot = this._titleRotationProps.rot,
|
|
bounds,
|
|
size,
|
|
margin = styles.margin,
|
|
position = this.get("position"),
|
|
matrix = new Y.Matrix();
|
|
matrix.rotate(rot);
|
|
bounds = matrix.getContentRect(w, h);
|
|
if(position === "left" || position === "right")
|
|
{
|
|
size = bounds.right - bounds.left;
|
|
if(margin)
|
|
{
|
|
size += margin.left + margin.right;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size = bounds.bottom - bounds.top;
|
|
if(margin)
|
|
{
|
|
size += margin.top + margin.bottom;
|
|
}
|
|
}
|
|
this._titleBounds = bounds;
|
|
this._totalTitleSize = size;
|
|
},
|
|
|
|
/**
|
|
* Updates path.
|
|
*
|
|
* @method _updatePathElement
|
|
* @private
|
|
*/
|
|
_updatePathElement: function()
|
|
{
|
|
var path = this._path,
|
|
tickPath = this._tickPath,
|
|
redrawGraphic = false,
|
|
graphic = this.get("graphic");
|
|
if(path)
|
|
{
|
|
redrawGraphic = true;
|
|
path.end();
|
|
}
|
|
if(tickPath)
|
|
{
|
|
redrawGraphic = true;
|
|
tickPath.end();
|
|
}
|
|
if(redrawGraphic)
|
|
{
|
|
graphic._redraw();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Updates the content and style properties for a title field.
|
|
*
|
|
* @method _updateTitle
|
|
* @private
|
|
*/
|
|
_setTitle: function()
|
|
{
|
|
var i,
|
|
styles,
|
|
customStyles,
|
|
title = this.get("title"),
|
|
titleTextField = this._titleTextField,
|
|
parentNode;
|
|
if(title !== null && title !== undefined)
|
|
{
|
|
customStyles = {
|
|
rotation: "rotation",
|
|
margin: "margin",
|
|
alpha: "alpha"
|
|
};
|
|
styles = this.get("styles").title;
|
|
if(!titleTextField)
|
|
{
|
|
titleTextField = DOCUMENT.createElement('span');
|
|
titleTextField.style.display = "block";
|
|
titleTextField.style.whiteSpace = "nowrap";
|
|
titleTextField.setAttribute("class", "axisTitle");
|
|
this.get("contentBox").append(titleTextField);
|
|
}
|
|
else if(!DOCUMENT.createElementNS)
|
|
{
|
|
if(titleTextField.style.filter)
|
|
{
|
|
titleTextField.style.filter = null;
|
|
}
|
|
}
|
|
titleTextField.style.position = "absolute";
|
|
for(i in styles)
|
|
{
|
|
if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
|
|
{
|
|
titleTextField.style[i] = styles[i];
|
|
}
|
|
}
|
|
this.get("appendTitleFunction")(titleTextField, title);
|
|
this._titleTextField = titleTextField;
|
|
this._titleRotationProps = this._getTextRotationProps(styles);
|
|
this._setTotalTitleSize(styles);
|
|
}
|
|
else if(titleTextField)
|
|
{
|
|
parentNode = titleTextField.parentNode;
|
|
if(parentNode)
|
|
{
|
|
parentNode.removeChild(titleTextField);
|
|
}
|
|
this._titleTextField = null;
|
|
this._totalTitleSize = 0;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Creates or updates an axis label.
|
|
*
|
|
* @method getLabel
|
|
* @param {Object} styles styles applied to label
|
|
* @return HTMLElement
|
|
* @private
|
|
*/
|
|
getLabel: function(styles)
|
|
{
|
|
var i,
|
|
label,
|
|
labelCache = this._labelCache,
|
|
customStyles = {
|
|
rotation: "rotation",
|
|
margin: "margin",
|
|
alpha: "alpha"
|
|
};
|
|
if(labelCache && labelCache.length > 0)
|
|
{
|
|
label = labelCache.shift();
|
|
}
|
|
else
|
|
{
|
|
label = DOCUMENT.createElement("span");
|
|
label.className = Y.Lang.trim([label.className, "axisLabel"].join(' '));
|
|
this.get("contentBox").append(label);
|
|
}
|
|
if(!DOCUMENT.createElementNS)
|
|
{
|
|
if(label.style.filter)
|
|
{
|
|
label.style.filter = null;
|
|
}
|
|
}
|
|
label.style.display = "block";
|
|
label.style.whiteSpace = "nowrap";
|
|
label.style.position = "absolute";
|
|
for(i in styles)
|
|
{
|
|
if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
|
|
{
|
|
label.style[i] = styles[i];
|
|
}
|
|
}
|
|
return label;
|
|
},
|
|
|
|
/**
|
|
* Creates a cache of labels that can be re-used when the axis redraws.
|
|
*
|
|
* @method _createLabelCache
|
|
* @private
|
|
*/
|
|
_createLabelCache: function()
|
|
{
|
|
if(this._labels)
|
|
{
|
|
while(this._labels.length > 0)
|
|
{
|
|
this._labelCache.push(this._labels.shift());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this._clearLabelCache();
|
|
}
|
|
this._labels = [];
|
|
},
|
|
|
|
/**
|
|
* Removes axis labels from the dom and clears the label cache.
|
|
*
|
|
* @method _clearLabelCache
|
|
* @private
|
|
*/
|
|
_clearLabelCache: function()
|
|
{
|
|
if(this._labelCache)
|
|
{
|
|
var len = this._labelCache.length,
|
|
i = 0,
|
|
label;
|
|
for(; i < len; ++i)
|
|
{
|
|
label = this._labelCache[i];
|
|
this._removeChildren(label);
|
|
Y.Event.purgeElement(label, true);
|
|
label.parentNode.removeChild(label);
|
|
}
|
|
}
|
|
this._labelCache = [];
|
|
},
|
|
|
|
/**
|
|
* Gets the end point of an axis.
|
|
*
|
|
* @method getLineEnd
|
|
* @return Object
|
|
* @private
|
|
*/
|
|
getLineEnd: function(pt)
|
|
{
|
|
var w = this.get("width"),
|
|
h = this.get("height"),
|
|
pos = this.get("position");
|
|
if(pos === "top" || pos === "bottom")
|
|
{
|
|
return {x:w, y:pt.y};
|
|
}
|
|
else
|
|
{
|
|
return {x:pt.x, y:h};
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Calcuates the width or height of an axis depending on its direction.
|
|
*
|
|
* @method getLength
|
|
* @return Number
|
|
* @private
|
|
*/
|
|
getLength: function()
|
|
{
|
|
var l,
|
|
style = this.get("styles"),
|
|
padding = style.padding,
|
|
w = this.get("width"),
|
|
h = this.get("height"),
|
|
pos = this.get("position");
|
|
if(pos === "top" || pos === "bottom")
|
|
{
|
|
l = w - (padding.left + padding.right);
|
|
}
|
|
else
|
|
{
|
|
l = h - (padding.top + padding.bottom);
|
|
}
|
|
return l;
|
|
},
|
|
|
|
/**
|
|
* Gets the position of the first point on an axis.
|
|
*
|
|
* @method getFirstPoint
|
|
* @param {Object} pt Object containing x and y coordinates.
|
|
* @return Object
|
|
* @private
|
|
*/
|
|
getFirstPoint:function(pt)
|
|
{
|
|
var style = this.get("styles"),
|
|
pos = this.get("position"),
|
|
padding = style.padding,
|
|
np = {x:pt.x, y:pt.y};
|
|
if(pos === "top" || pos === "bottom")
|
|
{
|
|
np.x += padding.left + this.get("edgeOffset");
|
|
}
|
|
else
|
|
{
|
|
np.y += this.get("height") - (padding.top + this.get("edgeOffset"));
|
|
}
|
|
return np;
|
|
},
|
|
|
|
/**
|
|
* Rotates and positions a text field.
|
|
*
|
|
* @method _rotate
|
|
* @param {HTMLElement} label text field to rotate and position
|
|
* @param {Object} props properties to be applied to the text field.
|
|
* @private
|
|
*/
|
|
_rotate: function(label, props)
|
|
{
|
|
var rot = props.rot,
|
|
x = props.x,
|
|
y = props.y,
|
|
filterString,
|
|
textAlpha,
|
|
matrix = new Y.Matrix(),
|
|
transformOrigin = props.transformOrigin || [0, 0],
|
|
offsetRect;
|
|
if(DOCUMENT.createElementNS)
|
|
{
|
|
matrix.translate(x, y);
|
|
matrix.rotate(rot);
|
|
Y_DOM.setStyle(label, "transformOrigin", (transformOrigin[0] * 100) + "% " + (transformOrigin[1] * 100) + "%");
|
|
Y_DOM.setStyle(label, "transform", matrix.toCSSText());
|
|
}
|
|
else
|
|
{
|
|
textAlpha = props.textAlpha;
|
|
if(Y_Lang.isNumber(textAlpha) && textAlpha < 1 && textAlpha > -1 && !isNaN(textAlpha))
|
|
{
|
|
filterString = "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + Math.round(textAlpha * 100) + ")";
|
|
}
|
|
if(rot !== 0)
|
|
{
|
|
//ms filters kind of, sort of uses a transformOrigin of 0, 0.
|
|
//we'll translate the difference to create a true 0, 0 origin.
|
|
matrix.rotate(rot);
|
|
offsetRect = matrix.getContentRect(props.labelWidth, props.labelHeight);
|
|
matrix.init();
|
|
matrix.translate(offsetRect.left, offsetRect.top);
|
|
matrix.translate(x, y);
|
|
this._simulateRotateWithTransformOrigin(matrix, rot, transformOrigin, props.labelWidth, props.labelHeight);
|
|
if(filterString)
|
|
{
|
|
filterString += " ";
|
|
}
|
|
else
|
|
{
|
|
filterString = "";
|
|
}
|
|
filterString += matrix.toFilterText();
|
|
label.style.left = matrix.dx + "px";
|
|
label.style.top = matrix.dy + "px";
|
|
}
|
|
else
|
|
{
|
|
label.style.left = x + "px";
|
|
label.style.top = y + "px";
|
|
}
|
|
if(filterString)
|
|
{
|
|
label.style.filter = filterString;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Simulates a rotation with a specified transformOrigin.
|
|
*
|
|
* @method _simulateTransformOrigin
|
|
* @param {Matrix} matrix Reference to a `Matrix` instance.
|
|
* @param {Number} rot The rotation (in degrees) that will be performed on a matrix.
|
|
* @param {Array} transformOrigin An array represeniting the origin in which to perform the transform. The first
|
|
* index represents the x origin and the second index represents the y origin.
|
|
* @param {Number} w The width of the object that will be transformed.
|
|
* @param {Number} h The height of the object that will be transformed.
|
|
* @private
|
|
*/
|
|
_simulateRotateWithTransformOrigin: function(matrix, rot, transformOrigin, w, h)
|
|
{
|
|
var transformX = transformOrigin[0] * w,
|
|
transformY = transformOrigin[1] * h;
|
|
transformX = !isNaN(transformX) ? transformX : 0;
|
|
transformY = !isNaN(transformY) ? transformY : 0;
|
|
matrix.translate(transformX, transformY);
|
|
matrix.rotate(rot);
|
|
matrix.translate(-transformX, -transformY);
|
|
},
|
|
|
|
/**
|
|
* Returns the coordinates (top, right, bottom, left) for the bounding box of the last label.
|
|
*
|
|
* @method getMaxLabelBounds
|
|
* @return Object
|
|
*/
|
|
getMaxLabelBounds: function()
|
|
{
|
|
return this._getLabelBounds(this.getMaximumValue());
|
|
},
|
|
|
|
/**
|
|
* Returns the coordinates (top, right, bottom, left) for the bounding box of the first label.
|
|
*
|
|
* @method getMinLabelBounds
|
|
* @return Object
|
|
*/
|
|
getMinLabelBounds: function()
|
|
{
|
|
return this._getLabelBounds(this.getMinimumValue());
|
|
},
|
|
|
|
/**
|
|
* Returns the coordinates (top, right, bottom, left) for the bounding box of a label.
|
|
*
|
|
* @method _getLabelBounds
|
|
* @param {String} Value of the label
|
|
* @return Object
|
|
* @private
|
|
*/
|
|
_getLabelBounds: function(val)
|
|
{
|
|
var layout = this._layout,
|
|
labelStyles = this.get("styles").label,
|
|
matrix = new Y.Matrix(),
|
|
label,
|
|
props = this._getTextRotationProps(labelStyles);
|
|
props.transformOrigin = layout._getTransformOrigin(props.rot);
|
|
label = this.getLabel(labelStyles);
|
|
this.get("appendLabelFunction")(label, this.get("labelFunction").apply(this, [val, this.get("labelFormat")]));
|
|
props.labelWidth = label.offsetWidth;
|
|
props.labelHeight = label.offsetHeight;
|
|
this._removeChildren(label);
|
|
Y.Event.purgeElement(label, true);
|
|
label.parentNode.removeChild(label);
|
|
props.x = 0;
|
|
props.y = 0;
|
|
layout._setRotationCoords(props);
|
|
matrix.translate(props.x, props.y);
|
|
this._simulateRotateWithTransformOrigin(matrix, props.rot, props.transformOrigin, props.labelWidth, props.labelHeight);
|
|
return matrix.getContentRect(props.labelWidth, props.labelHeight);
|
|
},
|
|
|
|
/**
|
|
* Removes all DOM elements from an HTML element. Used to clear out labels during detruction
|
|
* phase.
|
|
*
|
|
* @method _removeChildren
|
|
* @private
|
|
*/
|
|
_removeChildren: function(node)
|
|
{
|
|
if(node.hasChildNodes())
|
|
{
|
|
var child;
|
|
while(node.firstChild)
|
|
{
|
|
child = node.firstChild;
|
|
this._removeChildren(child);
|
|
node.removeChild(child);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Destructor implementation Axis class. Removes all labels and the Graphic instance from the widget.
|
|
*
|
|
* @method destructor
|
|
* @protected
|
|
*/
|
|
destructor: function()
|
|
{
|
|
var cb = this.get("contentBox").getDOMNode(),
|
|
labels = this.get("labels"),
|
|
graphic = this.get("graphic"),
|
|
label,
|
|
len = labels ? labels.length : 0;
|
|
if(len > 0)
|
|
{
|
|
while(labels.length > 0)
|
|
{
|
|
label = labels.shift();
|
|
this._removeChildren(label);
|
|
cb.removeChild(label);
|
|
label = null;
|
|
}
|
|
}
|
|
if(graphic)
|
|
{
|
|
graphic.destroy();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Length in pixels of largest text bounding box. Used to calculate the height of the axis.
|
|
*
|
|
* @property maxLabelSize
|
|
* @type Number
|
|
* @protected
|
|
*/
|
|
_maxLabelSize: 0,
|
|
|
|
/**
|
|
* Updates the content of text field. This method writes a value into a text field using
|
|
* `appendChild`. If the value is a `String`, it is converted to a `TextNode` first.
|
|
*
|
|
* @method _setText
|
|
* @param label {HTMLElement} label to be updated
|
|
* @param val {String} value with which to update the label
|
|
* @private
|
|
*/
|
|
_setText: function(textField, val)
|
|
{
|
|
textField.innerHTML = "";
|
|
if(Y_Lang.isNumber(val))
|
|
{
|
|
val = val + "";
|
|
}
|
|
else if(!val)
|
|
{
|
|
val = "";
|
|
}
|
|
if(IS_STRING(val))
|
|
{
|
|
val = DOCUMENT.createTextNode(val);
|
|
}
|
|
textField.appendChild(val);
|
|
},
|
|
|
|
/**
|
|
* Returns the total number of majorUnits that will appear on an axis.
|
|
*
|
|
* @method getTotalMajorUnits
|
|
* @return Number
|
|
*/
|
|
getTotalMajorUnits: function()
|
|
{
|
|
var units,
|
|
majorUnit = this.get("styles").majorUnit,
|
|
len;
|
|
if(majorUnit.determinant === "count")
|
|
{
|
|
units = majorUnit.count;
|
|
}
|
|
else if(majorUnit.determinant === "distance")
|
|
{
|
|
len = this.getLength();
|
|
units = (len/majorUnit.distance) + 1;
|
|
}
|
|
return units;
|
|
},
|
|
|
|
/**
|
|
* Returns the distance between major units on an axis.
|
|
*
|
|
* @method getMajorUnitDistance
|
|
* @param {Number} len Number of ticks
|
|
* @param {Number} uiLen Size of the axis.
|
|
* @param {Object} majorUnit Hash of properties used to determine the majorUnit
|
|
* @return Number
|
|
*/
|
|
getMajorUnitDistance: function(len, uiLen, majorUnit)
|
|
{
|
|
var dist;
|
|
if(majorUnit.determinant === "count")
|
|
{
|
|
if(!this.get("calculateEdgeOffset"))
|
|
{
|
|
len = len - 1;
|
|
}
|
|
dist = uiLen/len;
|
|
}
|
|
else if(majorUnit.determinant === "distance")
|
|
{
|
|
dist = majorUnit.distance;
|
|
}
|
|
return dist;
|
|
},
|
|
|
|
/**
|
|
* Checks to see if data extends beyond the range of the axis. If so,
|
|
* that data will need to be hidden. This method is internal, temporary and subject
|
|
* to removal in the future.
|
|
*
|
|
* @method _hasDataOverflow
|
|
* @protected
|
|
* @return Boolean
|
|
*/
|
|
_hasDataOverflow: function()
|
|
{
|
|
if(this.get("setMin") || this.get("setMax"))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Returns a string corresponding to the first label on an
|
|
* axis.
|
|
*
|
|
* @method getMinimumValue
|
|
* @return String
|
|
*/
|
|
getMinimumValue: function()
|
|
{
|
|
return this.get("minimum");
|
|
},
|
|
|
|
/**
|
|
* Returns a string corresponding to the last label on an
|
|
* axis.
|
|
*
|
|
* @method getMaximumValue
|
|
* @return String
|
|
*/
|
|
getMaximumValue: function()
|
|
{
|
|
return this.get("maximum");
|
|
}
|
|
}, {
|
|
ATTRS:
|
|
{
|
|
/**
|
|
* When set, defines the width of a vertical axis instance. By default, vertical axes automatically size based
|
|
* on their contents. When the width attribute is set, the axis will not calculate its width. When the width
|
|
* attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
|
|
* title, if present, will position itself off of the outer edge. If a specified width is less than the sum of
|
|
* the axis' contents, excess content will overflow.
|
|
*
|
|
* @attribute width
|
|
* @type Number
|
|
*/
|
|
width: {
|
|
lazyAdd: false,
|
|
|
|
getter: function()
|
|
{
|
|
if(this._explicitWidth)
|
|
{
|
|
return this._explicitWidth;
|
|
}
|
|
return this._calculatedWidth;
|
|
},
|
|
|
|
setter: function(val)
|
|
{
|
|
this._explicitWidth = val;
|
|
return val;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* When set, defines the height of a horizontal axis instance. By default, horizontal axes automatically size based
|
|
* on their contents. When the height attribute is set, the axis will not calculate its height. When the height
|
|
* attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
|
|
* title, if present, will position itself off of the outer edge. If a specified height is less than the sum of
|
|
* the axis' contents, excess content will overflow.
|
|
*
|
|
* @attribute height
|
|
* @type Number
|
|
*/
|
|
height: {
|
|
lazyAdd: false,
|
|
|
|
getter: function()
|
|
{
|
|
if(this._explicitHeight)
|
|
{
|
|
return this._explicitHeight;
|
|
}
|
|
return this._calculatedHeight;
|
|
},
|
|
|
|
setter: function(val)
|
|
{
|
|
this._explicitHeight = val;
|
|
return val;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Calculated value of an axis' width. By default, the value is used internally for vertical axes. If the `width`
|
|
* attribute is explicitly set, this value will be ignored.
|
|
*
|
|
* @attribute calculatedWidth
|
|
* @type Number
|
|
* @private
|
|
*/
|
|
calculatedWidth: {
|
|
getter: function()
|
|
{
|
|
return this._calculatedWidth;
|
|
},
|
|
|
|
setter: function(val)
|
|
{
|
|
this._calculatedWidth = val;
|
|
return val;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Calculated value of an axis' height. By default, the value is used internally for horizontal axes. If the `height`
|
|
* attribute is explicitly set, this value will be ignored.
|
|
*
|
|
* @attribute calculatedHeight
|
|
* @type Number
|
|
* @private
|
|
*/
|
|
calculatedHeight: {
|
|
getter: function()
|
|
{
|
|
return this._calculatedHeight;
|
|
},
|
|
|
|
setter: function(val)
|
|
{
|
|
this._calculatedHeight = val;
|
|
return val;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Difference between the first/last tick and edge of axis.
|
|
*
|
|
* @attribute edgeOffset
|
|
* @type Number
|
|
* @protected
|
|
*/
|
|
edgeOffset:
|
|
{
|
|
value: 0
|
|
},
|
|
|
|
/**
|
|
* The graphic in which the axis line and ticks will be rendered.
|
|
*
|
|
* @attribute graphic
|
|
* @type Graphic
|
|
*/
|
|
graphic: {},
|
|
|
|
/**
|
|
* @attribute path
|
|
* @type Shape
|
|
* @readOnly
|
|
* @private
|
|
*/
|
|
path: {
|
|
readOnly: true,
|
|
|
|
getter: function()
|
|
{
|
|
if(!this._path)
|
|
{
|
|
var graphic = this.get("graphic");
|
|
if(graphic)
|
|
{
|
|
this._path = graphic.addShape({type:"path"});
|
|
}
|
|
}
|
|
return this._path;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @attribute tickPath
|
|
* @type Shape
|
|
* @readOnly
|
|
* @private
|
|
*/
|
|
tickPath: {
|
|
readOnly: true,
|
|
|
|
getter: function()
|
|
{
|
|
if(!this._tickPath)
|
|
{
|
|
var graphic = this.get("graphic");
|
|
if(graphic)
|
|
{
|
|
this._tickPath = graphic.addShape({type:"path"});
|
|
}
|
|
}
|
|
return this._tickPath;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Contains the contents of the axis.
|
|
*
|
|
* @attribute node
|
|
* @type HTMLElement
|
|
*/
|
|
node: {},
|
|
|
|
/**
|
|
* Direction of the axis.
|
|
*
|
|
* @attribute position
|
|
* @type String
|
|
*/
|
|
position: {
|
|
lazyAdd: false,
|
|
|
|
setter: function(val)
|
|
{
|
|
var LayoutClass = this._layoutClasses[val];
|
|
if(val && val !== "none")
|
|
{
|
|
this._layout = new LayoutClass();
|
|
}
|
|
return val;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Distance determined by the tick styles used to calculate the distance between the axis
|
|
* line in relation to the top of the axis.
|
|
*
|
|
* @attribute topTickOffset
|
|
* @type Number
|
|
*/
|
|
topTickOffset: {
|
|
value: 0
|
|
},
|
|
|
|
/**
|
|
* Distance determined by the tick styles used to calculate the distance between the axis
|
|
* line in relation to the bottom of the axis.
|
|
*
|
|
* @attribute bottomTickOffset
|
|
* @type Number
|
|
*/
|
|
bottomTickOffset: {
|
|
value: 0
|
|
},
|
|
|
|
/**
|
|
* Distance determined by the tick styles used to calculate the distance between the axis
|
|
* line in relation to the left of the axis.
|
|
*
|
|
* @attribute leftTickOffset
|
|
* @type Number
|
|
*/
|
|
leftTickOffset: {
|
|
value: 0
|
|
},
|
|
|
|
/**
|
|
* Distance determined by the tick styles used to calculate the distance between the axis
|
|
* line in relation to the right side of the axis.
|
|
*
|
|
* @attribute rightTickOffset
|
|
* @type Number
|
|
*/
|
|
rightTickOffset: {
|
|
value: 0
|
|
},
|
|
|
|
/**
|
|
* Collection of labels used to render the axis.
|
|
*
|
|
* @attribute labels
|
|
* @type Array
|
|
*/
|
|
labels: {
|
|
readOnly: true,
|
|
getter: function()
|
|
{
|
|
return this._labels;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Collection of points used for placement of labels and ticks along the axis.
|
|
*
|
|
* @attribute tickPoints
|
|
* @type Array
|
|
*/
|
|
tickPoints: {
|
|
readOnly: true,
|
|
|
|
getter: function()
|
|
{
|
|
if(this.get("position") === "none")
|
|
{
|
|
return this.get("styles").majorUnit.count;
|
|
}
|
|
return this._tickPoints;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Indicates whether the axis overlaps the graph. If an axis is the inner most axis on a given
|
|
* position and the tick position is inside or cross, the axis will need to overlap the graph.
|
|
*
|
|
* @attribute overlapGraph
|
|
* @type Boolean
|
|
*/
|
|
overlapGraph: {
|
|
value:true,
|
|
|
|
validator: function(val)
|
|
{
|
|
return Y_Lang.isBoolean(val);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Length in pixels of largest text bounding box. Used to calculate the height of the axis.
|
|
*
|
|
* @attribute maxLabelSize
|
|
* @type Number
|
|
* @protected
|
|
*/
|
|
maxLabelSize: {
|
|
getter: function()
|
|
{
|
|
return this._maxLabelSize;
|
|
},
|
|
|
|
setter: function(val)
|
|
{
|
|
this._maxLabelSize = val;
|
|
return val;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Title for the axis. When specified, the title will display. The position of the title is determined by the axis position.
|
|
* <dl>
|
|
* <dt>top</dt><dd>Appears above the axis and it labels. The default rotation is 0.</dd>
|
|
* <dt>right</dt><dd>Appears to the right of the axis and its labels. The default rotation is 90.</dd>
|
|
* <dt>bottom</dt><dd>Appears below the axis and its labels. The default rotation is 0.</dd>
|
|
* <dt>left</dt><dd>Appears to the left of the axis and its labels. The default rotation is -90.</dd>
|
|
* </dl>
|
|
*
|
|
* @attribute title
|
|
* @type String
|
|
*/
|
|
title: {
|
|
value: null
|
|
},
|
|
|
|
/**
|
|
* Function used to append an axis value to an axis label. This function has the following signature:
|
|
* <dl>
|
|
* <dt>textField</dt><dd>The axis label to be appended. (`HTMLElement`)</dd>
|
|
* <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
|
|
* or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
|
|
* </dl>
|
|
* The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
|
|
* value is a `String`, the method will convert the the value to a `textNode` before appending to the
|
|
* `HTMLElement`. This method will not convert an `HTMLString` to an `HTMLElement`.
|
|
*
|
|
* @attribute appendLabelFunction
|
|
* @type Function
|
|
*/
|
|
appendLabelFunction: {
|
|
valueFn: function()
|
|
{
|
|
return this._setText;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Function used to append a title value to the title object. This function has the following signature:
|
|
* <dl>
|
|
* <dt>textField</dt><dd>The title text field to be appended. (`HTMLElement`)</dd>
|
|
* <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
|
|
* or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
|
|
* </dl>
|
|
* The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
|
|
* value is a `String`, the method will convert the the value to a `textNode` before appending to the
|
|
* `HTMLElement` element. This method will not convert an `HTMLString` to an `HTMLElement`.
|
|
*
|
|
* @attribute appendTitleFunction
|
|
* @type Function
|
|
*/
|
|
appendTitleFunction: {
|
|
valueFn: function()
|
|
{
|
|
return this._setText;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* An array containing the unformatted values of the axis labels. By default, TimeAxis, NumericAxis and
|
|
* StackedAxis labelValues are determined by the majorUnit style. By default, CategoryAxis labels are
|
|
* determined by the values of the dataProvider.
|
|
* <p>When the labelValues attribute is explicitly set, the labelValues are dictated by the set value and
|
|
* the position of ticks and labels are determined by where those values would fall on the axis. </p>
|
|
*
|
|
* @attribute labelValues
|
|
* @type Array
|
|
*/
|
|
labelValues: {
|
|
lazyAdd: false,
|
|
|
|
setter: function(val)
|
|
{
|
|
var opts = arguments[2];
|
|
if(!val || (opts && opts.src && opts.src === "internal"))
|
|
{
|
|
this._labelValuesExplicitlySet = false;
|
|
}
|
|
else
|
|
{
|
|
this._labelValuesExplicitlySet = true;
|
|
}
|
|
return val;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Suppresses the creation of the the first visible label and tick.
|
|
*
|
|
* @attribute hideFirstMajorUnit
|
|
* @type Boolean
|
|
*/
|
|
hideFirstMajorUnit: {
|
|
value: false
|
|
},
|
|
|
|
/**
|
|
* Suppresses the creation of the the last visible label and tick.
|
|
*
|
|
* @attribute hideLastMajorUnit
|
|
* @type Boolean
|
|
*/
|
|
hideLastMajorUnit: {
|
|
value: false
|
|
}
|
|
|
|
/**
|
|
* Style properties used for drawing an axis. This attribute is inherited from `Renderer`. Below are the default values:
|
|
* <dl>
|
|
* <dt>majorTicks</dt><dd>Properties used for drawing ticks.
|
|
* <dl>
|
|
* <dt>display</dt><dd>Position of the tick. Possible values are `inside`, `outside`, `cross` and `none`.
|
|
* The default value is `inside`.</dd>
|
|
* <dt>length</dt><dd>The length (in pixels) of the tick. The default value is 4.</dd>
|
|
* <dt>color</dt><dd>The color of the tick. The default value is `#dad8c9`</dd>
|
|
* <dt>weight</dt><dd>Number indicating the width of the tick. The default value is 1.</dd>
|
|
* <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
|
|
* </dl>
|
|
* </dd>
|
|
* <dt>line</dt><dd>Properties used for drawing the axis line.
|
|
* <dl>
|
|
* <dt>weight</dt><dd>Number indicating the width of the axis line. The default value is 1.</dd>
|
|
* <dt>color</dt><dd>The color of the axis line. The default value is `#dad8c9`.</dd>
|
|
* <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
|
|
* </dl>
|
|
* </dd>
|
|
* <dt>majorUnit</dt><dd>Properties used to calculate the `majorUnit` for the axis.
|
|
* <dl>
|
|
* <dt>determinant</dt><dd>The algorithm used for calculating distance between ticks. The possible options are
|
|
* `count` and `distance`. If the `determinant` is `count`, the axis ticks will spaced so that a specified number
|
|
* of ticks appear on the axis. If the `determinant` is `distance`, the axis ticks will spaced out according to
|
|
* the specified distance. The default value is `count`.</dd>
|
|
* <dt>count</dt><dd>Number of ticks to appear on the axis when the `determinant` is `count`. The default value is 11.</dd>
|
|
* <dt>distance</dt><dd>The distance (in pixels) between ticks when the `determinant` is `distance`. The default
|
|
* value is 75.</dd>
|
|
* </dl>
|
|
* </dd>
|
|
* <dt>label</dt><dd>Properties and styles applied to the axis labels.
|
|
* <dl>
|
|
* <dt>color</dt><dd>The color of the labels. The default value is `#808080`.</dd>
|
|
* <dt>alpha</dt><dd>Number between 0 and 1 indicating the opacity of the labels. The default value is 1.</dd>
|
|
* <dt>fontSize</dt><dd>The font-size of the labels. The default value is 85%</dd>
|
|
* <dt>rotation</dt><dd>The rotation, in degrees (between -90 and 90) of the labels. The default value is 0.</dd>
|
|
* <dt>offset</td><dd>A number between 0 and 1 indicating the relationship of the label to a tick. For a horizontal axis
|
|
* label, a value of 0 will position the label's left side even to the the tick. A position of 1 would position the
|
|
* right side of the label with the tick. A position of 0.5 would center the label horizontally with the tick. For a
|
|
* vertical axis, a value of 0 would position the top of the label with the tick, a value of 1 would position the bottom
|
|
* of the label with the tick and a value 0 would center the label vertically with the tick. The default value is 0.5.</dd>
|
|
* <dt>margin</dt><dd>The distance between the label and the axis/tick. Depending on the position of the `Axis`,
|
|
* only one of the properties used.
|
|
* <dl>
|
|
* <dt>top</dt><dd>Pixel value used for an axis with a `position` of `bottom`. The default value is 4.</dd>
|
|
* <dt>right</dt><dd>Pixel value used for an axis with a `position` of `left`. The default value is 4.</dd>
|
|
* <dt>bottom</dt><dd>Pixel value used for an axis with a `position` of `top`. The default value is 4.</dd>
|
|
* <dt>left</dt><dd>Pixel value used for an axis with a `position` of `right`. The default value is 4.</dd>
|
|
* </dl>
|
|
* </dd>
|
|
* </dl>
|
|
* </dd>
|
|
* </dl>
|
|
*
|
|
* @attribute styles
|
|
* @type Object
|
|
*/
|
|
}
|
|
});
|
|
Y.AxisType = Y.Base.create("baseAxis", Y.Axis, [], {});
|
|
|
|
|
|
}, '3.17.2', {"requires": ["dom", "widget", "widget-position", "widget-stack", "graphics", "axis-base"]});
|
|
|