12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- //
- // Purpose: Base class for the Axis class which defines axis
- // csale related properties and methods.
- //
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Drawing.Design;
- using FastReport.DataVisualization.Charting.Utilities;
- namespace FastReport.DataVisualization.Charting
- {
- #region Axis enumerations
- /// <summary>
- /// An enumeration of the mode of automatically calculating intervals.
- /// </summary>
- public enum IntervalAutoMode
- {
- /// <summary>
- /// Fixed number of intervals always created on the axis.
- /// </summary>
- FixedCount,
- /// <summary>
- /// Number of axis intervals depends on the axis length.
- /// </summary>
- VariableCount
- }
- /// <summary>
- /// An enumeration of axis position.
- /// </summary>
- internal enum AxisPosition
- {
- /// <summary>
- /// Left position
- /// </summary>
- Left,
- /// <summary>
- /// Right position
- /// </summary>
- Right,
- /// <summary>
- /// Top position
- /// </summary>
- Top,
- /// <summary>
- /// Bottom position
- /// </summary>
- Bottom
- }
- /// <summary>
- /// An enumeration of axis arrow styles.
- /// </summary>
- public enum AxisArrowStyle
- {
- /// <summary>
- /// No arrow
- /// </summary>
- None,
- /// <summary>
- /// Triangle type
- /// </summary>
- Triangle,
- /// <summary>
- /// Sharp triangle type
- /// </summary>
- SharpTriangle,
- /// <summary>
- /// Lines type
- /// </summary>
- Lines
- }
- #endregion
- /// <summary>
- /// The Axis class keeps information about minimum, maximum
- /// and interval values and it is responsible for setting
- /// these values automatically. It also handles
- /// logarithmic and reversed axis.
- /// </summary>
- public partial class Axis
- {
- #region Axis scale fields
- // Represents the distance between the data points and its
- // chart area margin, Measured as a percentage of default
- // margin size.
- internal double margin = 100.0;
- internal double marginView = 0.0;
- internal bool offsetTempSet = false;
- // Used for column chart margin
- internal double marginTemp = 0.0;
- private ArrayList _stripLineOffsets = new ArrayList();
-
- // Data members, which store properties values
- private bool _isLogarithmic = false;
- internal double logarithmBase = 10.0;
- internal bool isReversed = false;
- internal bool isStartedFromZero = true;
- internal TickMark minorTickMark = null;
- internal TickMark majorTickMark = null;
- internal Grid minorGrid = null;
- internal Grid majorGrid = null;
- internal bool enabled = false;
- internal bool autoEnabled = true;
- internal LabelStyle labelStyle = null;
- private DateTimeIntervalType _internalIntervalType = DateTimeIntervalType.Auto;
- internal double maximum = Double.NaN;
- internal double crossing = Double.NaN;
- internal double minimum = Double.NaN;
- // Temporary Minimum and maximum values.
- internal double tempMaximum = Double.NaN;
- internal double tempMinimum = Double.NaN;
- internal double tempCrossing = Double.NaN;
- internal CustomLabelsCollection tempLabels;
- internal bool tempAutoMaximum = true;
- internal bool tempAutoMinimum = true;
- internal double tempMajorGridInterval = Double.NaN;
- internal double tempMinorGridInterval = 0.0;
- internal double tempMajorTickMarkInterval = Double.NaN;
- internal double tempMinorTickMarkInterval = 0.0;
- internal double tempLabelInterval = Double.NaN;
- internal DateTimeIntervalType tempGridIntervalType = DateTimeIntervalType.NotSet;
- internal DateTimeIntervalType tempTickMarkIntervalType = DateTimeIntervalType.NotSet;
- internal DateTimeIntervalType tempLabelIntervalType = DateTimeIntervalType.NotSet;
- // Paint mode
- internal bool paintMode = false;
- // Axis type (X, Y, X2, Y2)
- internal AxisName axisType = AxisName.X;
- // Automatic maximum value (from data point values).
- private bool _autoMaximum = true;
- // Automatic minimum value (from data point values).
- private bool _autoMinimum = true;
-
- /// <summary>
- /// Axis position: Left, Right, Top Bottom
- /// </summary>
- private AxisPosition _axisPosition = AxisPosition.Left;
- /// <summary>
- /// Opposite Axis for this Axis. Necessary for Crossing.
- /// </summary>
- internal Axis oppositeAxis = null;
- // Axis data scaleView
- private AxisScaleView _scaleView = null;
- // Axis scroll bar class
- internal AxisScrollBar scrollBar = null;
- // For scater chart X values could be rounded.
- internal bool roundedXValues = false;
- // If Axis is logarithmic value shoud be converted to
- // linear only once.
- internal bool logarithmicConvertedToLinear = false;
- // IsLogarithmic minimum value
- internal double logarithmicMinimum;
- // IsLogarithmic maximum value
- internal double logarithmicMaximum;
- // Correction of interval because of
- // 3D Rotation and perspective
- internal double interval3DCorrection = Double.NaN;
- // Axis coordinate convertion optimization fields
- internal bool optimizedGetPosition = false;
- internal double paintViewMax = 0.0;
- internal double paintViewMin = 0.0;
- internal double paintRange = 0.0;
- internal double valueMultiplier = 0.0;
- internal RectangleF paintAreaPosition = RectangleF.Empty;
- internal double paintAreaPositionBottom = 0.0;
- internal double paintAreaPositionRight = 0.0;
- internal double paintChartAreaSize = 0.0;
- // Determines how number of intervals automatically calculated
- private IntervalAutoMode _intervalAutoMode = IntervalAutoMode.FixedCount;
- // True if scale segments are used
- internal bool scaleSegmentsUsed = false;
- // Preffered number of intervals on the axis
- internal int prefferedNumberofIntervals = 5;
- private Stack<Double> _intervalsStore = new Stack<Double>();
- #endregion
- #region Axis scale properties
- /// <summary>
- /// Axis position
- /// </summary>
- [
- Bindable(true),
- DefaultValue(AxisPosition.Left),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeReverse"),
- DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden)
- ]
- virtual internal AxisPosition AxisPosition
- {
- get
- {
- return this._axisPosition;
- }
- set
- {
- this._axisPosition = value;
- #if SUBAXES
- // Update axis position of the sub axis
- if( !((Axis)this).IsSubAxis )
- {
- foreach(SubAxis subAxis in ((Axis)this).SubAxes)
- {
- subAxis._axisPosition = value;
- }
- }
- #endif // SUBAXES
- this.Invalidate();
- }
- }
- /// <summary>
- /// Gets or sets a flag which indicates whether the number of intervals
- /// on the axis is fixed or varies with the axis size.
- /// </summary>
- [
- SRCategory("CategoryAttributeInterval"),
- DefaultValue(IntervalAutoMode.FixedCount),
- SRDescription("DescriptionAttributeIntervalAutoMode"),
- ]
- public IntervalAutoMode IntervalAutoMode
- {
- get
- {
- return this._intervalAutoMode;
- }
- set
- {
- this._intervalAutoMode = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a flag which indicates whether the axis is reversed.
- /// If set to reversed, the values on the axis are in reversed sort order
- /// and the direction of values on the axis is flipped.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(false),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeReverse"),
- ]
- public bool IsReversed
- {
- get
- {
- return isReversed;
- }
- set
- {
- isReversed = value;
- this.Invalidate();
- }
- }
- /// <summary>
- /// Gets or sets a flag which indicates whether the minimum value
- /// of the axis will be automatically set to zero if all data point
- /// values are positive. If there are negative data point values,
- /// the minimum value of the data points will be used.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(true),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeStartFromZero3"),
- ]
- public bool IsStartedFromZero
- {
- get
- {
- return isStartedFromZero;
- }
- set
- {
- isStartedFromZero = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a flag to add a margin to the axis.
- /// If true, a space is added between the first/last data
- /// point and the border of chart area.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(true),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeMargin"),
- ]
- public bool IsMarginVisible
- {
- get
- {
- if( margin > 0 )
- return true;
- else
- return false;
- }
- set
- {
- if( value == true )
- margin = 100;
- else
- margin = 0;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Date and time interval type.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(DateTimeIntervalType.Auto),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeInternalIntervalType"),
- RefreshPropertiesAttribute(RefreshProperties.All),
- ]
- internal DateTimeIntervalType InternalIntervalType
- {
- get
- {
- return _internalIntervalType;
- }
- set
- {
- // Set intervals for labels, grids and tick marks. ( Auto interval type )
- if( tempMajorGridInterval <= 0.0 ||
- (double.IsNaN(tempMajorGridInterval) && ((Axis)this).Interval <= 0.0) )
- {
- majorGrid.intervalType = value;
- }
- if( this.tempMajorTickMarkInterval <= 0.0 ||
- (double.IsNaN(tempMajorTickMarkInterval) && ((Axis)this).Interval <= 0.0) )
- {
- majorTickMark.intervalType = value;
- }
- if( this.tempLabelInterval <= 0.0 ||
- (double.IsNaN(tempLabelInterval) && ((Axis)this).Interval <= 0.0) )
- {
- labelStyle.intervalType = value;
- }
- _internalIntervalType = value;
- this.Invalidate();
- }
- }
- /// <summary>
- /// Sets auto interval values to grids, tick marks
- /// and labels
- /// </summary>
- internal double SetInterval
- {
- set
- {
- if( tempMajorGridInterval <= 0.0 ||
- (double.IsNaN(tempMajorGridInterval) && ((Axis)this).Interval <= 0.0) )
- {
- majorGrid.interval = value;
- }
- if( tempMajorTickMarkInterval <= 0.0 ||
- (double.IsNaN(tempMajorTickMarkInterval) && ((Axis)this).Interval <= 0.0) )
- {
- majorTickMark.interval = value;
- }
- if( tempLabelInterval <= 0.0 ||
- (double.IsNaN(tempLabelInterval) && ((Axis)this).Interval <= 0.0) )
- {
- labelStyle.interval = value;
- }
- this.Invalidate();
- }
- }
- /// <summary>
- /// Sets auto interval values to grids, tick marks
- /// and labels
- /// </summary>
- internal void SetIntervalAndType(double newInterval, DateTimeIntervalType newIntervalType)
- {
- if( tempMajorGridInterval <= 0.0 ||
- (double.IsNaN(tempMajorGridInterval) && ((Axis)this).Interval <= 0.0) )
- {
- majorGrid.interval = newInterval;
- majorGrid.intervalType = newIntervalType;
- }
- if( tempMajorTickMarkInterval <= 0.0 ||
- (double.IsNaN(tempMajorTickMarkInterval) && ((Axis)this).Interval <= 0.0) )
- {
- majorTickMark.interval = newInterval;
- majorTickMark.intervalType = newIntervalType;
- }
- if( tempLabelInterval <= 0.0 ||
- (double.IsNaN(tempLabelInterval) && ((Axis)this).Interval <= 0.0) )
- {
- labelStyle.interval = newInterval;
- labelStyle.intervalType = newIntervalType;
- }
- this.Invalidate();
- }
-
- /// <summary>
- /// Gets or sets the maximum axis value.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(Double.NaN),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeMaximum"),
- TypeConverter(typeof(AxisMinMaxAutoValueConverter))
- ]
- public double Maximum
- {
- get
- {
- // Get maximum
- if (_isLogarithmic && logarithmicConvertedToLinear && !Double.IsNaN(maximum))
- return logarithmicMaximum;
- else
- return maximum;
- }
- set
- {
- // Split a value to maximum and auto maximum
- if( Double.IsNaN(value) )
- {
- _autoMaximum = true;
- maximum = Double.NaN;
- }
- else
- {
- // Set maximum
- maximum = value;
- // Set non linearized Maximum for logarithmic scale
- logarithmicMaximum = value;
- _autoMaximum = false;
- }
- // Reset original property value fields
- ((Axis)this).tempMaximum = maximum;
- // This line is added because of Save ScaleView State August 29, 2003
- // in Web Forms. This place could cause problems with Reset Auto Values.
- ((Axis)this).tempAutoMaximum = _autoMaximum;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the minimum axis value
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(Double.NaN),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeMinimum"),
- TypeConverter(typeof(AxisMinMaxAutoValueConverter))
- ]
- public double Minimum
- {
- get
- {
- // Get minimum
- if (_isLogarithmic && logarithmicConvertedToLinear && !Double.IsNaN(maximum))
- return logarithmicMinimum;
- else
- return minimum;
- }
- set
- {
- // Split a value to minimum and auto minimum
- if( Double.IsNaN(value) )
- {
- _autoMinimum = true;
- minimum = Double.NaN;
- }
- else
- {
- // Set maximum
- minimum = value;
- _autoMinimum = false;
- // Set non linearized Minimum for logarithmic scale
- logarithmicMinimum = value;
- }
- // Reset original property value fields
- ((Axis)this).tempMinimum = minimum;
- // This line is added because of Save ScaleView State August 29, 2003
- // in Web Forms. This place could cause problems with Reset Auto Values.
- ((Axis)this).tempAutoMinimum = _autoMinimum;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the point where axis is crossed by another axis.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(Double.NaN),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeCrossing"),
- TypeConverter(typeof(AxisCrossingValueConverter))
- ]
- virtual public double Crossing
- {
- get
- {
- if( paintMode )
- if (_isLogarithmic)
- return Math.Pow( this.logarithmBase, GetCrossing() );
- else
- return GetCrossing();
- else
- return crossing;
- }
- set
- {
- crossing = value;
- // Reset original property value fields
- ((Axis)this).tempCrossing = crossing;
- this.Invalidate();
- CallOnModifing();
- }
- }
-
- /// <summary>
- /// Enables or disables the axis.
- /// </summary>
- [
- SRCategory("CategoryAttributeMisc"),
- Bindable(true),
- DefaultValue(typeof(AxisEnabled), "Auto"),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeEnabled7"),
- ]
- public AxisEnabled Enabled
- {
- get
- {
- // Take Enabled from two fields: enabled and auto enabled
- if( autoEnabled )
- {
- return AxisEnabled.Auto;
- }
- else if( enabled )
- {
- return AxisEnabled.True;
- }
- else
- {
- return AxisEnabled.False;
- }
- }
- set
- { // Split Enabled to two fields: enabled and auto enabled
- if( value == AxisEnabled.Auto )
- {
- autoEnabled = true;
- }
- else if( value == AxisEnabled.True )
- {
- enabled = true;
- autoEnabled = false;
- }
- else
- {
- enabled = false;
- autoEnabled = false;
- }
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a flag which indicates whether the axis is logarithmic.
- /// Zeros or negative data values are not allowed on logarithmic charts.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(false),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeLogarithmic"),
- ]
- public bool IsLogarithmic
- {
- get
- {
- return _isLogarithmic;
- }
- set
- {
- _isLogarithmic = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Base of the logarithm used in logarithmic scale.
- /// By default, this value is 10.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Bindable(true),
- DefaultValue(10.0),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeLogarithmBase"),
- ]
- public double LogarithmBase
- {
- get
- {
- return logarithmBase;
- }
- set
- {
- if( value < 2.0 )
- {
- throw (new ArgumentOutOfRangeException("value", SR.ExceptionAxisScaleLogarithmBaseInvalid));
- }
- logarithmBase = value;
-
- this.Invalidate();
- CallOnModifing();
- }
- }
- #endregion
- #region Axis Segments and Scale Breaks Properties
- // Field that stores Axis automatic scale breaks style.
- internal AxisScaleBreakStyle axisScaleBreakStyle = null;
- /// <summary>
- /// Gets or sets the style of scale breaks.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- SRDescription("DescriptionAttributeScaleBreakStyle"),
- TypeConverter(typeof(NoNameExpandableObjectConverter)),
- NotifyParentPropertyAttribute(true),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
- ]
- virtual public AxisScaleBreakStyle ScaleBreakStyle
- {
- get
- {
- return this.axisScaleBreakStyle;
- }
- set
- {
- this.axisScaleBreakStyle = value;
- this.axisScaleBreakStyle.axis = (Axis)this;
- //this.Invalidate();
- CallOnModifing();
- }
- }
- // Field that stores axis scale segments
- internal AxisScaleSegmentCollection scaleSegments = null;
- /// <summary>
- /// Axis scale segment collection.
- /// </summary>
- [
- SRCategory("CategoryAttributeScale"),
- Browsable(false),
- EditorBrowsable(EditorBrowsableState.Never),
- SRDescription("DescriptionAttributeAxisScaleSegmentCollection_AxisScaleSegmentCollection"),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
- #if DESIGNER
- Editor(typeof(ChartCollectionEditor), typeof(UITypeEditor))
- #endif
- ]
- internal AxisScaleSegmentCollection ScaleSegments
- {
- get
- {
- return this.scaleSegments;
- }
- }
- #endregion // Axis Segments and Scale Breaks Properties
- #region Axis data scaleView properies and methods
- /// <summary>
- /// Gets or sets the scale view settings of the axis.
- /// </summary>
- [
- SRCategory("CategoryAttributeDataView"),
- Bindable(true),
- SRDescription("DescriptionAttributeView"),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
- TypeConverter(typeof(NoNameExpandableObjectConverter))
- ]
- public AxisScaleView ScaleView
- {
- get
- {
- return _scaleView;
- }
- set
- {
- _scaleView = value;
- _scaleView.axis = (Axis)this;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the scroll bar settings of the axis.
- /// </summary>
- [
- SRCategory("CategoryAttributeDataView"),
- Bindable(true),
- SRDescription("DescriptionAttributeScrollBar"),
- DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
- TypeConverter(typeof(NoNameExpandableObjectConverter))
- ]
- public AxisScrollBar ScrollBar
- {
- get
- {
- return scrollBar;
- }
- set
- {
- scrollBar = value;
- scrollBar.axis = (Axis)this;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets axis data scaleView minimum position.
- /// </summary>
- /// <returns>Axis data scaleView minimum position.</returns>
- internal double ViewMinimum
- {
- get { return _scaleView.ViewMinimum; }
- }
- /// <summary>
- /// Gets axis data scaleView minimum position.
- /// </summary>
- /// <returns>Axis data scaleView minimum position.</returns>
- internal double ViewMaximum
- {
- get { return _scaleView.ViewMaximum; }
- }
- /// <summary>
- /// Gets automatic maximum value (from data point values).
- /// </summary>
- internal bool AutoMaximum
- {
- get { return _autoMaximum; }
- }
- /// <summary>
- /// Gets automatic minimum value (from data point values).
- /// </summary>
- internal bool AutoMinimum
- {
- get { return _autoMinimum; }
- }
- #endregion
- #region Axis position converters methos
- /// <summary>
- /// This function converts axis value to relative position (0-100%).
- /// If an axis has a logarithmic scale, the value is converted to a linear scale.
- /// </summary>
- /// <param name="axisValue">Value from axis.</param>
- /// <returns>Relative position (0-100%).</returns>
- public double GetPosition( double axisValue )
- {
- // Adjust for the IsLogarithmic axis
- if (_isLogarithmic && axisValue != 0.0)
- {
- axisValue = Math.Log( axisValue, this.logarithmBase );
- }
- // Get linear position
- return GetLinearPosition(axisValue);
- }
-
- /// <summary>
- /// This function converts an axis value to relative position (0-100%).
- /// If an axis has a logarithmic scale, the value is converted to a linear scale.
- /// </summary>
- /// <param name="axisValue">Axis value.</param>
- /// <returns>Relative position (0-100%).</returns>
- public double ValueToPosition( double axisValue )
- {
- return GetPosition( axisValue );
- }
-
- /// <summary>
- /// This function converts an axis value to a pixel position.
- /// If an axis has a logarithmic scale, the value is converted to a linear scale.
- /// </summary>
- /// <param name="axisValue">Value from axis.</param>
- /// <returns>Pixel position.</returns>
- public double ValueToPixelPosition( double axisValue )
- {
- // Get relative value
- double val = ValueToPosition(axisValue);
- // Convert it to pixels
- if( AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom )
- {
- val *= (this.Common.ChartPicture.Width - 1) / 100F;
- }
- else
- {
- val *= (this.Common.ChartPicture.Height - 1) / 100F;
- }
- return val;
- }
- /// <summary>
- /// This function converts a relative position to an axis value.
- /// If an axis has a logarithmic scale, the value is converted to a linear scale.
- /// </summary>
- /// <param name="position">Relative position (0-100%).</param>
- /// <returns>Axis value.</returns>
- public double PositionToValue( double position )
- {
- return PositionToValue(position, true);
- }
- /// <summary>
- /// This function converts a relative position to an axis value.
- /// If an axis has a logarithmic scale, the value is converted to a linear scale.
- /// </summary>
- /// <param name="position">Relative position (0-100%).</param>
- /// <param name="validateInput">Indicates if input value range should be checked.</param>
- /// <returns>Axis value.</returns>
- internal double PositionToValue( double position, bool validateInput)
- {
- // Check parameters
- if(validateInput &&
- (position < 0 || position > 100) )
- {
- throw (new ArgumentException(SR.ExceptionAxisScalePositionInvalid, "position"));
- }
- // Check if plot area position was already calculated
- if(PlotAreaPosition == null)
- {
- throw (new InvalidOperationException(SR.ExceptionAxisScalePositionToValueCallFailed));
- }
- // Convert chart picture position to plotting position
- if( AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom )
- position = position - PlotAreaPosition.X;
- else
- position = PlotAreaPosition.Bottom - position;
-
- // The Chart area size
- double ChartArea;
- if( AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom )
- ChartArea = PlotAreaPosition.Width;
- else
- ChartArea = PlotAreaPosition.Height;
-
-
- // The Real range as double
- double viewMax = ViewMaximum;
- double viewMin = ViewMinimum;
- double range = viewMax - viewMin;
- // Avoid division by zero
- double axisValue = 0;
- if( range != 0 )
- {
- // Find axis value from position
- axisValue = range / ChartArea * position;
- }
-
- // Corrected axis value for reversed
- if( isReversed )
- axisValue = viewMax - axisValue;
- else
- axisValue = viewMin + axisValue;
-
- return axisValue;
- }
-
- /// <summary>
- /// This function converts a pixel position to an axis value.
- /// If an axis has a logarithmic scale, the value is converted to a linear scale.
- /// </summary>
- /// <param name="position">Pixel position.</param>
- /// <returns>Axis value.</returns>
- public double PixelPositionToValue( double position )
- {
- // Convert it to pixels
- double val = position;
- if( AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom )
- {
- val *= 100F / ((float)(this.Common.ChartPicture.Width - 1));
- }
- else
- {
- val *= 100F / ((float)(this.Common.ChartPicture.Height - 1));
- }
- // Get from relative position
- return PositionToValue(val);
- }
- #endregion
- #region Axis scale methods
- /// <summary>
- /// Sets axis position. Axis position depends
- /// on crossing and reversed value.
- /// </summary>
- internal void SetAxisPosition()
- {
- // Change position of the axis
- if( GetOppositeAxis().isReversed )
- {
- if( AxisPosition == AxisPosition.Left )
- AxisPosition = AxisPosition.Right;
- else if( AxisPosition == AxisPosition.Right )
- AxisPosition = AxisPosition.Left;
- else if( AxisPosition == AxisPosition.Top )
- AxisPosition = AxisPosition.Bottom;
- else if( AxisPosition == AxisPosition.Bottom )
- AxisPosition = AxisPosition.Top;
- }
- }
- /// <summary>
- /// Sets temporary offset value.
- /// </summary>
- internal void SetTempAxisOffset( )
- {
- if (ChartArea.Series.Count == 0)
- {
- return;
- }
- // Conditions when this code changes margin size: Column chart,
- // margin is turned off, Interval offset is not used for
- // gridlines, tick marks and labels.
- Series ser = ChartArea.GetFirstSeries();
- if( ( ser.ChartType == SeriesChartType.Column ||
- ser.ChartType == SeriesChartType.StackedColumn ||
- ser.ChartType == SeriesChartType.StackedColumn100 ||
- ser.ChartType == SeriesChartType.Bar ||
- ser.ChartType == SeriesChartType.RangeBar ||
- ser.ChartType == SeriesChartType.RangeColumn ||
- ser.ChartType == SeriesChartType.StackedBar ||
- ser.ChartType == SeriesChartType.StackedBar100 ) &&
- margin != 100.0 && !offsetTempSet &&
- this._autoMinimum)
- {
-
- // Find offset correction for Column chart margin.
- double offset;
- marginTemp = margin;
- // Find point width
- // Check if series provide custom value for point width
- double pointWidthSize;
- string strWidth = ser[CustomPropertyName.PointWidth];
- if(strWidth != null)
- {
- pointWidthSize = CommonElements.ParseDouble(strWidth);
- }
- else
- {
- pointWidthSize = 0.8;
- }
-
- margin = ( pointWidthSize / 2 ) * 100;
- offset = ( margin ) / 100;
- double contraOffset = ( 100 - margin ) / 100;
-
- if (this._intervalsStore.Count == 0)
- {
- this._intervalsStore.Push(this.labelStyle.intervalOffset);
- this._intervalsStore.Push(this.majorGrid.intervalOffset);
- this._intervalsStore.Push(this.majorTickMark.intervalOffset);
- this._intervalsStore.Push(this.minorGrid.intervalOffset);
- this._intervalsStore.Push(this.minorTickMark.intervalOffset);
- }
- this.labelStyle.intervalOffset = Double.IsNaN(this.labelStyle.intervalOffset) ? offset : this.labelStyle.intervalOffset + offset;
- this.majorGrid.intervalOffset = Double.IsNaN(this.majorGrid.intervalOffset) ? offset : this.majorGrid.intervalOffset + offset;
- this.majorTickMark.intervalOffset = Double.IsNaN(this.majorTickMark.intervalOffset) ? offset : this.majorTickMark.intervalOffset + offset;
- this.minorGrid.intervalOffset = Double.IsNaN(this.minorGrid.intervalOffset) ? offset : this.minorGrid.intervalOffset + offset;
- this.minorTickMark.intervalOffset = Double.IsNaN(this.minorTickMark.intervalOffset) ? offset : this.minorTickMark.intervalOffset + offset;
- foreach( StripLine strip in ((Axis)(this)).StripLines )
- {
- _stripLineOffsets.Add( strip.IntervalOffset );
- strip.IntervalOffset -= contraOffset;
- }
- offsetTempSet = true;
- }
- }
- /// <summary>
- /// Resets temporary offset value.
- /// </summary>
- internal void ResetTempAxisOffset( )
- {
- if( this.offsetTempSet )
- {
- System.Diagnostics.Debug.Assert(this._intervalsStore.Count == 5, "Fail in interval store count");
- this.minorTickMark.intervalOffset = this._intervalsStore.Pop();
- this.minorGrid.intervalOffset = this._intervalsStore.Pop();
- this.majorTickMark.intervalOffset = this._intervalsStore.Pop();
- this.majorGrid.intervalOffset = this._intervalsStore.Pop();
- this.labelStyle.intervalOffset = this._intervalsStore.Pop();
- int index = 0;
- foreach( StripLine strip in ((Axis)(this)).StripLines )
- {
- if( _stripLineOffsets.Count > index )
- {
- strip.IntervalOffset = (double)_stripLineOffsets[index];
- }
- index++;
- }
- _stripLineOffsets.Clear();
- offsetTempSet = false;
- margin = marginTemp;
- }
- }
- /// <summary>
- /// This function will create auto maximum and minimum values
- /// using the interval. This function will make a gap between
- /// data points and border of the chart area.
- /// </summary>
- /// <param name="inter">Interval</param>
- /// <param name="shouldStartFromZero">True if minimum scale value should start from zero.</param>
- /// <param name="autoMax">Maximum is auto</param>
- /// <param name="autoMin">Minimum is auto</param>
- /// <param name="min">Minimum value</param>
- /// <param name="max">Maximum value</param>
- /// <returns>Interval</returns>
- internal double RoundedValues(
- double inter,
- bool shouldStartFromZero,
- bool autoMax,
- bool autoMin,
- ref double min,
- ref double max )
- {
- // For X Axes
- if( axisType == AxisName.X || axisType == AxisName.X2 )
- {
- if( margin == 0.0 && !this.roundedXValues )
- {
- return inter;
- }
- }
- else // For Y Axes
- {
- // Avoid dividing with 0. There is no gap.
- if( margin == 0.0 )
- {
- return inter;
- }
- }
-
- if( autoMin )
- { // Set minimum value
- if( min < 0.0 || ( !shouldStartFromZero && !ChartArea.stacked ) )
- {
- min = (double)( ((decimal)Math.Ceiling( min / inter ) - 1m ) * (decimal)inter );
- }
- else
- {
- min = 0.0;
- }
- }
- if( autoMax )
- {// Set maximum value
- if( max <= 0.0 && shouldStartFromZero )
- {
- max = 0.0;
- }
- else
- {
- max = (double)( ((decimal)Math.Floor( max / inter ) + 1m ) * (decimal)inter );
- }
- }
- return inter;
- }
- /// <summary>
- /// Recalculates an intelligent interval from real interval.
- /// </summary>
- /// <param name="diff">Real interval.</param>
- /// <returns>Inteligent interval.</returns>
- internal double CalcInterval( double diff )
- {
- // If the interval is zero return error
- if( diff == 0.0 )
- {
- throw (new ArgumentOutOfRangeException("diff", SR.ExceptionAxisScaleIntervalIsZero));
- }
- // If the real interval is > 1.0
- double step = -1;
- double temp = diff;
- while( temp > 1.0 )
- {
- step ++;
- temp = temp / 10.0;
- if( step > 1000 )
- {
- throw (new InvalidOperationException(SR.ExceptionAxisScaleMinimumMaximumInvalid));
- }
- }
-
- // If the real interval is < 1.0
- temp = diff;
- if( temp < 1.0 )
- {
- step = 0;
- }
- while( temp < 1.0 )
- {
- step --;
- temp = temp * 10.0;
- if( step < -1000 )
- {
- throw (new InvalidOperationException(SR.ExceptionAxisScaleMinimumMaximumInvalid));
- }
- }
-
- double power = (this.IsLogarithmic) ? this.logarithmBase : 10.0;
- double tempDiff = diff / Math.Pow( power, step );
- if( tempDiff < 3 )
- tempDiff = 2;
- else if( tempDiff < 7 )
- tempDiff = 5;
- else
- tempDiff = 10;
- // Make a correction of the real interval
- return tempDiff * Math.Pow( power, step );
- }
- /// <summary>
- /// Recalculates a intelligent interval from real interval
- /// obtained from maximum and minimum values
- /// </summary>
- /// <param name="min">Minimum</param>
- /// <param name="max">Maximum</param>
- /// <returns>Auto Interval</returns>
- private double CalcInterval( double min, double max )
- {
- // Approximated interval value
- return CalcInterval( ( max - min ) / 5 );
- }
-
- /// <summary>
- /// Recalculates a intelligent interval from real interval
- /// obtained from maximum, minimum and date type if
- /// the values is date-time value.
- /// </summary>
- /// <param name="min">Minimum value.</param>
- /// <param name="max">Maximum value.</param>
- /// <param name="date">True if date.</param>
- /// <param name="type">Date time interval type.</param>
- /// <param name="valuesType">AxisName of date-time values.</param>
- /// <returns>Auto Interval.</returns>
- internal double CalcInterval(
- double min,
- double max,
- bool date,
- out DateTimeIntervalType type,
- ChartValueType valuesType)
- {
- // AxisName is date time
- if( date )
- {
- DateTime dateTimeMin = DateTime.FromOADate( min );
- DateTime dateTimeMax = DateTime.FromOADate( max );
- TimeSpan timeSpan = dateTimeMax.Subtract( dateTimeMin );
- // Minutes
- double inter = timeSpan.TotalMinutes;
- // For Range less than 60 seconds interval is 5 sec
- if( inter <= 1.0 && valuesType != ChartValueType.Date)
- {
- // Milli Seconds
- double mlSeconds = timeSpan.TotalMilliseconds;
- if(mlSeconds <= 10)
- {
- type = DateTimeIntervalType.Milliseconds;
- return 1;
- }
- if(mlSeconds <= 50)
- {
- type = DateTimeIntervalType.Milliseconds;
- return 4;
- }
- if(mlSeconds <= 200)
- {
- type = DateTimeIntervalType.Milliseconds;
- return 20;
- }
- if(mlSeconds <= 500)
- {
- type = DateTimeIntervalType.Milliseconds;
- return 50;
- }
-
- // Seconds
- double seconds = timeSpan.TotalSeconds;
-
- if(seconds <= 7)
- {
- type = DateTimeIntervalType.Seconds;
- return 1;
- }
- else if(seconds <= 15)
- {
- type = DateTimeIntervalType.Seconds;
- return 2;
- }
- else if(seconds <= 30)
- {
- type = DateTimeIntervalType.Seconds;
- return 5;
- }
- else if(seconds <= 60)
- {
- type = DateTimeIntervalType.Seconds;
- return 10;
- }
- }// For Range less than 120 seconds interval is 10 sec
- else if( inter <= 2.0 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Seconds;
- return 20;
- }// For Range less than 180 seconds interval is 30 sec
- else if( inter <= 3.0 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Seconds;
- return 30;
- }
-
- // For Range less than 10 minutes interval is 1 min
- else if( inter <= 10 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Minutes;
- return 1;
- }
- // For Range less than 20 minutes interval is 1 min
- else if( inter <= 20 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Minutes;
- return 2;
- }// For Range less than 60 minutes interval is 5 min
- else if( inter <= 60 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Minutes;
- return 5;
- }// For Range less than 120 minutes interval is 10 min
- else if( inter <= 120 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Minutes;
- return 10;
- }// For Range less than 180 minutes interval is 30 min
- else if( inter <= 180 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Minutes;
- return 30;
- }
- // For Range less than 12 hours interval is 1 hour
- else if( inter <= 60*12 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Hours;
- return 1;
- }
- // For Range less than 24 hours interval is 4 hour
- else if( inter <= 60*24 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Hours;
- return 4;
- }
- // For Range less than 2 days interval is 6 hour
- else if( inter <= 60*24*2 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Hours;
- return 6;
- }
- // For Range less than 3 days interval is 12 hour
- else if( inter <= 60*24*3 && valuesType != ChartValueType.Date)
- {
- type = DateTimeIntervalType.Hours;
- return 12;
- }
- // For Range less than 10 days interval is 1 day
- else if( inter <= 60*24*10 )
- {
- type = DateTimeIntervalType.Days;
- return 1;
- }
- // For Range less than 20 days interval is 2 day
- else if( inter <= 60*24*20 )
- {
- type = DateTimeIntervalType.Days;
- return 2;
- }
- // For Range less than 30 days interval is 3 day
- else if( inter <= 60*24*30 )
- {
- type = DateTimeIntervalType.Days;
- return 3;
- }
- // For Range less than 2 months interval is 1 week
- else if( inter <= 60*24*30.5*2 )
- {
- type = DateTimeIntervalType.Weeks;
- return 1;
- }
- // For Range less than 5 months interval is 2weeks
- else if( inter <= 60*24*30.5*5 )
- {
- type = DateTimeIntervalType.Weeks;
- return 2;
- }
- // For Range less than 12 months interval is 1 month
- else if( inter <= 60*24*30.5*12 )
- {
- type = DateTimeIntervalType.Months;
- return 1;
- }
- // For Range less than 24 months interval is 3 month
- else if( inter <= 60*24*30.5*24 )
- {
- type = DateTimeIntervalType.Months;
- return 3;
- }
- // For Range less than 48 months interval is 6 months
- else if( inter <= 60*24*30.5*48 )
- {
- type = DateTimeIntervalType.Months;
- return 6;
- }
- // For Range more than 48 months interval is year
- else if( inter >= 60*24*30.5*48 )
- {
- type = DateTimeIntervalType.Years;
- return CalcYearInterval( inter / 60 / 24 / 365 );
- }
- }
- // Else numbers
- type = DateTimeIntervalType.Number;
- return CalcInterval( min, max );
- }
-
- /// <summary>
- /// Recalculates a intelligent interval for years
- /// </summary>
- /// <param name="years">Number of years</param>
- /// <returns>Interval in years</returns>
- private double CalcYearInterval( double years )
- {
- // If the interval is zero return error
- if( years <= 1.0 )
- {
- throw (new ArgumentOutOfRangeException("years", SR.ExceptionAxisScaleIntervalIsLessThen1Year));
- }
- if( years < 5 )
- return 1;
- else if( years < 10 )
- return 2;
-
- // Make a correction of the interval
- return Math.Floor( years / 5 );
- }
- /// <summary>
- /// This method returns the number of units
- /// between min and max.
- /// </summary>
- /// <param name="min">Minimum.</param>
- /// <param name="max">Maximum.</param>
- /// <param name="type">Date type.</param>
- /// <returns>Number of units.</returns>
- private int GetNumOfUnits( double min, double max, DateTimeIntervalType type )
- {
- double current = ChartHelper.GetIntervalSize(min, 1, type);
- return (int)Math.Round((max - min) / current);
- }
- /// <summary>
- /// This method checks if value type is date-time.
- /// </summary>
- /// <returns>Date-time type or Auto.</returns>
- internal ChartValueType GetDateTimeType()
- {
- List<string> list = null;
- ChartValueType dateType = ChartValueType.Auto;
-
- // Check if Value type is date from first series in the axis
- if( axisType == AxisName.X )
- {
- // Check X axes type
- list = ChartArea.GetXAxesSeries( AxisType.Primary, ((Axis)this).SubAxisName );
- if( list.Count == 0 )
- {
- return ChartValueType.Auto;
- }
- if( Common.DataManager.Series[list[0]].IsXValueDateTime() )
- {
- dateType = Common.DataManager.Series[list[0]].XValueType;
- }
- }
- else if( axisType == AxisName.X2 )
- {
- // Check X2 axes type
- list = ChartArea.GetXAxesSeries( AxisType.Secondary, ((Axis)this).SubAxisName );
- if( list.Count == 0 )
- {
- return ChartValueType.Auto;
- }
- if( Common.DataManager.Series[list[0]].IsXValueDateTime() )
- {
- dateType = Common.DataManager.Series[list[0]].XValueType;
- }
- }
- else if( axisType == AxisName.Y )
- {
- // Check Y axes type
- list = ChartArea.GetYAxesSeries( AxisType.Primary, ((Axis)this).SubAxisName );
- if( list.Count == 0 )
- {
- return ChartValueType.Auto;
- }
- if( Common.DataManager.Series[list[0]].IsYValueDateTime() )
- {
- dateType = Common.DataManager.Series[list[0]].YValueType;
- }
- }
- else if( axisType == AxisName.Y2 )
- {
- // Check Y2 axes type
- list = ChartArea.GetYAxesSeries( AxisType.Secondary, ((Axis)this).SubAxisName );
- if( list.Count == 0 )
- {
- return ChartValueType.Auto;
- }
- if( Common.DataManager.Series[list[0]].IsYValueDateTime() )
- {
- dateType = Common.DataManager.Series[list[0]].YValueType;
- }
- }
- return dateType;
- }
- /// <summary>
- /// This method removes "Auto", "min", "max" from crossing
- /// value and creates a double value.
- /// </summary>
- /// <returns>Crossing value</returns>
- private double GetCrossing()
- {
- if( Double.IsNaN(crossing) )
- {
- if( Common.ChartTypeRegistry.GetChartType( (string)ChartArea.ChartTypes[0] ).ZeroCrossing )
- {
- if( ViewMinimum > 0.0 )
- {
- return ViewMinimum;
- }
- else if( ViewMaximum < 0.0 )
- {
- return ViewMaximum;
- }
- else
- {
- return 0.0;
- }
- }
- else
- {
- return ViewMinimum;
- }
- }
- else if( crossing == Double.MaxValue )
- {
- return ViewMaximum;
- }
- else if( crossing == Double.MinValue )
- {
- return ViewMinimum;
- }
- return crossing;
- }
- /// <summary>
- /// Set auto minimum number. The minimum number
- /// which was sent to this function will be used to
- /// estimate a rounded minimum.
- /// </summary>
- /// <param name="min"> This value is a recommendation for the minimum value. </param>
- internal void SetAutoMinimum(double min)
- {
- // Set the minimum
- if( _autoMinimum )
- {
- minimum = min;
- }
- }
-
- /// <summary>
- /// Set auto maximum number. The maximum number
- /// which was sent to this function will be used to
- /// estimate a rounded maximum.
- /// </summary>
- /// <param name="max">This value is a recommendation for the maximum value.</param>
- internal void SetAutoMaximum(double max)
- {
- // Set the maximum
- if( _autoMaximum )
- {
- maximum = max;
- }
- }
- /// <summary>
- /// Find opposite axis of this axis. What is opposite
- /// axis depend on first series in chart area and primary
- /// and secondary X and Y axes for the first series.
- /// </summary>
- /// <returns>Opposite axis</returns>
- internal Axis GetOppositeAxis()
- {
- // Oppoiste axis found
- if (oppositeAxis != null)
- {
- return oppositeAxis;
- }
- List<string> list;
- switch( axisType )
- {
- // X Axis
- case AxisName.X:
- list = ChartArea.GetXAxesSeries( AxisType.Primary, ((Axis)this).SubAxisName );
- // There aren't data series
- if( list.Count == 0 )
- oppositeAxis = ChartArea.AxisY;
- // Take opposite axis from the first series from chart area
- else if( Common.DataManager.Series[list[0]].YAxisType == AxisType.Primary )
- oppositeAxis = ChartArea.AxisY.GetSubAxis(Common.DataManager.Series[list[0]].YSubAxisName);
- else
- oppositeAxis = ChartArea.AxisY2.GetSubAxis(Common.DataManager.Series[list[0]].YSubAxisName);
- break;
- // X2 Axis
- case AxisName.X2:
- list = ChartArea.GetXAxesSeries( AxisType.Secondary, ((Axis)this).SubAxisName );
- // There aren't data series
- if( list.Count == 0 )
- oppositeAxis = ChartArea.AxisY2;
- // Take opposite axis from the first series from chart area
- else if( Common.DataManager.Series[list[0]].YAxisType == AxisType.Primary)
- oppositeAxis = ChartArea.AxisY.GetSubAxis(Common.DataManager.Series[list[0]].YSubAxisName);
- else
- oppositeAxis = ChartArea.AxisY2.GetSubAxis(Common.DataManager.Series[list[0]].YSubAxisName);
- break;
- // Y Axis
- case AxisName.Y:
- list = ChartArea.GetYAxesSeries( AxisType.Primary, ((Axis)this).SubAxisName );
- // There aren't data series
- if( list.Count == 0 )
- oppositeAxis = ChartArea.AxisX;
- // Take opposite axis from the first series from chart area
- else if( Common.DataManager.Series[list[0]].XAxisType == AxisType.Primary )
- oppositeAxis = ChartArea.AxisX.GetSubAxis(Common.DataManager.Series[list[0]].XSubAxisName);
- else
- oppositeAxis = ChartArea.AxisX2.GetSubAxis(Common.DataManager.Series[list[0]].XSubAxisName);
- break;
- // Y2 Axis
- case AxisName.Y2:
- list = ChartArea.GetYAxesSeries( AxisType.Secondary, ((Axis)this).SubAxisName );
- // There aren't data series
- if( list.Count == 0 )
- oppositeAxis = ChartArea.AxisX2;
- // Take opposite axis from the first series from chart area
- else if( Common.DataManager.Series[list[0]].XAxisType == AxisType.Primary )
- oppositeAxis = ChartArea.AxisX.GetSubAxis(Common.DataManager.Series[list[0]].XSubAxisName);
- else
- oppositeAxis = ChartArea.AxisX2.GetSubAxis(Common.DataManager.Series[list[0]].XSubAxisName);
- break;
- }
- return oppositeAxis;
- }
- /// <summary>
- /// This function converts Values from Axes to
- /// linear relative positions.
- /// </summary>
- /// <param name="axisValue">Value from axis.</param>
- /// <returns>Relative position.</returns>
- internal double GetLinearPosition( double axisValue )
- {
- bool circularArea = (ChartArea == null || !ChartArea.chartAreaIsCurcular) ?
- false : true;
- // Check if some value calculation is optimized
- if(!this.optimizedGetPosition)
- {
- paintViewMax = ViewMaximum;
- paintViewMin = ViewMinimum;
- paintRange = paintViewMax - paintViewMin;
- paintAreaPosition = PlotAreaPosition.ToRectangleF();
- // Update position for circular chart area
- if(circularArea)
- {
- paintAreaPosition.Width /= 2.0f;
- paintAreaPosition.Height /= 2.0f;
- }
- paintAreaPositionBottom = paintAreaPosition.Y + paintAreaPosition.Height;
- paintAreaPositionRight = paintAreaPosition.X + paintAreaPosition.Width;
- // The Chart area size
- if( AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom )
- paintChartAreaSize = paintAreaPosition.Width;
- else
- paintChartAreaSize = paintAreaPosition.Height;
- valueMultiplier = 0.0;
- if( paintRange != 0 )
- {
- valueMultiplier = paintChartAreaSize / paintRange;
- }
- }
- // The Chart area pixel size
- double position = valueMultiplier * ( axisValue - paintViewMin);
- // Check if axis scale segments are enabled
- if(this.scaleSegmentsUsed)
- {
- AxisScaleSegment scaleSegment = this.ScaleSegments.FindScaleSegmentForAxisValue(axisValue);
- if(scaleSegment != null)
- {
- double segmentSize = 0.0;
- double segmentPosition = 0.0;
- scaleSegment.GetScalePositionAndSize(paintChartAreaSize, out segmentPosition, out segmentSize);
- // Make sure value do not exceed max possible
- if(!this.ScaleSegments.AllowOutOfScaleValues)
- {
- if(axisValue > scaleSegment.ScaleMaximum)
- {
- axisValue = scaleSegment.ScaleMaximum;
- }
- else if(axisValue < scaleSegment.ScaleMinimum)
- {
- axisValue = scaleSegment.ScaleMinimum;
- }
- }
- double segmentScaleRange = scaleSegment.ScaleMaximum - scaleSegment.ScaleMinimum;
- position = (segmentSize / segmentScaleRange) * (axisValue - scaleSegment.ScaleMinimum);
- position += segmentPosition;
- }
- }
- // Window position
- // (Do Not use .Right or .Bottom methods below) - rounding issue!
- if( isReversed )
- {
- if( AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom )
- position = paintAreaPositionRight - position;
- else
- position = paintAreaPosition.Y + position;
- }
- else
- {
- if( AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom )
- position = paintAreaPosition.X + position;
- else
- position = paintAreaPositionBottom - position;
- }
- return position;
- }
- #endregion
- #region Axis estimate axis methods
- /// <summary>
- /// This function recalculates minimum maximum and interval.
- /// The function uses current values for minimum and maximum to
- /// find rounding values. If the value from the data source for the
- /// maximum value is 376.5 this function will return 380. This function
- /// also set interval type for date
- /// </summary>
- internal void EstimateAxis()
- {
- double axisInterval;
- // Check if veiw size specified without scaleView position
- if(!Double.IsNaN(this.ScaleView.Size))
- {
- // If size set only use axis minimum for scaleView position
- if(Double.IsNaN(this.ScaleView.Position))
- {
- this.ScaleView.Position = this.Minimum;
- }
- }
- // Zooming Mode
- if( !Double.IsNaN(_scaleView.Position) && !Double.IsNaN(_scaleView.Size) )
- {
- double viewMaximum = ViewMaximum;
- double viewMinimum = ViewMinimum;
- // IsLogarithmic axes
- if (this._isLogarithmic)
- {
- viewMaximum = Math.Pow( this.logarithmBase, viewMaximum );
- viewMinimum = Math.Pow( this.logarithmBase, viewMinimum );
- }
- else
- {
- // Add rounding and gap for maximum and minimum
- EstimateAxis( ref this.minimum, ref this.maximum, _autoMaximum, _autoMinimum );
- }
- // Find Interval for Zoom
- axisInterval = EstimateAxis( ref viewMinimum, ref viewMaximum, true, true );
- }
- else // No Zooming mode
- {
- // Estimate axis shoud be always called for non logarithmic axis
- axisInterval = EstimateAxis( ref this.minimum, ref this.maximum, _autoMaximum, _autoMinimum );
- }
- // Set intervals for grids, tick marks and labels
- if( axisInterval <= 0.0 )
- {
- throw (new InvalidOperationException(SR.ExceptionAxisScaleAutoIntervalInvalid));
- }
- else
- {
- // This code checks if all series in the chart area have “integer type”
- // for specified axes, which means int, uint, long and ulong and rounds interval.
- #if SUBAXES
- if( ChartArea.SeriesIntegerType( this.axisType, ((Axis)this).SubAxisName ) )
- #else // SUBAXES
- if ( ChartArea.SeriesIntegerType( this.axisType, string.Empty ))
- #endif // SUBAXES
- {
- axisInterval = Math.Round( axisInterval );
- if( axisInterval == 0.0 )
- {
- axisInterval = 1.0;
- }
- // Round Minimum to floor value if type is integer
- minimum = Math.Floor( minimum );
- }
- SetInterval = axisInterval;
- }
- }
-
- /// <summary>
- /// This function recalculates minimum maximum and interval.
- /// The function uses current values for minimum and maximum to
- /// find rounding values. If the value from the data source for the
- /// maximum value is 376.5 this function will return 380. This function
- /// also set interval type for date
- /// </summary>
- /// <param name="minimumValue">Minimum</param>
- /// <param name="maximumValue">Maximum</param>
- /// <param name="autoMaximum">Maximum value is Auto</param>
- /// <param name="autoMinimum">Minimum value is Auto</param>
- /// <returns>Interval</returns>
- internal double EstimateAxis( ref double minimumValue, ref double maximumValue, bool autoMaximum, bool autoMinimum )
- {
- double axisInterval;
- // The axis minimum value is greater than the maximum value.
- if( maximumValue < minimumValue )
- {
- if(!this.Common.ChartPicture.SuppressExceptions)
- {
- throw (new InvalidOperationException(SR.ExceptionAxisScaleMinimumValueIsGreaterThenMaximumDataPoint));
- }
- else
- {
- // Max axis scale should be always bigger
- double tempValue = maximumValue;
- maximumValue = minimumValue;
- minimumValue = tempValue;
- }
- }
- // Take Value type
- ChartValueType dateType = GetDateTimeType();
-
- // Axis type is logarithmic
- if (_isLogarithmic)
- {
- axisInterval = EstimateLogarithmicAxis( ref minimumValue, ref maximumValue, crossing, autoMaximum, autoMinimum );
- }
-
- // Axis type is date
- else if( dateType != ChartValueType.Auto)
- {
- axisInterval = EstimateDateAxis( ref minimumValue, ref maximumValue, autoMaximum, autoMinimum, dateType );
- }
-
- // Axis type is number
- else
- {
- axisInterval = EstimateNumberAxis( ref minimumValue, ref maximumValue, this.IsStartedFromZero, this.prefferedNumberofIntervals, autoMaximum, autoMinimum );
- }
- // Set intervals for grids, tick marks and labels
- if( axisInterval <= 0.0 )
- {
- throw (new InvalidOperationException(SR.ExceptionAxisScaleAutoIntervalInvalid));
- }
- else
- {
- // Set interval for Grid lines Tick Marks and labels
- SetInterval = axisInterval;
- }
- return axisInterval;
- }
- /// <summary>
- /// This function recalculates minimum maximum and interval for
- /// logarithmic axis. The function uses current values for minimum and
- /// maximum to find new rounding values.
- /// </summary>
- /// <param name="minimumValue">Current Minimum value</param>
- /// <param name="maximumValue">Current Maximum value</param>
- /// <param name="crossingValue">Crossing value</param>
- /// <param name="autoMaximum">Maximum value is Auto</param>
- /// <param name="autoMinimum">Minimum value is Auto</param>
- /// <returns>Interval</returns>
- private double EstimateLogarithmicAxis( ref double minimumValue, ref double maximumValue, double crossingValue, bool autoMaximum, bool autoMinimum )
- {
- double axisInterval;
- if( !logarithmicConvertedToLinear )
- {
- // Remember values. Do not use POW function because of rounding.
- this.logarithmicMinimum = this.minimum;
- this.logarithmicMaximum = this.maximum;
- }
- // For log axis margin always turn on.
- margin = 100;
- // Supress zero and negative values with logarithmic axis exceptions
- if(this.Common != null && this.Common.Chart != null && this.Common.Chart.chartPicture.SuppressExceptions)
- {
- if (minimumValue <= 0.0 )
- {
- minimumValue = 1.0;
- }
- if (maximumValue <= 0.0 )
- {
- maximumValue = 1.0;
- }
- if (crossingValue <= 0.0 && crossingValue != Double.MinValue )
- {
- crossingValue = 1.0;
- }
- }
- // The logarithmic axes can not show negative values.
- if( minimumValue <= 0.0 || maximumValue <= 0.0 || crossingValue <= 0.0 )
- {
- if (minimumValue <= 0.0 )
- throw (new ArgumentOutOfRangeException("minimumValue", SR.ExceptionAxisScaleLogarithmicNegativeValues));
- if (maximumValue <= 0.0 )
- throw (new ArgumentOutOfRangeException("maximumValue", SR.ExceptionAxisScaleLogarithmicNegativeValues));
- }
- // Change crossing to linear scale
- crossingValue = Math.Log( crossingValue, this.logarithmBase );
- // Change minimum and maximum to linear scale
- minimumValue = Math.Log( minimumValue, this.logarithmBase );
- maximumValue = Math.Log( maximumValue, this.logarithmBase );
- logarithmicConvertedToLinear = true;
-
- // Find interval - Make approximately 5 grid lines and labels.
- double diff = ( maximumValue - minimumValue ) / 5;
- // Make good interval for logarithmic scale
- axisInterval = Math.Floor( diff );
- if( axisInterval == 0 ) axisInterval = 1;
- if( autoMinimum && autoMaximum )
- {
- // The maximum and minimum rounding with interval
- RoundedValues( axisInterval, this.IsStartedFromZero, autoMaximum, autoMinimum, ref minimumValue, ref maximumValue );
- }
-
- // Do not allow min/max values more than a hundred
- if(ChartArea.hundredPercent)
- {
- if(autoMinimum)
- {
- if(minimumValue < 0)
- minimumValue = 0;
- }
- if(autoMaximum)
- {
- if(maximumValue > 2)
- maximumValue = 2;
- }
- }
- // Set interval for Grid lines Tick Marks and labels
- return axisInterval;
- }
- /// <summary>
- /// This function recalculates minimum maximum and interval for
- /// Date axis. The function uses current values for minimum and
- /// maximum to find new rounding values.
- /// </summary>
- /// <param name="minimumValue">Current Minimum value</param>
- /// <param name="maximumValue">Current Maximum value</param>
- /// <param name="autoMaximum">Maximum value is Auto</param>
- /// <param name="autoMinimum">Minimum value is Auto</param>
- /// <param name="valuesType">AxisName of date-time values.</param>
- /// <returns>Interval</returns>
- private double EstimateDateAxis(
- ref double minimumValue,
- ref double maximumValue,
- bool autoMaximum,
- bool autoMinimum,
- ChartValueType valuesType)
- {
- double axisInterval;
- double min = minimumValue;
- double max = maximumValue;
- // Find interval for this date type
- axisInterval = CalcInterval(min, max, true, out _internalIntervalType, valuesType);
- // For 3D Charts interval could be changed. After rotation
- // projection of axis could be very small.
- if( !double.IsNaN( this.interval3DCorrection ) &&
- ChartArea.Area3DStyle.Enable3D &&
- !ChartArea.chartAreaIsCurcular)
- {
- axisInterval = Math.Floor( axisInterval / this.interval3DCorrection );
- this.interval3DCorrection = double.NaN;
- }
- // Find number of units between minimum and maximum
- int numberOfUnits = GetNumOfUnits( min, max, _internalIntervalType );
- // Make a gap between max point and axis for Y axes
- if( axisType == AxisName.Y || axisType == AxisName.Y2 )
- {
- if (autoMinimum && minimumValue > ChartHelper.GetIntervalSize(min, axisInterval, _internalIntervalType))
- {
- // Add gap to the minimum value from the series
- // equal half of the interval
- minimumValue += ChartHelper.GetIntervalSize(
- min,
- - (axisInterval / 2.0) * margin / 100,
- _internalIntervalType,
- null,
- 0.0,
- DateTimeIntervalType.Number,
- false,
- false);
- // Align minimum sacale value on the interval
- minimumValue = ChartHelper.AlignIntervalStart(
- minimumValue,
- axisInterval * margin / 100,
- _internalIntervalType);
- }
- // Increase maximum if not zero. Make a space between chart type
- // and the end of the chart area.
- if( autoMaximum && max > 0 && margin != 0.0 )
- {
- maximumValue = minimumValue + ChartHelper.GetIntervalSize(
- minimumValue,
- (double)((Math.Floor(numberOfUnits / axisInterval / margin * 100)+2) * axisInterval * margin / 100),
- _internalIntervalType);
- }
- }
- InternalIntervalType = _internalIntervalType;
- // Set interval for Grid lines Tick Marks and labels
- return axisInterval;
- }
-
- /// <summary>
- /// This function recalculates minimum maximum and interval for
- /// number type axis. The function uses current values for minimum and
- /// maximum to find new rounding values.
- /// </summary>
- /// <param name="minimumValue">Current Minimum value</param>
- /// <param name="maximumValue">Current Maximum value</param>
- /// <param name="shouldStartFromZero">Should start from zero flag.</param>
- /// <param name="preferredNumberOfIntervals">Preferred number of intervals. Can be set to zero for dynamic mode.</param>
- /// <param name="autoMaximum">Maximum value is Auto</param>
- /// <param name="autoMinimum">Minimum value is Auto</param>
- /// <returns>Interval</returns>
- internal double EstimateNumberAxis(
- ref double minimumValue,
- ref double maximumValue,
- bool shouldStartFromZero,
- int preferredNumberOfIntervals,
- bool autoMaximum,
- bool autoMinimum )
- {
- double axisInterval;
- double min = minimumValue;
- double max = maximumValue;
- double diff;
- if( !roundedXValues && ( axisType == AxisName.X || axisType == AxisName.X2 ) )
- {
- diff = ChartArea.GetPointsInterval( false, 10 );
- if( diff == 0 || ( max - min ) / diff > 20 )
- {
- diff = ( max - min ) / preferredNumberOfIntervals;
- }
-
- }
- else
- {
- diff = ( max - min ) / preferredNumberOfIntervals;
- }
- // For 3D Charts interval could be changed. After rotation
- // projection of axis could be very small.
- if( !double.IsNaN( this.interval3DCorrection ) &&
- ChartArea.Area3DStyle.Enable3D &&
- !ChartArea.chartAreaIsCurcular)
- {
- diff = diff / this.interval3DCorrection;
- // Do not change minimum and maximum with 3D correction.
- if( max - min < diff )
- {
- diff = max - min;
- }
- this.interval3DCorrection = double.NaN;
- if( diff != 0.0 )
- {
- diff = CalcInterval( diff );
- }
- }
-
- if( autoMaximum || autoMinimum )
- {
- if( diff == 0 )
- {
- // Can not find interval. Minimum and maximum are same
- max = min + 1;
- diff = 0.2;
- axisInterval = 0.2;
- }
- else
- {
- axisInterval = CalcInterval( diff );
- }
- }
- else
- {
- axisInterval = diff;
- }
- // Case when minimum or maximum is set and interval is > maximum.
- // Reasons overflow exception.
- if( ((Axis)this).interval != 0 && ((Axis)this).interval > axisInterval && minimumValue + ((Axis)this).interval > maximumValue )
- {
- axisInterval = ((Axis)this).interval;
- if( autoMaximum )
- {
- maximumValue = minimumValue + axisInterval;
- }
- if( autoMinimum )
- {
- minimumValue = maximumValue - axisInterval;
- }
- }
- // The maximum and minimum rounding for Y Axes
- if( axisType == AxisName.Y || axisType == AxisName.Y2 || ( roundedXValues && ( axisType == AxisName.X || axisType == AxisName.X2 )))
- {
- // Start from zero for the 100% chart types
- bool minIsZero = false;
- bool maxIsZero = false;
- if(ChartArea.hundredPercent)
- {
- minIsZero = (minimumValue == 0.0);
- maxIsZero = (maximumValue == 0.0);
- }
- // Round min/max values
- RoundedValues( axisInterval, shouldStartFromZero, autoMaximum, autoMinimum, ref minimumValue, ref maximumValue );
- // Do not allow min/max values more than a hundred
- if(ChartArea.hundredPercent)
- {
- if(autoMinimum)
- {
- if(minimumValue < -100)
- minimumValue = -100;
- if(minIsZero)
- minimumValue = 0;
- }
- if(autoMaximum)
- {
- if(maximumValue > 100)
- maximumValue = 100;
- if(maxIsZero)
- maximumValue = 0;
- }
- }
- }
- // Set interval for Grid lines Tick Marks and labels
- return axisInterval;
- }
- #endregion
- }
- }
|