123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754 |
- // 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: LabelStyle and CustomLabel classes are used to determine
- // chart axis labels. Labels can be automatically
- // generated based on the series data or be “manually”
- // set by the user.
- //
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Drawing.Design;
- using System.Drawing.Drawing2D;
- using FastReport.DataVisualization.Charting.ChartTypes;
- using FastReport.DataVisualization.Charting.Utilities;
- namespace FastReport.DataVisualization.Charting
- {
- #region Labels enumerations
- /// <summary>
- /// An enumeration that specifies a mark for custom labels.
- /// </summary>
- public enum LabelMarkStyle
- {
- /// <summary>
- /// No label marks are used.
- /// </summary>
- None,
- /// <summary>
- /// Labels use side marks.
- /// </summary>
- SideMark,
- /// <summary>
- /// Labels use line and side marks.
- /// </summary>
- LineSideMark,
- /// <summary>
- /// Draws a box around the label. The box always starts at the axis position.
- /// </summary>
- Box
- };
- /// <summary>
- /// An enumeration of custom grid lines and tick marks flags used in the custom labels.
- /// </summary>
- [Flags]
- public enum GridTickTypes
- {
- /// <summary>
- /// No tick mark or grid line are shown.
- /// </summary>
- None = 0,
- /// <summary>
- /// Tick mark is shown.
- /// </summary>
- TickMark = 1,
- /// <summary>
- /// Grid line is shown.
- /// </summary>
- Gridline = 2,
- /// <summary>
- /// Tick mark and grid line are shown.
- /// </summary>
- All = TickMark | Gridline
- }
- /// <summary>
- /// An enumeration of label styles for circular chart area axis.
- /// </summary>
- internal enum CircularAxisLabelsStyle
- {
- /// <summary>
- /// Style depends on number of labels.
- /// </summary>
- Auto,
- /// <summary>
- /// Label text positions around the circular area.
- /// </summary>
- Circular,
- /// <summary>
- /// Label text is always horizontal.
- /// </summary>
- Horizontal,
- /// <summary>
- /// Label text has the same angle as circular axis.
- /// </summary>
- Radial
- }
- #endregion
- /// <summary>
- /// The CustomLabelsCollection class is a strongly typed collection of
- /// custom axis labels.
- /// </summary>
- [
- SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
- ]
- public class CustomLabelsCollection : ChartElementCollection<CustomLabel>
- {
- #region Constructors
- /// <summary>
- /// Custom labels collection object constructor
- /// </summary>
- /// <param name="axis">Reference to the axis object.</param>
- internal CustomLabelsCollection(Axis axis) : base(axis)
- {
- }
- #endregion
- #region Properties
- internal Axis Axis
- {
- get { return Parent as Axis; }
- }
- #endregion
- #region Labels adding methods
- /// <summary>
- /// Adds a custom label into the collection.
- /// </summary>
- /// <param name="fromPosition">Label left position.</param>
- /// <param name="toPosition">Label right position.</param>
- /// <param name="text">Label text.</param>
- /// <returns>Newly added item.</returns>
- public CustomLabel Add(double fromPosition, double toPosition, string text)
- {
- CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
- Add(label);
- return label;
- }
- /// <summary>
- /// Adds one custom label into the collection. Custom label flag may be specified.
- /// </summary>
- /// <param name="fromPosition">Label left position.</param>
- /// <param name="toPosition">Label right position.</param>
- /// <param name="text">Label text.</param>
- /// <param name="customLabel">Indicates if label is custom (created by user).</param>
- /// <returns>Newly added item.</returns>
- internal CustomLabel Add(double fromPosition, double toPosition, string text, bool customLabel)
- {
- CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
- label.customLabel = customLabel;
- Add(label);
- return label;
- }
- /// <summary>
- /// Adds a custom label into the collection.
- /// </summary>
- /// <param name="fromPosition">Label left position.</param>
- /// <param name="toPosition">Label right position.</param>
- /// <param name="text">Label text.</param>
- /// <param name="rowIndex">Label row index.</param>
- /// <param name="markStyle">Label marking style.</param>
- /// <returns>Newly added item.</returns>
- public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle)
- {
- CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle);
- Add(label);
- return label;
- }
- /// <summary>
- /// Adds a custom label into the collection.
- /// </summary>
- /// <param name="fromPosition">Label left position.</param>
- /// <param name="toPosition">Label right position.</param>
- /// <param name="text">Label text.</param>
- /// <param name="rowIndex">Label row index.</param>
- /// <param name="markStyle">Label marking style.</param>
- /// <returns>Index of newly added item.</returns>
- /// <param name="gridTick">Custom grid line and tick mark flag.</param>
- public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle, GridTickTypes gridTick)
- {
- CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle, gridTick);
- Add(label);
- return label;
- }
- /// <summary>
- /// Adds multiple custom labels to the collection.
- /// The labels will be DateTime labels with the specified interval type,
- /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
- /// </summary>
- /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
- /// <param name="intervalType">Unit of measurement of the label step.</param>
- /// <param name="min">Minimum value..</param>
- /// <param name="max">Maximum value..</param>
- /// <param name="format">Label text format.</param>
- /// <param name="rowIndex">Label row index.</param>
- /// <param name="markStyle">Label marking style.</param>
- public void Add(double labelsStep, DateTimeIntervalType intervalType, double min, double max, string format, int rowIndex, LabelMarkStyle markStyle)
- {
- // Find labels range min/max values
- if(min == 0.0 &&
- max == 0.0 &&
- this.Axis != null &&
- !double.IsNaN(this.Axis.Minimum) &&
- !double.IsNaN(this.Axis.Maximum))
- {
- min = this.Axis.Minimum;
- max = this.Axis.Maximum;
- }
- double fromX = Math.Min(min, max);
- double toX = Math.Max(min, max);
- this.SuspendUpdates();
- try
- {
- // Loop through all label points
- double labelStart = fromX;
- double labelEnd = 0;
- while (labelStart < toX)
- {
- // Determine label end location
- if (intervalType == DateTimeIntervalType.Number)
- {
- labelEnd = labelStart + labelsStep;
- }
- else if (intervalType == DateTimeIntervalType.Milliseconds)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddMilliseconds(labelsStep).ToOADate();
- }
- else if (intervalType == DateTimeIntervalType.Seconds)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddSeconds(labelsStep).ToOADate();
- }
- else if (intervalType == DateTimeIntervalType.Minutes)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddMinutes(labelsStep).ToOADate();
- }
- else if (intervalType == DateTimeIntervalType.Hours)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddHours(labelsStep).ToOADate();
- }
- else if (intervalType == DateTimeIntervalType.Days)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddDays(labelsStep).ToOADate();
- }
- else if (intervalType == DateTimeIntervalType.Weeks)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddDays(7 * labelsStep).ToOADate();
- }
- else if (intervalType == DateTimeIntervalType.Months)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddMonths((int)labelsStep).ToOADate();
- }
- else if (intervalType == DateTimeIntervalType.Years)
- {
- labelEnd = DateTime.FromOADate(labelStart).AddYears((int)labelsStep).ToOADate();
- }
- else
- {
- // Unsupported step type
- throw (new ArgumentException(SR.ExceptionAxisLabelsIntervalTypeUnsupported(intervalType.ToString())));
- }
- if (labelEnd > toX)
- {
- labelEnd = toX;
- }
- // Generate label text
- ChartValueType valueType = ChartValueType.Double;
- if (intervalType != DateTimeIntervalType.Number)
- {
- if (this.Axis.GetAxisValuesType() == ChartValueType.DateTimeOffset)
- valueType = ChartValueType.DateTimeOffset;
- else
- valueType = ChartValueType.DateTime;
- }
- string text = ValueConverter.FormatValue(
- this.Common.Chart,
- this.Axis,
- null,
- labelStart + (labelEnd - labelStart) / 2,
- format,
- valueType,
- ChartElementType.AxisLabels);
- // Add label
- CustomLabel label = new CustomLabel(labelStart, labelEnd, text, rowIndex, markStyle);
- this.Add(label);
- labelStart = labelEnd;
- }
- }
- finally
- {
- this.ResumeUpdates();
- }
- }
- /// <summary>
- /// Adds multiple custom labels to the collection.
- /// The labels will be DateTime labels with the specified interval type,
- /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
- /// </summary>
- /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
- /// <param name="intervalType">Unit of measurement of the label step.</param>
- public void Add(double labelsStep, DateTimeIntervalType intervalType)
- {
- Add(labelsStep, intervalType, 0, 0, "", 0, LabelMarkStyle.None);
- }
- /// <summary>
- /// Adds multiple custom labels to the collection.
- /// The labels will be DateTime labels with the specified interval type,
- /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
- /// </summary>
- /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
- /// <param name="intervalType">Unit of measurement of the label step.</param>
- /// <param name="format">Label text format.</param>
- public void Add(double labelsStep, DateTimeIntervalType intervalType, string format)
- {
- Add(labelsStep, intervalType, 0, 0, format, 0, LabelMarkStyle.None);
- }
- /// <summary>
- /// Adds multiple custom labels to the collection.
- /// The labels will be DateTime labels with the specified interval type,
- /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
- /// </summary>
- /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
- /// <param name="intervalType">Unit of measurement of the label step.</param>
- /// <param name="format">Label text format.</param>
- /// <param name="rowIndex">Label row index.</param>
- /// <param name="markStyle">Label marking style.</param>
- public void Add(double labelsStep, DateTimeIntervalType intervalType, string format, int rowIndex, LabelMarkStyle markStyle)
- {
- Add(labelsStep, intervalType, 0, 0, format, rowIndex, markStyle);
- }
- #endregion
- }
- /// <summary>
- /// The CustomLabel class represents a single custom axis label. Text and
- /// position along the axis is provided by the caller.
- /// </summary>
- [
- SRDescription("DescriptionAttributeCustomLabel_CustomLabel"),
- DefaultProperty("Text"),
- ]
- public class CustomLabel : ChartNamedElement
- {
- #region Fields and Constructors
- // Private data members, which store properties values
- private double _fromPosition = 0;
- private double _toPosition = 0;
- private string _text = "";
- private LabelMarkStyle _labelMark = LabelMarkStyle.None;
- private Color _foreColor = Color.Empty;
- private Color _markColor = Color.Empty;
- private int _labelRowIndex = 0;
- // Custom grid lines and tick marks flags
- private GridTickTypes _gridTick = GridTickTypes.None;
- // Indicates if label was automatically created or cpecified by user (custom)
- internal bool customLabel = true;
- // Image associated with the label
- private string _image = string.Empty;
- // Image transparent color
- private Color _imageTransparentColor = Color.Empty;
- // Label tooltip
- private string _tooltip = string.Empty;
- private Axis _axis = null;
- #endregion
- #region Constructors
- /// <summary>
- /// Default constructor
- /// </summary>
- public CustomLabel()
- {
- }
- /// <summary>
- /// CustomLabel constructor
- /// </summary>
- /// <param name="fromPosition">From position.</param>
- /// <param name="toPosition">To position.</param>
- /// <param name="text">Label text.</param>
- /// <param name="labelRow">Label row index.</param>
- /// <param name="markStyle">Label mark style.</param>
- public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle)
- {
- this._fromPosition = fromPosition;
- this._toPosition = toPosition;
- this._text = text;
- this._labelRowIndex = labelRow;
- this._labelMark = markStyle;
- this._gridTick = GridTickTypes.None;
- }
- /// <summary>
- /// CustomLabel constructor
- /// </summary>
- /// <param name="fromPosition">From position.</param>
- /// <param name="toPosition">To position.</param>
- /// <param name="text">Label text.</param>
- /// <param name="labelRow">Label row index.</param>
- /// <param name="markStyle">Label mark style.</param>
- /// <param name="gridTick">Custom grid line and tick marks flag.</param>
- public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle, GridTickTypes gridTick)
- {
- this._fromPosition = fromPosition;
- this._toPosition = toPosition;
- this._text = text;
- this._labelRowIndex = labelRow;
- this._labelMark = markStyle;
- this._gridTick = gridTick;
- }
- #endregion
- #region Helper methods
- /// <summary>
- /// Returns a cloned label object.
- /// </summary>
- /// <returns>Copy of current custom label.</returns>
- public CustomLabel Clone()
- {
- CustomLabel newLabel = new CustomLabel();
- newLabel.FromPosition = this.FromPosition;
- newLabel.ToPosition = this.ToPosition;
- newLabel.Text = this.Text;
- newLabel.ForeColor = this.ForeColor;
- newLabel.MarkColor = this.MarkColor;
- newLabel.RowIndex = this.RowIndex;
- newLabel.LabelMark = this.LabelMark;
- newLabel.GridTicks = this.GridTicks;
- newLabel.ToolTip = this.ToolTip;
- newLabel.Tag = this.Tag;
- newLabel.Image = this.Image;
- newLabel.ImageTransparentColor = this.ImageTransparentColor;
- return newLabel;
- }
- internal override IChartElement Parent
- {
- get
- {
- return base.Parent;
- }
- set
- {
- base.Parent = value;
- if (value != null)
- {
- _axis = Parent.Parent as Axis;
- }
- }
- }
- /// <summary>
- /// Gets the axis to which this object is attached to.
- /// </summary>
- /// <returns>Axis.</returns>
- [
- Browsable(false),
- DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden),
- ]
- public Axis Axis
- {
- get
- {
- return _axis;
- }
- }
- #endregion
- #region CustomLabel properties
- /// <summary>
- /// Gets or sets the tooltip of the custom label.
- /// </summary>
- [
- SRCategory("CategoryAttributeMapArea"),
- Bindable(true),
- SRDescription("DescriptionAttributeToolTip"),
- DefaultValue("")
- ]
- public string ToolTip
- {
- set
- {
- this._tooltip = value;
- }
- get
- {
- return this._tooltip;
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the label image.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(""),
- SRDescription("DescriptionAttributeCustomLabel_Image"),
- #if DESIGNER
- Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
- #endif
- NotifyParentPropertyAttribute(true)
- ]
- public string Image
- {
- get
- {
- return _image;
- }
- set
- {
- _image = value;
- Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a color which will be replaced with a transparent color while drawing the image.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- NotifyParentPropertyAttribute(true),
- SRDescription("DescriptionAttributeImageTransparentColor"),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color ImageTransparentColor
- {
- get
- {
- return _imageTransparentColor;
- }
- set
- {
- _imageTransparentColor = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Custom label name. This property is for internal use only.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- SRDescription("DescriptionAttributeCustomLabel_Name"),
- DefaultValue("Custom LabelStyle"),
- DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
- DesignOnlyAttribute(true),
- SerializationVisibilityAttribute(SerializationVisibility.Hidden)
- ]
- public override string Name
- {
- get
- {
- return base.Name;
- }
- set
- {
- base.Name = value;
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a property which specifies whether
- /// custom tick marks and grid lines will be drawn in the center of the label.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(GridTickTypes.None),
- SRDescription("DescriptionAttributeCustomLabel_GridTicks"),
- #if DESIGNER
- Editor(typeof(FlagsEnumUITypeEditor), typeof(UITypeEditor))
- #endif
- ]
- public GridTickTypes GridTicks
- {
- get
- {
- return _gridTick;
- }
- set
- {
- _gridTick = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the end position of the custom label in axis coordinates.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(0.0),
- SRDescription("DescriptionAttributeCustomLabel_From"),
- TypeConverter(typeof(AxisLabelDateValueConverter))
- ]
- public double FromPosition
- {
- get
- {
- return _fromPosition;
- }
- set
- {
- _fromPosition = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the starting position of the custom label in axis coordinates.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(0.0),
- SRDescription("DescriptionAttributeCustomLabel_To"),
- TypeConverter(typeof(AxisLabelDateValueConverter))
- ]
- public double ToPosition
- {
- get
- {
- return _toPosition;
- }
- set
- {
- _toPosition = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the text of the custom label.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(""),
- SRDescription("DescriptionAttributeCustomLabel_Text")
- ]
- public string Text
- {
- get
- {
- return _text;
- }
- set
- {
- _text = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the text color of the custom label.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeForeColor"),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color ForeColor
- {
- get
- {
- return _foreColor;
- }
- set
- {
- _foreColor = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the color of the label mark line of the custom label.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), ""),
- SRDescription("DescriptionAttributeCustomLabel_MarkColor"),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color MarkColor
- {
- get
- {
- return _markColor;
- }
- set
- {
- _markColor = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the row index of the custom label.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(0),
- SRDescription("DescriptionAttributeCustomLabel_RowIndex")
- ]
- public int RowIndex
- {
- get
- {
- return this._labelRowIndex;
- }
- set
- {
- if(value < 0)
- {
- throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexIsNegative));
- }
- this._labelRowIndex = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a property which define the marks for the labels in the second row.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(LabelMarkStyle.None),
- SRDescription("DescriptionAttributeCustomLabel_LabelMark")
- ]
- public LabelMarkStyle LabelMark
- {
- get
- {
- return _labelMark;
- }
- set
- {
- _labelMark = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- #endregion
- }
- /// <summary>
- /// The LabelStyle class contains properties which define the visual appearance of
- /// the axis labels, their interval and position. This class is also
- /// responsible for calculating the position of all the labels and
- /// drawing them.
- /// </summary>
- [
- SRDescription("DescriptionAttributeLabel_Label"),
- DefaultProperty("Enabled"),
- ]
- public class LabelStyle : ChartElement
- {
- #region Fields
- // Reference to the Axis
- private Axis _axis = null;
- // Private data members, which store properties values
- private bool _enabled = true;
- internal double intervalOffset = double.NaN;
- internal double interval = double.NaN;
- internal DateTimeIntervalType intervalType = DateTimeIntervalType.NotSet;
- internal DateTimeIntervalType intervalOffsetType = DateTimeIntervalType.NotSet;
- private FontCache _fontCache = new FontCache();
- private Font _font;
- private Color _foreColor = Color.Black;
- internal int angle = 0;
- internal bool isStaggered = false;
- private bool _isEndLabelVisible = true;
- private bool _truncatedLabels = false;
- private string _format = "";
- #endregion
- #region Constructors
- /// <summary>
- /// Public default constructor.
- /// </summary>
- public LabelStyle()
- {
- _font = _fontCache.DefaultFont;
- }
- /// <summary>
- /// Public constructor.
- /// </summary>
- /// <param name="axis">Axis which owns the grid.</param>
- internal LabelStyle(Axis axis)
- : this()
- {
- _axis = axis;
- }
- #endregion
- #region Axis labels drawing methods
- /// <summary>
- /// Draws axis labels on the circular chart area.
- /// </summary>
- /// <param name="graph">Reference to the Chart Graphics object.</param>
- internal void PaintCircular( ChartGraphics graph )
- {
- // Label string drawing format
- using (StringFormat format = new StringFormat())
- {
- format.FormatFlags |= StringFormatFlags.LineLimit;
- format.Trimming = StringTrimming.EllipsisCharacter;
- // Labels are disabled for this axis
- if (!_axis.LabelStyle.Enabled)
- return;
- // Draw text with anti-aliasing
- /*
- if( (graph.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
- {
- graph.TextRenderingHint = TextRenderingHint.AntiAlias;
- }
- else
- {
- graph.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
- }
- */
- // Gets axis labels style
- CircularAxisLabelsStyle labelsStyle = this._axis.ChartArea.GetCircularAxisLabelsStyle();
- // Get list of circular axes with labels
- ArrayList circularAxes = this._axis.ChartArea.GetCircularAxisList();
- // Draw each axis label
- int index = 0;
- foreach (CircularChartAreaAxis circAxis in circularAxes)
- {
- if (circAxis.Title.Length > 0)
- {
- //******************************************************************
- //** Calculate label position corner position
- //******************************************************************
- PointF labelRelativePosition = new PointF(
- this._axis.ChartArea.circularCenter.X,
- this._axis.ChartArea.PlotAreaPosition.Y);
- // Adjust labels Y position
- labelRelativePosition.Y -= _axis.markSize + Axis.elementSpacing;
- // Convert to absolute
- PointF[] labelPosition = new PointF[] { graph.GetAbsolutePoint(labelRelativePosition) };
- // Get label rotation angle
- float labelAngle = circAxis.AxisPosition;
- ICircularChartType chartType = this._axis.ChartArea.GetCircularChartType();
- if (chartType != null && chartType.XAxisCrossingSupported())
- {
- if (!double.IsNaN(this._axis.ChartArea.AxisX.Crossing))
- {
- labelAngle += (float)this._axis.ChartArea.AxisX.Crossing;
- }
- }
- // Make sure angle is presented as a positive number
- while (labelAngle < 0)
- {
- labelAngle = 360f + labelAngle;
- }
- // Set graphics rotation matrix
- Matrix newMatrix = new Matrix();
- newMatrix.RotateAt(labelAngle, graph.GetAbsolutePoint(this._axis.ChartArea.circularCenter));
- newMatrix.TransformPoints(labelPosition);
- // Set text alignment
- format.LineAlignment = StringAlignment.Center;
- format.Alignment = StringAlignment.Near;
- if (labelsStyle != CircularAxisLabelsStyle.Radial)
- {
- if (labelAngle < 5f || labelAngle > 355f)
- {
- format.Alignment = StringAlignment.Center;
- format.LineAlignment = StringAlignment.Far;
- }
- if (labelAngle < 185f && labelAngle > 175f)
- {
- format.Alignment = StringAlignment.Center;
- format.LineAlignment = StringAlignment.Near;
- }
- if (labelAngle > 185f && labelAngle < 355f)
- {
- format.Alignment = StringAlignment.Far;
- }
- }
- else
- {
- if (labelAngle > 180f)
- {
- format.Alignment = StringAlignment.Far;
- }
- }
- // Set text rotation angle
- float textAngle = labelAngle;
- if (labelsStyle == CircularAxisLabelsStyle.Radial)
- {
- if (labelAngle > 180)
- {
- textAngle += 90f;
- }
- else
- {
- textAngle -= 90f;
- }
- }
- else if (labelsStyle == CircularAxisLabelsStyle.Circular)
- {
- format.Alignment = StringAlignment.Center;
- format.LineAlignment = StringAlignment.Far;
- }
- // Set text rotation matrix
- Matrix oldMatrix = graph.Transform;
- if (labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
- {
- Matrix textRotationMatrix = oldMatrix.Clone();
- textRotationMatrix.RotateAt(textAngle, labelPosition[0]);
- graph.Transform = textRotationMatrix;
- }
- // Get axis titl (label) color
- Color labelColor = _foreColor;
- if (!circAxis.TitleForeColor.IsEmpty)
- {
- labelColor = circAxis.TitleForeColor;
- }
- // Draw label
- using (Brush brush = new SolidBrush(labelColor))
- {
- graph.DrawString(
- circAxis.Title.Replace("\\n", "\n"),
- (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
- brush,
- labelPosition[0],
- format);
- }
- // Process selection region
- if (this._axis.Common.ProcessModeRegions)
- {
- SizeF size = graph.MeasureString(circAxis.Title.Replace("\\n", "\n"), (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont);
- RectangleF labelRect = GetLabelPosition(
- labelPosition[0],
- size,
- format);
- PointF[] points = new PointF[]
- {
- labelRect.Location,
- new PointF(labelRect.Right, labelRect.Y),
- new PointF(labelRect.Right, labelRect.Bottom),
- new PointF(labelRect.X, labelRect.Bottom)
- };
- using (GraphicsPath path = new GraphicsPath())
- {
- path.AddPolygon(points);
- path.CloseAllFigures();
- path.Transform(graph.Transform);
- this._axis.Common.HotRegionsList.AddHotRegion(
- path,
- false,
- ChartElementType.AxisLabels,
- circAxis.Title);
- }
- }
- // Restore graphics
- if(labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
- {
- graph.Transform = oldMatrix;
- }
- }
- ++index;
- }
- }
- }
- /// <summary>
- /// Gets rectangle position of the label.
- /// </summary>
- /// <param name="position">Original label position.</param>
- /// <param name="size">Label text size.</param>
- /// <param name="format">Label string format.</param>
- /// <returns>Label rectangle position.</returns>
- internal static RectangleF GetLabelPosition(
- PointF position,
- SizeF size,
- StringFormat format)
- {
- // Calculate label position rectangle
- RectangleF labelPosition = RectangleF.Empty;
- labelPosition.Width = size.Width;
- labelPosition.Height = size.Height;
- if(format.Alignment == StringAlignment.Far)
- {
- labelPosition.X = position.X - size.Width;
- }
- else if(format.Alignment == StringAlignment.Near)
- {
- labelPosition.X = position.X;
- }
- else if(format.Alignment == StringAlignment.Center)
- {
- labelPosition.X = position.X - size.Width/2F;
- }
- if(format.LineAlignment == StringAlignment.Far)
- {
- labelPosition.Y = position.Y - size.Height;
- }
- else if(format.LineAlignment == StringAlignment.Near)
- {
- labelPosition.Y = position.Y;
- }
- else if(format.LineAlignment == StringAlignment.Center)
- {
- labelPosition.Y = position.Y - size.Height/2F;
- }
- return labelPosition;
- }
- /// <summary>
- /// Draws axis labels.
- /// </summary>
- /// <param name="graph">Reference to the Chart Graphics object.</param>
- /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
- internal void Paint( ChartGraphics graph, bool backElements )
- {
- // Label string drawing format
- using (StringFormat format = new StringFormat())
- {
- format.FormatFlags |= StringFormatFlags.LineLimit;
- format.Trimming = StringTrimming.EllipsisCharacter;
- // Labels are disabled for this axis
- if (!_axis.LabelStyle.Enabled)
- return;
- // deliant fix-> VSTS #157848, #143286 - drawing custom label in empty axis
- if (Double.IsNaN(_axis.ViewMinimum) || Double.IsNaN(_axis.ViewMaximum))
- return;
- // Draw labels in 3D space
- if (this._axis.ChartArea.Area3DStyle.Enable3D && !this._axis.ChartArea.chartAreaIsCurcular)
- {
- this.Paint3D(graph, backElements);
- return;
- }
- // Initialize all labels position rectangle
- RectangleF rectLabels = _axis.ChartArea.Position.ToRectangleF();
- float labelSize = _axis.labelSize;
- if (_axis.AxisPosition == AxisPosition.Left)
- {
- rectLabels.Width = labelSize;
- if (_axis.GetIsMarksNextToAxis())
- rectLabels.X = (float)_axis.GetAxisPosition();
- else
- rectLabels.X = _axis.PlotAreaPosition.X;
- rectLabels.X -= labelSize + _axis.markSize;
- // Set label text alignment
- format.Alignment = StringAlignment.Far;
- format.LineAlignment = StringAlignment.Center;
- }
- else if (_axis.AxisPosition == AxisPosition.Right)
- {
- rectLabels.Width = labelSize;
- if (_axis.GetIsMarksNextToAxis())
- rectLabels.X = (float)_axis.GetAxisPosition();
- else
- rectLabels.X = _axis.PlotAreaPosition.Right;
- rectLabels.X += _axis.markSize;
- // Set label text alignment
- format.Alignment = StringAlignment.Near;
- format.LineAlignment = StringAlignment.Center;
- }
- else if (_axis.AxisPosition == AxisPosition.Top)
- {
- rectLabels.Height = labelSize;
- if (_axis.GetIsMarksNextToAxis())
- rectLabels.Y = (float)_axis.GetAxisPosition();
- else
- rectLabels.Y = _axis.PlotAreaPosition.Y;
- rectLabels.Y -= labelSize + _axis.markSize;
- // Set label text alignment
- format.Alignment = StringAlignment.Center;
- format.LineAlignment = StringAlignment.Far;
- }
- else if (_axis.AxisPosition == AxisPosition.Bottom)
- {
- rectLabels.Height = labelSize;
- if (_axis.GetIsMarksNextToAxis())
- rectLabels.Y = (float)_axis.GetAxisPosition();
- else
- rectLabels.Y = _axis.PlotAreaPosition.Bottom;
- rectLabels.Y += _axis.markSize;
- // Set label text alignment
- format.Alignment = StringAlignment.Center;
- format.LineAlignment = StringAlignment.Near;
- }
- // Calculate bounding rectangle
- RectangleF boundaryRect = rectLabels;
- if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
- {
- if (_axis.AxisPosition == AxisPosition.Left)
- {
- boundaryRect.X += _axis.totlaGroupingLabelsSize;
- boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
- }
- else if (_axis.AxisPosition == AxisPosition.Right)
- {
- boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
- }
- else if (_axis.AxisPosition == AxisPosition.Top)
- {
- boundaryRect.Y += _axis.totlaGroupingLabelsSize;
- boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
- }
- else if (_axis.AxisPosition == AxisPosition.Bottom)
- {
- boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
- }
- }
- // Check if the AJAX zooming and scrolling mode is enabled.
- // Labels are drawn slightly different in this case.
- bool ajaxScrollingEnabled = false;
- bool firstFrame = true;
- bool lastFrame = true;
- // Draw all labels from the collection
- int labelIndex = 0;
- foreach (CustomLabel label in this._axis.CustomLabels)
- {
- bool truncatedLeft = false;
- bool truncatedRight = false;
- double labelFrom = label.FromPosition;
- double labelTo = label.ToPosition;
- bool useRelativeCoordiantes = false;
- double labelFromRelative = double.NaN;
- double labelToRelative = double.NaN;
- // Skip if label middle point is outside current scaleView
- if (label.RowIndex == 0)
- {
- double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
- decimal viewMin = (decimal)_axis.ViewMinimum;
- decimal viewMax = (decimal)_axis.ViewMaximum;
- if (ajaxScrollingEnabled)
- {
- // Skip very first and last labels if they are partialy outside the scaleView
- if (firstFrame)
- {
- if ((decimal)label.FromPosition < (decimal)_axis.Minimum)
- {
- continue;
- }
- }
- if (lastFrame)
- {
- if ((decimal)label.ToPosition > (decimal)_axis.Maximum)
- {
- continue;
- }
- }
- // Skip label only if it is compleltly out of the scaleView
- if ((decimal)label.ToPosition < viewMin ||
- (decimal)label.FromPosition > viewMax)
- {
- continue;
- }
- // RecalculateAxesScale label index starting from the first frame.
- // Index is used to determine position of the offset labels
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- // Reset index
- labelIndex = 0;
- // Get first series attached to this axis
- Series axisSeries = null;
- if (_axis.axisType == AxisName.X || _axis.axisType == AxisName.X2)
- {
- List<string> seriesArray = _axis.ChartArea.GetXAxesSeries((_axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, _axis.SubAxisName);
- if (seriesArray.Count > 0)
- {
- axisSeries = _axis.Common.DataManager.Series[seriesArray[0]];
- if (axisSeries != null && !axisSeries.IsXValueIndexed)
- {
- axisSeries = null;
- }
- }
- }
- // Set start position and iterate through label positions
- // NOTE: Labels offset should not be taken in the account
- double currentPosition = _axis.Minimum;
- while (currentPosition < _axis.Maximum)
- {
- if (currentPosition >= middlePoint)
- {
- break;
- }
- currentPosition += ChartHelper.GetIntervalSize(currentPosition, _axis.LabelStyle.GetInterval(), _axis.LabelStyle.GetIntervalType(),
- axisSeries, 0.0, DateTimeIntervalType.Number, true);
- ++labelIndex;
- }
- }
- }
- else
- {
- // Skip label if label middle point is not in the scaleView
- if ((decimal)middlePoint < viewMin ||
- (decimal)middlePoint > viewMax)
- {
- continue;
- }
- }
- // Make sure label To and From coordinates are processed by one scale segment based
- // on the label middle point position.
- if (_axis.ScaleSegments.Count > 0)
- {
- AxisScaleSegment scaleSegment = _axis.ScaleSegments.FindScaleSegmentForAxisValue(middlePoint);
- _axis.ScaleSegments.AllowOutOfScaleValues = true;
- _axis.ScaleSegments.EnforceSegment(scaleSegment);
- }
- // Use center point instead of the To/From if label takes all scaleView
- // This is done to avoid issues with labels drawing with high
- // zooming levels.
- if ((decimal)label.FromPosition < viewMin &&
- (decimal)label.ToPosition > viewMax)
- {
- // Indicates that chart relative coordinates should be used instead of axis values
- useRelativeCoordiantes = true;
- // Calculate label From/To in relative coordinates using
- // label middle point and 100% width.
- labelFromRelative = _axis.GetLinearPosition(middlePoint) - 50.0;
- labelToRelative = labelFromRelative + 100.0;
- }
- }
- else
- {
- // Skip labels completly outside the scaleView
- if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
- {
- continue;
- }
- // Check if label is partially visible.
- if (!ajaxScrollingEnabled &&
- _axis.ScaleView.IsZoomed)
- {
- if (label.FromPosition < _axis.ViewMinimum)
- {
- truncatedLeft = true;
- labelFrom = _axis.ViewMinimum;
- }
- if (label.ToPosition > _axis.ViewMaximum)
- {
- truncatedRight = true;
- labelTo = _axis.ViewMaximum;
- }
- }
- }
- // Calculate single label position
- RectangleF rect = rectLabels;
- // Label is in the first row
- if (label.RowIndex == 0)
- {
- if (_axis.AxisPosition == AxisPosition.Left)
- {
- rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
- rect.Width = _axis.unRotatedLabelSize;
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Width /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.X += rect.Width;
- }
- }
- }
- else if (_axis.AxisPosition == AxisPosition.Right)
- {
- rect.Width = _axis.unRotatedLabelSize;
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Width /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.X += rect.Width;
- }
- }
- }
- else if (_axis.AxisPosition == AxisPosition.Top)
- {
- rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
- rect.Height = _axis.unRotatedLabelSize;
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Height /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.Y += rect.Height;
- }
- }
- }
- else if (_axis.AxisPosition == AxisPosition.Bottom)
- {
- rect.Height = _axis.unRotatedLabelSize;
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Height /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.Y += rect.Height;
- }
- }
- }
- // Increase label index
- ++labelIndex;
- }
- // Label is in the second row
- else if (label.RowIndex > 0)
- {
- if (_axis.AxisPosition == AxisPosition.Left)
- {
- rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
- for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
- {
- rect.X += _axis.groupingLabelSizes[index - 1];
- }
- rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- else if (_axis.AxisPosition == AxisPosition.Right)
- {
- rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
- for (int index = 1; index < label.RowIndex; index++)
- {
- rect.X += _axis.groupingLabelSizes[index - 1];
- }
- rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- else if (_axis.AxisPosition == AxisPosition.Top)
- {
- rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
- for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
- {
- rect.Y += _axis.groupingLabelSizes[index - 1];
- }
- rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- if (_axis.AxisPosition == AxisPosition.Bottom)
- {
- rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
- for (int index = 1; index < label.RowIndex; index++)
- {
- rect.Y += _axis.groupingLabelSizes[index - 1];
- }
- rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- }
- // Unknown label row value
- else
- {
- throw (new InvalidOperationException(SR.ExceptionAxisLabelIndexIsNegative));
- }
- // Set label From and To coordinates
- double fromPosition = _axis.GetLinearPosition(labelFrom);
- double toPosition = _axis.GetLinearPosition(labelTo);
- if (useRelativeCoordiantes)
- {
- useRelativeCoordiantes = false;
- fromPosition = labelFromRelative;
- toPosition = labelToRelative;
- }
- if (_axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom)
- {
- rect.X = (float)Math.Min(fromPosition, toPosition);
- rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
- // Adjust label To/From position if offset labels are used
- if (label.RowIndex == 0 &&
- ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
- {
- rect.X -= rect.Width / 2F;
- rect.Width *= 2F;
- }
- }
- else
- {
- rect.Y = (float)Math.Min(fromPosition, toPosition);
- rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
- // Adjust label To/From position if offset labels are used
- if (label.RowIndex == 0 &&
- ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
- {
- rect.Y -= rect.Height / 2F;
- rect.Height *= 2F;
- }
- }
- // Draw label
- using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
- {
- graph.DrawLabelStringRel(_axis,
- label.RowIndex,
- label.LabelMark,
- label.MarkColor,
- label.Text,
- label.Image,
- label.ImageTransparentColor,
- (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
- brush,
- rect,
- format,
- (_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle,
- (!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
- label,
- truncatedLeft,
- truncatedRight);
- }
- // Clear scale segment enforcement
- _axis.ScaleSegments.EnforceSegment(null);
- _axis.ScaleSegments.AllowOutOfScaleValues = false;
- }
- }
- }
- #endregion
- #region 3D Axis labels drawing methods
- /// <summary>
- /// Get a rectangle between chart area position and plotting area on specified side.
- /// Also sets axis labels string formatting for the specified labels position.
- /// </summary>
- /// <param name="area">Chart area object.</param>
- /// <param name="position">Position in chart area.</param>
- /// <param name="stringFormat">Axis labels string format.</param>
- /// <returns>Axis labels rectangle.</returns>
- private RectangleF GetAllLabelsRect(ChartArea area, AxisPosition position, StringFormat stringFormat)
- {
- // Find axis with same position
- Axis labelsAxis = null;
- foreach(Axis curAxis in area.Axes)
- {
- if(curAxis.AxisPosition == position)
- {
- labelsAxis = curAxis;
- break;
- }
- }
- if(labelsAxis == null)
- {
- return RectangleF.Empty;
- }
- // Calculate rect for different positions
- RectangleF rectLabels = area.Position.ToRectangleF();
- if( position == AxisPosition.Left )
- {
- rectLabels.Width = labelsAxis.labelSize;
- if( labelsAxis.GetIsMarksNextToAxis() )
- {
- rectLabels.X = (float)labelsAxis.GetAxisPosition();
- rectLabels.Width = (float)Math.Max(rectLabels.Width, rectLabels.X - labelsAxis.PlotAreaPosition.X);
- }
- else
- {
- rectLabels.X = labelsAxis.PlotAreaPosition.X;
- }
- rectLabels.X -= rectLabels.Width;
- if(area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
- {
- rectLabels.X -= labelsAxis.markSize;
- }
- // Set label text alignment
- stringFormat.Alignment = StringAlignment.Far;
- stringFormat.LineAlignment = StringAlignment.Center;
- }
- else if( position == AxisPosition.Right )
- {
- rectLabels.Width = labelsAxis.labelSize;
- if( labelsAxis.GetIsMarksNextToAxis() )
- {
- rectLabels.X = (float)labelsAxis.GetAxisPosition();
- rectLabels.Width = (float)Math.Max(rectLabels.Width, labelsAxis.PlotAreaPosition.Right - rectLabels.X);
- }
- else
- {
- rectLabels.X = labelsAxis.PlotAreaPosition.Right;
- }
-
- if(!area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
- {
- rectLabels.X += labelsAxis.markSize;
- }
- // Set label text alignment
- stringFormat.Alignment = StringAlignment.Near;
- stringFormat.LineAlignment = StringAlignment.Center;
- }
- else if( position == AxisPosition.Top )
- {
- rectLabels.Height = labelsAxis.labelSize;
- if( labelsAxis.GetIsMarksNextToAxis() )
- {
- rectLabels.Y = (float)labelsAxis.GetAxisPosition();
- rectLabels.Height = (float)Math.Max(rectLabels.Height, rectLabels.Y - labelsAxis.PlotAreaPosition.Y);
- }
- else
- {
- rectLabels.Y = labelsAxis.PlotAreaPosition.Y;
- }
- rectLabels.Y -= rectLabels.Height;
- if(area.Area3DStyle.WallWidth == 0)
- {
- rectLabels.Y -= labelsAxis.markSize;
- }
- // Set label text alignment
- stringFormat.Alignment = StringAlignment.Center;
- stringFormat.LineAlignment = StringAlignment.Far;
- }
- else if( position == AxisPosition.Bottom )
- {
- rectLabels.Height = labelsAxis.labelSize;
- if( labelsAxis.GetIsMarksNextToAxis() )
- {
- rectLabels.Y = (float)labelsAxis.GetAxisPosition();
- rectLabels.Height = (float)Math.Max(rectLabels.Height, labelsAxis.PlotAreaPosition.Bottom - rectLabels.Y);
- }
- else
- {
- rectLabels.Y = labelsAxis.PlotAreaPosition.Bottom;
- }
- rectLabels.Y += labelsAxis.markSize;
- // Set label text alignment
- stringFormat.Alignment = StringAlignment.Center;
- stringFormat.LineAlignment = StringAlignment.Near;
- }
- return rectLabels;
- }
- /// <summary>
- /// Gets position of axis labels.
- /// Top and Bottom axis labels can be drawn on the sides (left or right)
- /// of the plotting area. If angle between axis and it's projection is
- /// between -25 and 25 degrees the axis are drawn at the bottom/top,
- /// otherwise labels are moved on the left or right side.
- /// </summary>
- /// <param name="axis">Axis object.</param>
- /// <returns>Position where axis labels should be drawn.</returns>
- private AxisPosition GetLabelsPosition(Axis axis)
- {
- // Get angle between 2D axis and it's 3D projection.
- double axisAngle = axis.GetAxisProjectionAngle();
- // Pick the side to draw the labels on
- if(axis.AxisPosition == AxisPosition.Bottom)
- {
- if(axisAngle <= -25 )
- return AxisPosition.Right;
- else if(axisAngle >= 25 )
- return AxisPosition.Left;
- }
- else if(axis.AxisPosition == AxisPosition.Top)
- {
- if(axisAngle <= -25 )
- return AxisPosition.Left;
- else if(axisAngle >= 25 )
- return AxisPosition.Right;
- }
- // Labels are on the same side as the axis
- return axis.AxisPosition;
- }
- /// <summary>
- /// Draws axis labels in 3D space.
- /// </summary>
- /// <param name="graph">Reference to the Chart Graphics object.</param>
- /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
- internal void Paint3D( ChartGraphics graph, bool backElements )
- {
- // Label string drawing format
- using (StringFormat format = new StringFormat())
- {
- format.Trimming = StringTrimming.EllipsisCharacter;
- // Calculate single pixel size in relative coordinates
- SizeF pixelSize = graph.GetRelativeSize(new SizeF(1f, 1f));
- //********************************************************************
- //** Determine the side of the plotting area to draw the labels on.
- //********************************************************************
- AxisPosition labelsPosition = GetLabelsPosition(_axis);
- //*****************************************************************
- //** Set the labels Z position
- //*****************************************************************
- bool axisOnEdge;
- float labelsZPosition = _axis.GetMarksZPosition(out axisOnEdge);
- // Adjust Z position for the "bent" tick marks
- bool adjustForWallWidth = false;
- if (this._axis.AxisPosition == AxisPosition.Top &&
- !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Top, backElements, false))
- {
- adjustForWallWidth = true;
- }
- if (this._axis.AxisPosition == AxisPosition.Left &&
- !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Left, backElements, false))
- {
- adjustForWallWidth = true;
- }
- if (this._axis.AxisPosition == AxisPosition.Right &&
- !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Right, backElements, false))
- {
- adjustForWallWidth = true;
- }
- if (adjustForWallWidth && this._axis.ChartArea.Area3DStyle.WallWidth > 0)
- {
- if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
- {
- labelsZPosition -= this._axis.ChartArea.areaSceneWallWidth.Width;
- }
- else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
- {
- labelsZPosition -= this._axis.MajorTickMark.Size + this._axis.ChartArea.areaSceneWallWidth.Width;
- }
- else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
- {
- labelsZPosition -= this._axis.MajorTickMark.Size / 2f + this._axis.ChartArea.areaSceneWallWidth.Width;
- }
- }
- //*****************************************************************
- //** Check if labels should be drawn as back or front element.
- //*****************************************************************
- bool labelsInsidePlotArea = (this._axis.GetIsMarksNextToAxis() && !axisOnEdge);
- if (backElements == labelsInsidePlotArea)
- {
- // Skip drawing
- return;
- }
- //********************************************************************
- //** Initialize all labels position rectangle
- //********************************************************************
- RectangleF rectLabels = this.GetAllLabelsRect(this._axis.ChartArea, this._axis.AxisPosition, format);
- //********************************************************************
- //** Calculate bounding rectangle used to truncate labels on the
- //** chart area boundary if TruncatedLabels property is set to true.
- //********************************************************************
- RectangleF boundaryRect = rectLabels;
- if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
- {
- if (this._axis.AxisPosition == AxisPosition.Left)
- {
- boundaryRect.X += _axis.totlaGroupingLabelsSize;
- boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
- }
- else if (this._axis.AxisPosition == AxisPosition.Right)
- {
- boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
- }
- else if (this._axis.AxisPosition == AxisPosition.Top)
- {
- boundaryRect.Y += _axis.totlaGroupingLabelsSize;
- boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
- }
- else if (this._axis.AxisPosition == AxisPosition.Bottom)
- {
- boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
- }
- }
- // Pre-calculated height of the first labels row
- float firstLabelsRowHeight = -1f;
- // For 3D axis labels the first row of labels
- // has to be drawn after all other rows because
- // of hot regions.
- for (int selectionRow = 0; selectionRow <= this._axis.GetGroupLabelLevelCount(); selectionRow++)
- {
- //********************************************************************
- //** Draw all labels from the collection
- //********************************************************************
- int labelIndex = 0;
- foreach (CustomLabel label in this._axis.CustomLabels)
- {
- bool truncatedLeft = false;
- bool truncatedRight = false;
- double labelFrom = label.FromPosition;
- double labelTo = label.ToPosition;
- if (label.RowIndex != selectionRow)
- {
- continue;
- }
- // Skip if label middle point is outside current scaleView
- if (label.RowIndex == 0)
- {
- double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
- if ((decimal)middlePoint < (decimal)_axis.ViewMinimum ||
- (decimal)middlePoint > (decimal)_axis.ViewMaximum)
- {
- continue;
- }
- }
- else
- {
- // Skip labels completly outside the scaleView
- if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
- {
- continue;
- }
- // Check if label is partially visible
- if (_axis.ScaleView.IsZoomed)
- {
- if (label.FromPosition < _axis.ViewMinimum)
- {
- truncatedLeft = true;
- labelFrom = _axis.ViewMinimum;
- }
- if (label.ToPosition > _axis.ViewMaximum)
- {
- truncatedRight = true;
- labelTo = _axis.ViewMaximum;
- }
- }
- }
- // Calculate single label position
- RectangleF rect = rectLabels;
- // Label is in the first row
- if (label.RowIndex == 0)
- {
- if (this._axis.AxisPosition == AxisPosition.Left)
- {
- if (!this._axis.GetIsMarksNextToAxis())
- {
- rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
- rect.Width = _axis.unRotatedLabelSize;
- }
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Width /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.X += rect.Width;
- }
- }
- }
- else if (this._axis.AxisPosition == AxisPosition.Right)
- {
- if (!this._axis.GetIsMarksNextToAxis())
- {
- rect.Width = _axis.unRotatedLabelSize;
- }
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Width /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.X += rect.Width;
- }
- }
- }
- else if (this._axis.AxisPosition == AxisPosition.Top)
- {
- if (!this._axis.GetIsMarksNextToAxis())
- {
- rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
- rect.Height = _axis.unRotatedLabelSize;
- }
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Height /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.Y += rect.Height;
- }
- }
- }
- else if (this._axis.AxisPosition == AxisPosition.Bottom)
- {
- if (!this._axis.GetIsMarksNextToAxis())
- {
- rect.Height = _axis.unRotatedLabelSize;
- }
- // Adjust label rectangle if offset labels are used
- if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
- {
- rect.Height /= 2F;
- if (labelIndex % 2 != 0F)
- {
- rect.Y += rect.Height;
- }
- }
- }
- // Increase label index
- ++labelIndex;
- }
- // Label is in the second row
- else if (label.RowIndex > 0)
- {
- // Hide grouping labels (where index of row > 0) when they are displayed
- // not on the same side as their axis. Fixes MS issue #64.
- if (labelsPosition != this._axis.AxisPosition)
- {
- continue;
- }
- if (_axis.AxisPosition == AxisPosition.Left)
- {
- rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
- for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
- {
- rect.X += _axis.groupingLabelSizes[index - 1];
- }
- rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- else if (_axis.AxisPosition == AxisPosition.Right)
- {
- rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
- for (int index = 1; index < label.RowIndex; index++)
- {
- rect.X += _axis.groupingLabelSizes[index - 1];
- }
- rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- else if (_axis.AxisPosition == AxisPosition.Top)
- {
- rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
- for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
- {
- rect.Y += _axis.groupingLabelSizes[index - 1];
- }
- rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- if (_axis.AxisPosition == AxisPosition.Bottom)
- {
- rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
- for (int index = 1; index < label.RowIndex; index++)
- {
- rect.Y += _axis.groupingLabelSizes[index - 1];
- }
- rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
- }
- }
- // Unknown label row value
- else
- {
- throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexMustBe1Or2));
- }
- //********************************************************************
- //** Set label From and To coordinates.
- //********************************************************************
- double fromPosition = _axis.GetLinearPosition(labelFrom);
- double toPosition = _axis.GetLinearPosition(labelTo);
- if (this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom)
- {
- rect.X = (float)Math.Min(fromPosition, toPosition);
- rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
- if (rect.Width < pixelSize.Width)
- {
- rect.Width = pixelSize.Width;
- }
- // Adjust label To/From position if offset labels are used
- if (label.RowIndex == 0 &&
- ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
- {
- rect.X -= rect.Width / 2F;
- rect.Width *= 2F;
- }
- }
- else
- {
- rect.Y = (float)Math.Min(fromPosition, toPosition);
- rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
- if (rect.Height < pixelSize.Height)
- {
- rect.Height = pixelSize.Height;
- }
- // Adjust label To/From position if offset labels are used
- if (label.RowIndex == 0 &&
- ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
- {
- rect.Y -= rect.Height / 2F;
- rect.Height *= 2F;
- }
- }
- // Save original rect
- RectangleF initialRect = new RectangleF(rect.Location, rect.Size);
- //********************************************************************
- //** Transform and adjust label rectangle coordinates in 3D space.
- //********************************************************************
- Point3D[] rectPoints = new Point3D[3];
- if (this._axis.AxisPosition == AxisPosition.Left)
- {
- rectPoints[0] = new Point3D(rect.Right, rect.Y, labelsZPosition);
- rectPoints[1] = new Point3D(rect.Right, rect.Y + rect.Height / 2f, labelsZPosition);
- rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
- this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
- rect.Y = rectPoints[0].Y;
- rect.Height = rectPoints[2].Y - rect.Y;
- rect.Width = rectPoints[1].X - rect.X;
- }
- else if (this._axis.AxisPosition == AxisPosition.Right)
- {
- rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
- rectPoints[1] = new Point3D(rect.X, rect.Y + rect.Height / 2f, labelsZPosition);
- rectPoints[2] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
- this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
- rect.Y = rectPoints[0].Y;
- rect.Height = rectPoints[2].Y - rect.Y;
- rect.Width = rect.Right - rectPoints[1].X;
- rect.X = rectPoints[1].X;
- }
- else if (this._axis.AxisPosition == AxisPosition.Top)
- {
- // Transform 3 points of the rectangle
- rectPoints[0] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
- rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Bottom, labelsZPosition);
- rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
- this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
- if (labelsPosition == AxisPosition.Top)
- {
- rect.X = rectPoints[0].X;
- rect.Width = rectPoints[2].X - rect.X;
- rect.Height = rectPoints[1].Y - rect.Y;
- }
- else if (labelsPosition == AxisPosition.Right)
- {
- RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
- rect.Y = rectPoints[0].Y;
- rect.Height = rectPoints[2].Y - rect.Y;
- rect.X = rectPoints[1].X;
- rect.Width = rightLabelsRect.Right - rect.X;
- }
- else if (labelsPosition == AxisPosition.Left)
- {
- RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
- rect.Y = rectPoints[2].Y;
- rect.Height = rectPoints[0].Y - rect.Y;
- rect.X = rightLabelsRect.X;
- rect.Width = rectPoints[1].X - rightLabelsRect.X;
- }
- }
- else if (this._axis.AxisPosition == AxisPosition.Bottom)
- {
- // Transform 3 points of the rectangle
- rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
- rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Y, labelsZPosition);
- rectPoints[2] = new Point3D(rect.Right, rect.Y, labelsZPosition);
- this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
- if (labelsPosition == AxisPosition.Bottom)
- {
- rect.X = rectPoints[0].X;
- rect.Width = rectPoints[2].X - rect.X;
- rect.Height = rect.Bottom - rectPoints[1].Y;
- rect.Y = rectPoints[1].Y;
- }
- else if (labelsPosition == AxisPosition.Right)
- {
- RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
- rect.Y = rectPoints[2].Y;
- rect.Height = rectPoints[0].Y - rect.Y;
- rect.X = rectPoints[1].X;
- rect.Width = rightLabelsRect.Right - rect.X;
- // Adjust label rect by shifting it down by quarter of the tick size
- if (this._axis.autoLabelAngle == 0)
- {
- rect.Y += this._axis.markSize / 4f;
- }
- }
- else if (labelsPosition == AxisPosition.Left)
- {
- RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
- rect.Y = rectPoints[0].Y;
- rect.Height = rectPoints[2].Y - rect.Y;
- rect.X = rightLabelsRect.X;
- rect.Width = rectPoints[1].X - rightLabelsRect.X;
- // Adjust label rect by shifting it down by quarter of the tick size
- if (this._axis.autoLabelAngle == 0)
- {
- rect.Y += this._axis.markSize / 4f;
- }
- }
- }
- // Find axis with same position
- Axis labelsAxis = null;
- foreach (Axis curAxis in this._axis.ChartArea.Axes)
- {
- if (curAxis.AxisPosition == labelsPosition)
- {
- labelsAxis = curAxis;
- break;
- }
- }
- //********************************************************************
- //** Adjust font angles for Top and Bottom axis
- //********************************************************************
- int labelsFontAngle = (_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle;
- if (labelsPosition != this._axis.AxisPosition)
- {
- if ((this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom) &&
- (labelsFontAngle == 90 || labelsFontAngle == -90))
- {
- labelsFontAngle = 0;
- }
- else if (this._axis.AxisPosition == AxisPosition.Bottom)
- {
- if (labelsPosition == AxisPosition.Left && labelsFontAngle > 0)
- {
- labelsFontAngle = -labelsFontAngle;
- }
- else if (labelsPosition == AxisPosition.Right && labelsFontAngle < 0)
- {
- labelsFontAngle = -labelsFontAngle;
- }
- }
- else if (this._axis.AxisPosition == AxisPosition.Top)
- {
- if (labelsPosition == AxisPosition.Left && labelsFontAngle < 0)
- {
- labelsFontAngle = -labelsFontAngle;
- }
- else if (labelsPosition == AxisPosition.Right && labelsFontAngle > 0)
- {
- labelsFontAngle = -labelsFontAngle;
- }
- }
- }
- //********************************************************************
- //** NOTE: Code below improves chart labels readability in scenarios
- //** described in MS issue #65.
- //**
- //** Prevent labels in the first row from overlapping the grouping
- //** labels in the rows below. The solution only apply to the limited
- //** use cases defined by the condition below.
- //********************************************************************
- StringFormatFlags oldFormatFlags = format.FormatFlags;
- if (label.RowIndex == 0 &&
- labelsFontAngle == 0 &&
- _axis.groupingLabelSizes != null &&
- _axis.groupingLabelSizes.Length > 0 &&
- this._axis.AxisPosition == AxisPosition.Bottom &&
- labelsPosition == AxisPosition.Bottom &&
- !((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
- {
- if (firstLabelsRowHeight == -1f)
- {
- // Calculate first labels row max height
- Point3D[] labelPositionPoints = new Point3D[1];
- labelPositionPoints[0] = new Point3D(initialRect.X, initialRect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment, labelsZPosition);
- this._axis.ChartArea.matrix3D.TransformPoints(labelPositionPoints);
- float height = labelPositionPoints[0].Y - rect.Y;
- firstLabelsRowHeight = (height > 0f) ? height : rect.Height;
- }
- // Resuse pre-calculated first labels row height
- rect.Height = firstLabelsRowHeight;
- // Change current string format to prevent strings to go out of the
- // specified bounding rectangle
- if ((format.FormatFlags & StringFormatFlags.LineLimit) == 0)
- {
- format.FormatFlags |= StringFormatFlags.LineLimit;
- }
- }
- //********************************************************************
- //** Draw label text.
- //********************************************************************
- using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
- {
- graph.DrawLabelStringRel(
- labelsAxis,
- label.RowIndex,
- label.LabelMark,
- label.MarkColor,
- label.Text,
- label.Image,
- label.ImageTransparentColor,
- (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
- brush,
- rect,
- format,
- labelsFontAngle,
- (!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
- label,
- truncatedLeft,
- truncatedRight);
- }
- // Restore old string format that was temporary modified
- if (format.FormatFlags != oldFormatFlags)
- {
- format.FormatFlags = oldFormatFlags;
- }
- }
- }
- }
- }
- #endregion
- #region Helper methods
- /// <summary>
- /// Sets the axis to which this object attached to.
- /// </summary>
- /// <returns>Axis object.</returns>
- internal Axis Axis
- {
- set { _axis = value; }
- }
- /// <summary>
- /// Invalidate chart picture
- /// </summary>
- internal override void Invalidate()
- {
- if(this._axis != null)
- {
- this._axis.Invalidate();
- }
- base.Invalidate();
- }
- #endregion
- #region Label properties
- /// <summary>
- /// Gets or sets the interval offset of the label.
- /// </summary>
- [
- SRCategory("CategoryAttributeData"),
- Bindable(true),
- SRDescription("DescriptionAttributeLabel_IntervalOffset"),
- DefaultValue(Double.NaN),
- RefreshPropertiesAttribute(RefreshProperties.All),
- TypeConverter(typeof(AxisElementIntervalValueConverter))
- ]
- public double IntervalOffset
- {
- get
- {
- return intervalOffset;
- }
- set
- {
- intervalOffset = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets the interval offset.
- /// </summary>
- /// <returns></returns>
- internal double GetIntervalOffset()
- {
- if(double.IsNaN(intervalOffset) && this._axis != null)
- {
- return this._axis.IntervalOffset;
- }
- return intervalOffset;
- }
- /// <summary>
- /// Gets or sets the unit of measurement of the label offset.
- /// </summary>
- [
- SRCategory("CategoryAttributeData"),
- Bindable(true),
- DefaultValue(DateTimeIntervalType.NotSet),
- SRDescription("DescriptionAttributeLabel_IntervalOffsetType"),
- RefreshPropertiesAttribute(RefreshProperties.All),
- ]
- public DateTimeIntervalType IntervalOffsetType
- {
- get
- {
- return intervalOffsetType;
- }
- set
- {
- intervalOffsetType = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets the type of the interval offset.
- /// </summary>
- /// <returns></returns>
- internal DateTimeIntervalType GetIntervalOffsetType()
- {
- if(intervalOffsetType == DateTimeIntervalType.NotSet && this._axis != null)
- {
- return this._axis.IntervalOffsetType;
- }
- return intervalOffsetType;
- }
- /// <summary>
- /// Gets or sets the interval size of the label.
- /// </summary>
- [
- SRCategory("CategoryAttributeData"),
- Bindable(true),
- DefaultValue(Double.NaN),
- SRDescription("DescriptionAttributeLabel_Interval"),
- TypeConverter(typeof(AxisElementIntervalValueConverter)),
- ]
- public double Interval
- {
- get
- {
- return interval;
- }
- set
- {
- interval = value;
- // Reset original property value fields
- if (this._axis != null)
- {
- this._axis.tempLabelInterval = interval;
- }
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets the interval.
- /// </summary>
- /// <returns></returns>
- internal double GetInterval()
- {
- if(double.IsNaN(interval) && this._axis != null)
- {
- return this._axis.Interval;
- }
- return interval;
- }
- /// <summary>
- /// Gets or sets the unit of measurement of the interval size of the label.
- /// </summary>
- [
- SRCategory("CategoryAttributeData"),
- Bindable(true),
- DefaultValue(DateTimeIntervalType.NotSet),
- SRDescription("DescriptionAttributeLabel_IntervalType"),
- RefreshPropertiesAttribute(RefreshProperties.All)
- ]
- public DateTimeIntervalType IntervalType
- {
- get
- {
- return intervalType;
- }
- set
- {
- intervalType = value;
- // Reset original property value fields
- if (this._axis != null)
- {
- this._axis.tempLabelIntervalType = intervalType;
- }
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets the type of the interval.
- /// </summary>
- /// <returns></returns>
- internal DateTimeIntervalType GetIntervalType()
- {
- if(intervalType == DateTimeIntervalType.NotSet && this._axis != null)
- {
- return this._axis.IntervalType;
- }
- return intervalType;
- }
- /// <summary>
- /// Gets or sets the font of the label.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
- SRDescription("DescriptionAttributeLabel_Font")
- ]
- public Font Font
- {
- get
- {
- return _font;
- }
- set
- {
- // Turn off labels autofitting
- if (this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
- {
- if(!this._axis.Common.Chart.serializing)
- {
- this._axis.IsLabelAutoFit = false;
- }
- }
- _font = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the fore color of the label.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(typeof(Color), "Black"),
- SRDescription("DescriptionAttributeFontColor"),
- NotifyParentPropertyAttribute(true),
- TypeConverter(typeof(ColorConverter)),
- #if DESIGNER
- Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
- #endif
- ]
- public Color ForeColor
- {
- get
- {
- return _foreColor;
- }
- set
- {
- _foreColor = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a value that represents the angle at which font is drawn.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(0),
- SRDescription("DescriptionAttributeLabel_FontAngle"),
- RefreshPropertiesAttribute(RefreshProperties.All)
- ]
- public int Angle
- {
- get
- {
- return angle;
- }
- set
- {
- if(value < -90 || value > 90)
- {
- throw (new ArgumentOutOfRangeException("value", SR.ExceptionAxisLabelFontAngleInvalid));
- }
-
- // Turn of label offset if angle is not 0, 90 or -90
- if(IsStaggered && value != 0 && value != -90 && value != 90)
- {
- IsStaggered = false;
- }
- // Turn off labels autofitting
- if(this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
- {
- if (!this._axis.Common.Chart.serializing)
- {
- this._axis.IsLabelAutoFit = false;
- }
- }
- angle = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a property which specifies whether the labels are shown with offset.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(false),
- SRDescription("DescriptionAttributeLabel_OffsetLabels"),
- RefreshPropertiesAttribute(RefreshProperties.All)
- ]
- public bool IsStaggered
- {
- get
- {
- return isStaggered;
- }
- set
- {
- // Make sure that angle is 0, 90 or -90
- if(value && (this.Angle != 0 || this.Angle != -90 || this.Angle != 90))
- {
- this.Angle = 0;
- }
- // Turn off labels autofitting
- if (this._axis != null && this._axis.Common != null && this._axis.Common.Chart != null)
- {
- if (!this._axis.Common.Chart.serializing)
- {
- this._axis.IsLabelAutoFit = false;
- }
- }
- isStaggered = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a property which specifies whether the labels are shown at axis ends.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(true),
- SRDescription("DescriptionAttributeLabel_ShowEndLabels"),
- ]
- public bool IsEndLabelVisible
- {
- get
- {
- return _isEndLabelVisible;
- }
- set
- {
- _isEndLabelVisible = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a property which specifies whether the label can be truncated.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(false),
- SRDescription("DescriptionAttributeLabel_TruncatedLabels"),
- ]
- public bool TruncatedLabels
- {
- get
- {
- return _truncatedLabels;
- }
- set
- {
- _truncatedLabels = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets the formatting string for the label text.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(""),
- SRDescription("DescriptionAttributeLabel_Format"),
- ]
- public string Format
- {
- get
- {
- return _format;
- }
- set
- {
- _format = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- /// <summary>
- /// Gets or sets a property which indicates whether the label is enabled.
- /// </summary>
- [
- SRCategory("CategoryAttributeAppearance"),
- Bindable(true),
- DefaultValue(true),
- SRDescription("DescriptionAttributeLabel_Enabled"),
- ]
- public bool Enabled
- {
- get
- {
- return _enabled;
- }
- set
- {
- _enabled = value;
- this.Invalidate();
- CallOnModifing();
- }
- }
- #endregion
- #region IDisposable Members
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- //Free managed resources
- if (_fontCache!=null)
- {
- _fontCache.Dispose();
- _fontCache = null;
- }
- }
- }
- #endregion
- }
- }
|