axis.as
来自「用于flash/flex的 as3的 2D图形图像图表的动态生成」· AS 代码 · 共 714 行 · 第 1/2 页
AS
714 行
}
/**
* Marks all items slated for removal from this axis.
* @param trans a Transitioner for collecting value updates.
* @param keep a Boolean array indicating which items to keep
* @param con a container Sprite whose contents should be marked
* for removal
*/
protected function markRemovals(trans:Transitioner, keep:Array, con:Sprite) : void
{
for (var i:uint = keep.length; --i >= 0; ) {
if (!keep[i]) trans.removeChild(con.getChildAt(i));
}
}
// -- Layout ----------------------------------------------------------
/**
* Performs layout, setting the position of labels and grid lines.
* @param trans a Transitioner for collecting value updates.
*/
protected function layout(trans:Transitioner) : void
{
var i:uint, label:AxisLabel, gline:AxisGridLine, p:Point;
var _lab:Sprite = this.labels;
var _gls:Sprite = this.gridLines;
var o:Object;
// layout labels
for (i=0; i<_lab.numChildren; ++i) {
label = _lab.getChildAt(i) as AxisLabel;
p = positionLabel(label, axisScale);
o = trans.$(label);
o.x = p.x;
o.y = p.y;
o.alpha = trans.willRemove(label) ? 0 : 1;
}
// fix label overlap
if (fixLabelOverlap) fixOverlap(trans);
// layout gridlines
for (i=0; i<_gls.numChildren; ++i) {
gline = _gls.getChildAt(i) as AxisGridLine;
p = positionGridLine(gline, axisScale);
o = trans.$(gline);
o.x1 = p.x;
o.y1 = p.y;
o.x2 = p.x + lineLengthX + _xd*(lineCapX1+lineCapX2);
o.y2 = p.y + lineLengthY + _yd*(lineCapY1+lineCapY2);
o.alpha = trans.willRemove(gline) ? 0 : 1;
}
// update previous scale
_prevScale = axisScale.clone(); // clone scale
_xaP = _xa; _yaP = _ya; _xbP = _xb; _ybP = _yb;
}
// -- Label Overlap ---------------------------------------------------
/**
* Eliminates overlap between labels along an axis.
* @param trans a transitioner, potentially storing label positions
*/
protected function fixOverlap(trans:Transitioner):void
{
var labs:Array = [], d:DisplayObject, i:int;
// collect and sort labels
for (i=0; i<labels.numChildren; ++i) {
var s:AxisLabel = AxisLabel(labels.getChildAt(i));
if (!trans.willRemove(s)) labs.push(s);
}
if (labs.length == 0) return;
labs.sortOn("ordinal", Array.NUMERIC);
// stores the labels to remove
var rem:Dictionary = new Dictionary();
if (axisScale.scaleType == ScaleType.LOG) {
fixLogOverlap(labs, rem, trans, axisScale);
}
// maintain min and max if we get down to two
i = labs.length;
var min:Object = labs[0];
var max:Object = labs[i-1];
var mid:Object = (i&1) ? labs[(i>>1)] : null;
// fix overlap with an iterative optimization
// remove every other label with each iteration
while (hasOverlap(labs, trans)) {
// reduce labels
i = labs.length;
if (mid && i>3 && i<8) { // use min, med, max if we can
for each (d in labs) rem[d] = d;
if (rem[min]) delete rem[min];
if (rem[max]) delete rem[max];
if (rem[mid]) delete rem[mid];
labs = [min, mid, max];
}
else if (i < 4) { // use min and max if we're down to two
if (rem[min]) delete rem[min];
if (rem[max]) delete rem[max];
for each (d in labs) {
if (d != min && d != max) rem[d] = d;
}
break;
}
else { // else remove every odd element
i = i - (i&1 ? 2 : 1);
for (; i>0; i-=2) {
rem[labs[i]] = labs[i];
labs.splice(i, 1); // remove from array
}
}
}
// remove the deleted labels
for each (d in rem) {
trans.$(d).alpha = 0;
trans.removeChild(d, true);
}
}
private static function fixLogOverlap(labs:Array, rem:Dictionary,
trans:Transitioner, scale:Scale):void
{
var base:int = int(Object(scale).base), i:int, j:int, zidx:int;
if (!hasOverlap(labs, trans)) return;
// find zero
zidx = Arrays.binarySearch(labs, 0, "value");
var neg:Boolean = Number(scale.min) < 0;
var pos:Boolean = Number(scale.max) > 0;
// if includes negative, traverse backwards from zero/end
if (neg) {
i = (zidx<0 ? labs.length : zidx) - (pos ? 1 : 2);
for (j=pos?1:2; i>=0; ++j, --i) {
if (j == base) {
j = 1;
} else {
rem[labs[i]] = labs[i];
labs.splice(i, 1); --zidx;
}
}
}
// if includes positive, traverse forwards from zero/start
if (pos) {
i = (zidx<0 ? 0 : zidx+1) + (neg ? 0 : 1);
for (j=neg?1:2; i<labs.length; ++j) {
if (j == base) {
j = 1; ++i;
} else {
rem[labs[i]] = labs[i];
labs.splice(i, 1);
}
}
}
}
private static function hasOverlap(labs:Array, trans:Transitioner):Boolean
{
var d:DisplayObject = labs[0], e:DisplayObject;
for (var i:int=1; i<labs.length; ++i) {
if (overlaps(trans, d, (e=labs[i]))) return true;
d = e;
}
return false;
}
/**
* Indicates if two display objects overlap, sensitive to any target
* values stored in a transitioner.
* @param trans a Transitioner, potentially with target values
* @param l1 a display object
* @param l2 a display object
* @return true if the objects overlap (considering values in the
* transitioner, if appropriate), false otherwise
*/
private static function overlaps(trans:Transitioner,
l1:DisplayObject, l2:DisplayObject):Boolean
{
if (trans.immediate) return l1.hitTestObject(l2);
// get original co-ordinates
var xa:Number = l1.x, ya:Number = l1.y;
var xb:Number = l2.x, yb:Number = l2.y;
var o:Object;
// set to target co-ordinates
o = trans.$(l1); l1.x = o.x; l1.y = o.y;
o = trans.$(l2); l2.x = o.x; l2.y = o.y;
// compute overlap
var b:Boolean = l1.hitTestObject(l2);
// reset to original coordinates
l1.x = xa; l1.y = ya; l2.x = xb; l2.y = yb;
return b;
}
// -- Axis Label Helpers ----------------------------------------------
/**
* Creates a new axis label.
* @param val the value to create the label for
* @return an AxisLabel
*/
protected function createLabel(val:Object) : AxisLabel
{
var label:AxisLabel = new AxisLabel();
var f:Number = _prevScale.interpolate(val);
label.alpha = 0;
label.value = val;
label.x = _xlo + _xaP + f*(_xbP - _xaP);
label.y = _ylo + _yaP + f*(_ybP - _yaP);
updateLabel(label);
labels.addChild(label);
return label;
}
/**
* Computes the position of an axis label.
* @param label the axis label to layout
* @param scale the scale used to map values to the axis
* @return a Point with x,y coordinates for the axis label
*/
protected function positionLabel(label:AxisLabel, scale:Scale) : Point
{
var f:Number = scale.interpolate(label.value);
_point.x = _xlo + _xa + f*(_xb-_xa);
_point.y = _ylo + _ya + f*(_yb-_ya);
return _point;
}
/**
* Updates an axis label's settings
* @param label the label to update
*/
protected function updateLabel(label:AxisLabel) : void
{
label.textFormat = _labelTextFormat;
label.horizontalAnchor = _anchorH;
label.verticalAnchor = _anchorV;
label.rotation = (180/Math.PI) * _labelAngle;
label.textMode = _labelTextMode;
label.text = _labelFormat==null ? axisScale.label(label.value)
: Strings.format(_labelFormat, label.value);
}
/**
* Updates all axis labels.
*/
protected function updateLabels() : void
{
var _labels:Sprite = this.labels;
for (var i:uint = 0; i<_labels.numChildren; ++i) {
updateLabel(_labels.getChildAt(i) as AxisLabel);
}
}
/**
* Returns the index of a label in the label's container sprite for a
* given data value.
* @param val the data value to find
* @param len the number of labels to check
* @return the index of a label with matching value, or -1 if no label
* was found
*/
protected function findLabel(val:Object, len:uint) : int
{
var _labels:Sprite = this.labels;
for (var i:uint = 0; i < len; ++i) {
// TODO: make this robust to repeated values
if (Stats.equal((_labels.getChildAt(i) as AxisLabel).value, val)) {
return i;
}
}
return -1;
}
// -- Axis GridLine Helpers -------------------------------------------
/**
* Creates a new axis grid line.
* @param val the value to create the grid lines for
* @return an AxisGridLine
*/
protected function createGridLine(val:Object) : AxisGridLine
{
var gline:AxisGridLine = new AxisGridLine();
var f:Number = _prevScale.interpolate(val);
gline.alpha = 0;
gline.value = val;
gline.x1 = _xaP + f*(_xbP-_xaP) - _xd*lineCapX1;
gline.y1 = _yaP + f*(_ybP-_yaP) - _yd*lineCapY1;
gline.x2 = gline.x1 + lineLengthX + _xd*(lineCapX1 + lineCapX2)
gline.y2 = gline.y1 + lineLengthY + _yd*(lineCapY1 + lineCapY2);
updateGridLine(gline);
gridLines.addChild(gline);
return gline;
}
/**
* Computes the position of an axis grid line.
* @param gline the axis grid line to layout
* @param scale the scale used to map values to the axis
* @return a Point with x,y coordinates for the axis grid line
*/
protected function positionGridLine(gline:AxisGridLine, scale:Scale) : Point
{
var f:Number = scale.interpolate(gline.value);
_point.x = _xa + f*(_xb-_xa) - _xd*lineCapX1;
_point.y = _ya + f*(_yb-_ya) - _yd*lineCapY1;
return _point;
}
/**
* Updates an axis grid line's settings
* @param gline the grid line to update
*/
protected function updateGridLine(gline:AxisGridLine) : void
{
gline.lineColor = _lineColor;
gline.lineWidth = _lineWidth;
}
/**
* Updates all grid lines.
*/
protected function updateGridLines() : void
{
var _glines:Sprite = this.gridLines;
for (var i:uint = 0; i<_glines.numChildren; ++i) {
updateGridLine(_glines.getChildAt(i) as AxisGridLine);
}
}
/**
* Returns the index of a grid lines in the line's container sprite
* for a given data value.
* @param val the data value to find
* @param len the number of grid lines to check
* @return the index of a grid line with matching value, or -1 if no
* grid line was found
*/
protected function findGridLine(val:Object, len:uint) : int
{
var _glines:Sprite = this.gridLines;
for (var i:uint = 0; i<len; ++i) {
// TODO: make this robust to repeated values
if (Stats.equal((_glines.getChildAt(i) as AxisGridLine).value, val)) {
return i;
}
}
return -1;
}
} // end of class Axis
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?