📄 numericaxis.as
字号:
{ var seriesCount:int = data.length; var dataMinimum:Number = NaN; var dataMaximum:Number = NaN; for(var i:int = 0; i < seriesCount; i++) { var series:ISeries = data[i] as ISeries; var seriesLength:int = series.length; for(var j:int = 0; j < seriesLength; j++) { var item:Object = series.dataProvider[j]; if(item === null) { continue; } //automatically calculates stacked values var value:Number = this.chart.itemToAxisValue(series, j, this) as Number; if(isNaN(value)) { continue; //skip bad data } //don't let bad data propogate //Math.min()/Math.max() with a NaN argument will choose NaN. Ya Rly. dataMinimum = isNaN(dataMinimum) ? value : Math.min(dataMinimum, value); dataMaximum = isNaN(dataMaximum) ? value : Math.max(dataMaximum, value); } } if(!isNaN(dataMinimum) && !isNaN(dataMaximum)) { this._dataMinimum = dataMinimum; this._dataMaximum = dataMaximum; } else { //some sensible defaults this._dataMinimum = 0; this._dataMaximum = 1; } this.resetScale(); this.calculatePositionMultiplier(); this.renderer.ticks = this.createAxisData(this.majorUnit); this.renderer.minorTicks = this.createAxisData(this.minorUnit); } //-------------------------------------- // Protected Methods //-------------------------------------- /** * @private * If the minimum, maximum, major unit or minor unit have not been set by the user, * these values must be generated by the axis. May be overridden to use custom * scaling algorithms. */ protected function resetScale():void { //use the discovered min and max from the data //if the developer didn't specify anything if(!this._minimumSetByUser) { this._minimum = this._dataMinimum; } if(!this._maximumSetByUser) { this._maximum = this._dataMaximum; } this.checkMinLessThanMax(); this.pinToOrigin(); this.calculateMajorUnit(); this.adjustMinAndMaxFromMajorUnit(); this.correctLogScaleMinimum(); //ensure that min != max if(!this._maximumSetByUser && this._minimum == this._maximum) { this._maximum = this._minimum + 1; if(!this._majorUnitSetByUser) { //rarely happens, so I'll hardcode a nice major unit //for our difference of one this._majorUnit = 0.5; } } this.calculateMinorUnit(); //even if they are manually set by the user, check all values for possible floating point errors. //we don't want extra labels or anything like that! this._minimum = NumberUtil.roundToPrecision(this._minimum, 10); this._maximum = NumberUtil.roundToPrecision(this._maximum, 10); this._majorUnit = NumberUtil.roundToPrecision(this._majorUnit, 10); this._minorUnit = NumberUtil.roundToPrecision(this._minorUnit, 10); } /** * @private * Determines the best major unit. */ protected function calculateMajorUnit():void { if(this._majorUnitSetByUser) { return; } var range:Number = this.maximum - this.minimum; var idealMajorUnit:Number = this.renderer.length / IDEAL_PIXELS_BETWEEN_MAJOR_POSITIONS; if(idealMajorUnit > 0) { this._majorUnit = this.niceNumber(range / idealMajorUnit); } else majorUnit = 0; } /** * @private * Determines the best minor unit. */ protected function calculateMinorUnit():void { if(this._minorUnitSetByUser) { return; } var range:Number = this.maximum - this.minimum; var majorUnitSpacing:Number = this.renderer.length * (this.majorUnit / range); var maximumMinorValueCount:int = int(majorUnitSpacing / IDEAL_PIXELS_BETWEEN_MINOR_POSITIONS); if(maximumMinorValueCount > 0) { var smallestMinorUnit:Number = this._majorUnit / maximumMinorValueCount; this._minorUnit = smallestMinorUnit; do { var lastMinorUnit:Number = this._minorUnit; this._minorUnit = this.niceNumber(this._minorUnit); if(lastMinorUnit == this._minorUnit) { this._minorUnit = 0; break; } if(this._minorUnit >= this._majorUnit) { this._minorUnit = this._majorUnit; break; } } //make sure we have a good division (not 25 and 10, for example) while(this._minorUnit != 0 && this._majorUnit % this._minorUnit != 0) } else { this._minorUnit = 0; } } /** * @private * Creates the AxisData objects for the axis renderer. */ protected function createAxisData(unit:Number):Array { if(unit <= 0) { return []; } var data:Array = []; var displayedMaximum:Boolean = false; var value:Number = this.minimum; while(value <= this.maximum) { value = NumberUtil.roundToPrecision(value, 10); //because Flash UIComponents round the position to the nearest pixel, we need to do the same. var position:Number = Math.round(this.valueToLocal(value)); var label:String = this.valueToLabel(value); var axisData:AxisData = new AxisData(position, value, label); data.push(axisData); //if the maximum has been displayed, we're done! if(displayedMaximum) break; //a bad unit will get us stuck in an infinite loop if(unit <= 0) { value = this.maximum; } else { value += unit; if(this.snapToUnits) { value = NumberUtil.roundDownToNearest(value, unit); } value = Math.min(value, this.maximum); //don't go over the max! } displayedMaximum = NumberUtil.fuzzyEquals(value, this.maximum); } return data; } //-------------------------------------- // Private Methods //-------------------------------------- /** * @private * If we want to always show zero, corrects the min or max as needed. */ private function pinToOrigin():void { //if we're pinned to zero, and min or max is supposed to be generated, //make sure zero is somewhere in the range if(this.alwaysShowZero) { if(!this._minimumSetByUser && this._minimum > 0 && this._maximum > 0) { this._minimum = 0; } else if(!this._maximumSetByUser && this._minimum < 0 && this._maximum < 0) { this._maximum = 0; } } } /** * @private * Increases the maximum and decreases the minimum based on the major unit. */ private function adjustMinAndMaxFromMajorUnit():void { //adjust the maximum so that it appears on a major unit //but don't change the maximum if the user set it or it is pinned to zero if(!this._maximumSetByUser && !(this.alwaysShowZero && this._maximum == 0)) { var oldMaximum:Number = this._maximum; this._maximum = NumberUtil.roundUpToNearest(this._maximum, this._majorUnit); //uncomment to include an additional major unit in this adjustment if(this._maximum == oldMaximum /*|| this._maximum - oldMaximum < this._majorUnit */) { this._maximum += this._majorUnit; } } //adjust the minimum so that it appears on a major unit //but don't change the minimum if the user set it or it is pinned to zero if(!this._minimumSetByUser && !(this.alwaysShowZero && this._minimum == 0)) { var oldMinimum:Number = this._minimum; this._minimum = NumberUtil.roundDownToNearest(this._minimum, this._majorUnit); //uncomment to include an additional major unit in this adjustment if(this._minimum == oldMinimum /*|| oldMinimum - this._minimum < this._majorUnit*/) { this._minimum -= this._majorUnit; } } } /** * @private * If we're using logarithmic scale, corrects the minimum if it gets set * to a value <= 0. */ private function correctLogScaleMinimum():void { //logarithmic scale can't have a minimum value <= 0. If that's the case, push it up to 1.0 //TODO: Determine if there's a better way to handle this... if(!this._minimumSetByUser && this.scale == ScaleType.LOGARITHMIC && this._minimum <= 0) { //use the dataMinimum if it's between 0 and 1 //otherwise, just use 1 if(this._dataMinimum > 0 && this._dataMinimum < 1) { this._minimum = this._dataMinimum; } else { this._minimum = 1; } } } /** * @private * Calculates a "nice" number for use with major or minor units * on the axis. Only returns numbers similar to 10, 20, 25, and 50. */ private function niceNumber(value:Number):Number { if(value == 0) { return 0; } var count:int = 0; while(value > 10.0e-8) { value /= 10; count++; } //all that division in the while loop up there //could cause rounding errors. Don't you hate that? value = NumberUtil.roundToPrecision(value, 10); if(value > 4.0e-8) { value = 5.0e-8; } else if(value > 2.0e-8) { value = 2.5e-8; } else if(value > 1.0e-8) { value = 2.0e-8; } else { value = 1.0e-8; } for(var i:int = count; i > 0; i--) { value *= 10; } return value; } /** * @private * Swaps the minimum and maximum values, if needed. */ private function checkMinLessThanMax():void { if(this._minimum > this._maximum) { var temp:Number = this._minimum; this._minimum = this._maximum; this._maximum = temp; //be sure to swap these flags too! var temp2:Boolean = this._minimumSetByUser; this._minimumSetByUser = this._maximumSetByUser; this._maximumSetByUser = temp2; } } /** * @private * Calculates the multiplier used to convert a data point to an actual position * on the axis. */ private function calculatePositionMultiplier():void { var range:Number = this.maximum - this.minimum; if(this.scale == ScaleType.LOGARITHMIC) { range = Math.log(this.maximum) - Math.log(this.minimum); } if(range == 0) { this.positionMultiplier = 0; return; } this.positionMultiplier = this.renderer.length / range; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -