Label.cs 101 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. //
  5. // Purpose: LabelStyle and CustomLabel classes are used to determine
  6. // chart axis labels. Labels can be automatically
  7. // generated based on the series data or be “manually”
  8. // set by the user.
  9. //
  10. using System;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using System.ComponentModel;
  14. using System.Drawing;
  15. using System.Drawing.Design;
  16. using System.Drawing.Drawing2D;
  17. using FastReport.DataVisualization.Charting.ChartTypes;
  18. using FastReport.DataVisualization.Charting.Utilities;
  19. namespace FastReport.DataVisualization.Charting
  20. {
  21. #region Labels enumerations
  22. /// <summary>
  23. /// An enumeration that specifies a mark for custom labels.
  24. /// </summary>
  25. public enum LabelMarkStyle
  26. {
  27. /// <summary>
  28. /// No label marks are used.
  29. /// </summary>
  30. None,
  31. /// <summary>
  32. /// Labels use side marks.
  33. /// </summary>
  34. SideMark,
  35. /// <summary>
  36. /// Labels use line and side marks.
  37. /// </summary>
  38. LineSideMark,
  39. /// <summary>
  40. /// Draws a box around the label. The box always starts at the axis position.
  41. /// </summary>
  42. Box
  43. };
  44. /// <summary>
  45. /// An enumeration of custom grid lines and tick marks flags used in the custom labels.
  46. /// </summary>
  47. [Flags]
  48. public enum GridTickTypes
  49. {
  50. /// <summary>
  51. /// No tick mark or grid line are shown.
  52. /// </summary>
  53. None = 0,
  54. /// <summary>
  55. /// Tick mark is shown.
  56. /// </summary>
  57. TickMark = 1,
  58. /// <summary>
  59. /// Grid line is shown.
  60. /// </summary>
  61. Gridline = 2,
  62. /// <summary>
  63. /// Tick mark and grid line are shown.
  64. /// </summary>
  65. All = TickMark | Gridline
  66. }
  67. /// <summary>
  68. /// An enumeration of label styles for circular chart area axis.
  69. /// </summary>
  70. internal enum CircularAxisLabelsStyle
  71. {
  72. /// <summary>
  73. /// Style depends on number of labels.
  74. /// </summary>
  75. Auto,
  76. /// <summary>
  77. /// Label text positions around the circular area.
  78. /// </summary>
  79. Circular,
  80. /// <summary>
  81. /// Label text is always horizontal.
  82. /// </summary>
  83. Horizontal,
  84. /// <summary>
  85. /// Label text has the same angle as circular axis.
  86. /// </summary>
  87. Radial
  88. }
  89. #endregion
  90. /// <summary>
  91. /// The CustomLabelsCollection class is a strongly typed collection of
  92. /// custom axis labels.
  93. /// </summary>
  94. [
  95. SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
  96. ]
  97. public class CustomLabelsCollection : ChartElementCollection<CustomLabel>
  98. {
  99. #region Constructors
  100. /// <summary>
  101. /// Custom labels collection object constructor
  102. /// </summary>
  103. /// <param name="axis">Reference to the axis object.</param>
  104. internal CustomLabelsCollection(Axis axis) : base(axis)
  105. {
  106. }
  107. #endregion
  108. #region Properties
  109. internal Axis Axis
  110. {
  111. get { return Parent as Axis; }
  112. }
  113. #endregion
  114. #region Labels adding methods
  115. /// <summary>
  116. /// Adds a custom label into the collection.
  117. /// </summary>
  118. /// <param name="fromPosition">Label left position.</param>
  119. /// <param name="toPosition">Label right position.</param>
  120. /// <param name="text">Label text.</param>
  121. /// <returns>Newly added item.</returns>
  122. public CustomLabel Add(double fromPosition, double toPosition, string text)
  123. {
  124. CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
  125. Add(label);
  126. return label;
  127. }
  128. /// <summary>
  129. /// Adds one custom label into the collection. Custom label flag may be specified.
  130. /// </summary>
  131. /// <param name="fromPosition">Label left position.</param>
  132. /// <param name="toPosition">Label right position.</param>
  133. /// <param name="text">Label text.</param>
  134. /// <param name="customLabel">Indicates if label is custom (created by user).</param>
  135. /// <returns>Newly added item.</returns>
  136. internal CustomLabel Add(double fromPosition, double toPosition, string text, bool customLabel)
  137. {
  138. CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
  139. label.customLabel = customLabel;
  140. Add(label);
  141. return label;
  142. }
  143. /// <summary>
  144. /// Adds a custom label into the collection.
  145. /// </summary>
  146. /// <param name="fromPosition">Label left position.</param>
  147. /// <param name="toPosition">Label right position.</param>
  148. /// <param name="text">Label text.</param>
  149. /// <param name="rowIndex">Label row index.</param>
  150. /// <param name="markStyle">Label marking style.</param>
  151. /// <returns>Newly added item.</returns>
  152. public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle)
  153. {
  154. CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle);
  155. Add(label);
  156. return label;
  157. }
  158. /// <summary>
  159. /// Adds a custom label into the collection.
  160. /// </summary>
  161. /// <param name="fromPosition">Label left position.</param>
  162. /// <param name="toPosition">Label right position.</param>
  163. /// <param name="text">Label text.</param>
  164. /// <param name="rowIndex">Label row index.</param>
  165. /// <param name="markStyle">Label marking style.</param>
  166. /// <returns>Index of newly added item.</returns>
  167. /// <param name="gridTick">Custom grid line and tick mark flag.</param>
  168. public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle, GridTickTypes gridTick)
  169. {
  170. CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle, gridTick);
  171. Add(label);
  172. return label;
  173. }
  174. /// <summary>
  175. /// Adds multiple custom labels to the collection.
  176. /// The labels will be DateTime labels with the specified interval type,
  177. /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
  178. /// </summary>
  179. /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
  180. /// <param name="intervalType">Unit of measurement of the label step.</param>
  181. /// <param name="min">Minimum value..</param>
  182. /// <param name="max">Maximum value..</param>
  183. /// <param name="format">Label text format.</param>
  184. /// <param name="rowIndex">Label row index.</param>
  185. /// <param name="markStyle">Label marking style.</param>
  186. public void Add(double labelsStep, DateTimeIntervalType intervalType, double min, double max, string format, int rowIndex, LabelMarkStyle markStyle)
  187. {
  188. // Find labels range min/max values
  189. if(min == 0.0 &&
  190. max == 0.0 &&
  191. this.Axis != null &&
  192. !double.IsNaN(this.Axis.Minimum) &&
  193. !double.IsNaN(this.Axis.Maximum))
  194. {
  195. min = this.Axis.Minimum;
  196. max = this.Axis.Maximum;
  197. }
  198. double fromX = Math.Min(min, max);
  199. double toX = Math.Max(min, max);
  200. this.SuspendUpdates();
  201. try
  202. {
  203. // Loop through all label points
  204. double labelStart = fromX;
  205. double labelEnd = 0;
  206. while (labelStart < toX)
  207. {
  208. // Determine label end location
  209. if (intervalType == DateTimeIntervalType.Number)
  210. {
  211. labelEnd = labelStart + labelsStep;
  212. }
  213. else if (intervalType == DateTimeIntervalType.Milliseconds)
  214. {
  215. labelEnd = DateTime.FromOADate(labelStart).AddMilliseconds(labelsStep).ToOADate();
  216. }
  217. else if (intervalType == DateTimeIntervalType.Seconds)
  218. {
  219. labelEnd = DateTime.FromOADate(labelStart).AddSeconds(labelsStep).ToOADate();
  220. }
  221. else if (intervalType == DateTimeIntervalType.Minutes)
  222. {
  223. labelEnd = DateTime.FromOADate(labelStart).AddMinutes(labelsStep).ToOADate();
  224. }
  225. else if (intervalType == DateTimeIntervalType.Hours)
  226. {
  227. labelEnd = DateTime.FromOADate(labelStart).AddHours(labelsStep).ToOADate();
  228. }
  229. else if (intervalType == DateTimeIntervalType.Days)
  230. {
  231. labelEnd = DateTime.FromOADate(labelStart).AddDays(labelsStep).ToOADate();
  232. }
  233. else if (intervalType == DateTimeIntervalType.Weeks)
  234. {
  235. labelEnd = DateTime.FromOADate(labelStart).AddDays(7 * labelsStep).ToOADate();
  236. }
  237. else if (intervalType == DateTimeIntervalType.Months)
  238. {
  239. labelEnd = DateTime.FromOADate(labelStart).AddMonths((int)labelsStep).ToOADate();
  240. }
  241. else if (intervalType == DateTimeIntervalType.Years)
  242. {
  243. labelEnd = DateTime.FromOADate(labelStart).AddYears((int)labelsStep).ToOADate();
  244. }
  245. else
  246. {
  247. // Unsupported step type
  248. throw (new ArgumentException(SR.ExceptionAxisLabelsIntervalTypeUnsupported(intervalType.ToString())));
  249. }
  250. if (labelEnd > toX)
  251. {
  252. labelEnd = toX;
  253. }
  254. // Generate label text
  255. ChartValueType valueType = ChartValueType.Double;
  256. if (intervalType != DateTimeIntervalType.Number)
  257. {
  258. if (this.Axis.GetAxisValuesType() == ChartValueType.DateTimeOffset)
  259. valueType = ChartValueType.DateTimeOffset;
  260. else
  261. valueType = ChartValueType.DateTime;
  262. }
  263. string text = ValueConverter.FormatValue(
  264. this.Common.Chart,
  265. this.Axis,
  266. null,
  267. labelStart + (labelEnd - labelStart) / 2,
  268. format,
  269. valueType,
  270. ChartElementType.AxisLabels);
  271. // Add label
  272. CustomLabel label = new CustomLabel(labelStart, labelEnd, text, rowIndex, markStyle);
  273. this.Add(label);
  274. labelStart = labelEnd;
  275. }
  276. }
  277. finally
  278. {
  279. this.ResumeUpdates();
  280. }
  281. }
  282. /// <summary>
  283. /// Adds multiple custom labels to the collection.
  284. /// The labels will be DateTime labels with the specified interval type,
  285. /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
  286. /// </summary>
  287. /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
  288. /// <param name="intervalType">Unit of measurement of the label step.</param>
  289. public void Add(double labelsStep, DateTimeIntervalType intervalType)
  290. {
  291. Add(labelsStep, intervalType, 0, 0, "", 0, LabelMarkStyle.None);
  292. }
  293. /// <summary>
  294. /// Adds multiple custom labels to the collection.
  295. /// The labels will be DateTime labels with the specified interval type,
  296. /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
  297. /// </summary>
  298. /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
  299. /// <param name="intervalType">Unit of measurement of the label step.</param>
  300. /// <param name="format">Label text format.</param>
  301. public void Add(double labelsStep, DateTimeIntervalType intervalType, string format)
  302. {
  303. Add(labelsStep, intervalType, 0, 0, format, 0, LabelMarkStyle.None);
  304. }
  305. /// <summary>
  306. /// Adds multiple custom labels to the collection.
  307. /// The labels will be DateTime labels with the specified interval type,
  308. /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
  309. /// </summary>
  310. /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
  311. /// <param name="intervalType">Unit of measurement of the label step.</param>
  312. /// <param name="format">Label text format.</param>
  313. /// <param name="rowIndex">Label row index.</param>
  314. /// <param name="markStyle">Label marking style.</param>
  315. public void Add(double labelsStep, DateTimeIntervalType intervalType, string format, int rowIndex, LabelMarkStyle markStyle)
  316. {
  317. Add(labelsStep, intervalType, 0, 0, format, rowIndex, markStyle);
  318. }
  319. #endregion
  320. }
  321. /// <summary>
  322. /// The CustomLabel class represents a single custom axis label. Text and
  323. /// position along the axis is provided by the caller.
  324. /// </summary>
  325. [
  326. SRDescription("DescriptionAttributeCustomLabel_CustomLabel"),
  327. DefaultProperty("Text"),
  328. ]
  329. public class CustomLabel : ChartNamedElement
  330. {
  331. #region Fields and Constructors
  332. // Private data members, which store properties values
  333. private double _fromPosition = 0;
  334. private double _toPosition = 0;
  335. private string _text = "";
  336. private LabelMarkStyle _labelMark = LabelMarkStyle.None;
  337. private Color _foreColor = Color.Empty;
  338. private Color _markColor = Color.Empty;
  339. private int _labelRowIndex = 0;
  340. // Custom grid lines and tick marks flags
  341. private GridTickTypes _gridTick = GridTickTypes.None;
  342. // Indicates if label was automatically created or cpecified by user (custom)
  343. internal bool customLabel = true;
  344. // Image associated with the label
  345. private string _image = string.Empty;
  346. // Image transparent color
  347. private Color _imageTransparentColor = Color.Empty;
  348. // Label tooltip
  349. private string _tooltip = string.Empty;
  350. private Axis _axis = null;
  351. #endregion
  352. #region Constructors
  353. /// <summary>
  354. /// Default constructor
  355. /// </summary>
  356. public CustomLabel()
  357. {
  358. }
  359. /// <summary>
  360. /// CustomLabel constructor
  361. /// </summary>
  362. /// <param name="fromPosition">From position.</param>
  363. /// <param name="toPosition">To position.</param>
  364. /// <param name="text">Label text.</param>
  365. /// <param name="labelRow">Label row index.</param>
  366. /// <param name="markStyle">Label mark style.</param>
  367. public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle)
  368. {
  369. this._fromPosition = fromPosition;
  370. this._toPosition = toPosition;
  371. this._text = text;
  372. this._labelRowIndex = labelRow;
  373. this._labelMark = markStyle;
  374. this._gridTick = GridTickTypes.None;
  375. }
  376. /// <summary>
  377. /// CustomLabel constructor
  378. /// </summary>
  379. /// <param name="fromPosition">From position.</param>
  380. /// <param name="toPosition">To position.</param>
  381. /// <param name="text">Label text.</param>
  382. /// <param name="labelRow">Label row index.</param>
  383. /// <param name="markStyle">Label mark style.</param>
  384. /// <param name="gridTick">Custom grid line and tick marks flag.</param>
  385. public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle, GridTickTypes gridTick)
  386. {
  387. this._fromPosition = fromPosition;
  388. this._toPosition = toPosition;
  389. this._text = text;
  390. this._labelRowIndex = labelRow;
  391. this._labelMark = markStyle;
  392. this._gridTick = gridTick;
  393. }
  394. #endregion
  395. #region Helper methods
  396. /// <summary>
  397. /// Returns a cloned label object.
  398. /// </summary>
  399. /// <returns>Copy of current custom label.</returns>
  400. public CustomLabel Clone()
  401. {
  402. CustomLabel newLabel = new CustomLabel();
  403. newLabel.FromPosition = this.FromPosition;
  404. newLabel.ToPosition = this.ToPosition;
  405. newLabel.Text = this.Text;
  406. newLabel.ForeColor = this.ForeColor;
  407. newLabel.MarkColor = this.MarkColor;
  408. newLabel.RowIndex = this.RowIndex;
  409. newLabel.LabelMark = this.LabelMark;
  410. newLabel.GridTicks = this.GridTicks;
  411. newLabel.ToolTip = this.ToolTip;
  412. newLabel.Tag = this.Tag;
  413. newLabel.Image = this.Image;
  414. newLabel.ImageTransparentColor = this.ImageTransparentColor;
  415. return newLabel;
  416. }
  417. internal override IChartElement Parent
  418. {
  419. get
  420. {
  421. return base.Parent;
  422. }
  423. set
  424. {
  425. base.Parent = value;
  426. if (value != null)
  427. {
  428. _axis = Parent.Parent as Axis;
  429. }
  430. }
  431. }
  432. /// <summary>
  433. /// Gets the axis to which this object is attached to.
  434. /// </summary>
  435. /// <returns>Axis.</returns>
  436. [
  437. Browsable(false),
  438. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
  439. SerializationVisibilityAttribute(SerializationVisibility.Hidden),
  440. ]
  441. public Axis Axis
  442. {
  443. get
  444. {
  445. return _axis;
  446. }
  447. }
  448. #endregion
  449. #region CustomLabel properties
  450. /// <summary>
  451. /// Gets or sets the tooltip of the custom label.
  452. /// </summary>
  453. [
  454. SRCategory("CategoryAttributeMapArea"),
  455. Bindable(true),
  456. SRDescription("DescriptionAttributeToolTip"),
  457. DefaultValue("")
  458. ]
  459. public string ToolTip
  460. {
  461. set
  462. {
  463. this._tooltip = value;
  464. }
  465. get
  466. {
  467. return this._tooltip;
  468. CallOnModifing();
  469. }
  470. }
  471. /// <summary>
  472. /// Gets or sets the label image.
  473. /// </summary>
  474. [
  475. SRCategory("CategoryAttributeAppearance"),
  476. Bindable(true),
  477. DefaultValue(""),
  478. SRDescription("DescriptionAttributeCustomLabel_Image"),
  479. #if DESIGNER
  480. Editor(typeof(ImageValueEditor), typeof(UITypeEditor)),
  481. #endif
  482. NotifyParentPropertyAttribute(true)
  483. ]
  484. public string Image
  485. {
  486. get
  487. {
  488. return _image;
  489. }
  490. set
  491. {
  492. _image = value;
  493. Invalidate();
  494. CallOnModifing();
  495. }
  496. }
  497. /// <summary>
  498. /// Gets or sets a color which will be replaced with a transparent color while drawing the image.
  499. /// </summary>
  500. [
  501. SRCategory("CategoryAttributeAppearance"),
  502. Bindable(true),
  503. DefaultValue(typeof(Color), ""),
  504. NotifyParentPropertyAttribute(true),
  505. SRDescription("DescriptionAttributeImageTransparentColor"),
  506. TypeConverter(typeof(ColorConverter)),
  507. #if DESIGNER
  508. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  509. #endif
  510. ]
  511. public Color ImageTransparentColor
  512. {
  513. get
  514. {
  515. return _imageTransparentColor;
  516. }
  517. set
  518. {
  519. _imageTransparentColor = value;
  520. this.Invalidate();
  521. CallOnModifing();
  522. }
  523. }
  524. /// <summary>
  525. /// Custom label name. This property is for internal use only.
  526. /// </summary>
  527. [
  528. SRCategory("CategoryAttributeAppearance"),
  529. SRDescription("DescriptionAttributeCustomLabel_Name"),
  530. DefaultValue("Custom LabelStyle"),
  531. DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
  532. DesignOnlyAttribute(true),
  533. SerializationVisibilityAttribute(SerializationVisibility.Hidden)
  534. ]
  535. public override string Name
  536. {
  537. get
  538. {
  539. return base.Name;
  540. }
  541. set
  542. {
  543. base.Name = value;
  544. CallOnModifing();
  545. }
  546. }
  547. /// <summary>
  548. /// Gets or sets a property which specifies whether
  549. /// custom tick marks and grid lines will be drawn in the center of the label.
  550. /// </summary>
  551. [
  552. SRCategory("CategoryAttributeAppearance"),
  553. Bindable(true),
  554. DefaultValue(GridTickTypes.None),
  555. SRDescription("DescriptionAttributeCustomLabel_GridTicks"),
  556. #if DESIGNER
  557. Editor(typeof(FlagsEnumUITypeEditor), typeof(UITypeEditor))
  558. #endif
  559. ]
  560. public GridTickTypes GridTicks
  561. {
  562. get
  563. {
  564. return _gridTick;
  565. }
  566. set
  567. {
  568. _gridTick = value;
  569. this.Invalidate();
  570. CallOnModifing();
  571. }
  572. }
  573. /// <summary>
  574. /// Gets or sets the end position of the custom label in axis coordinates.
  575. /// </summary>
  576. [
  577. SRCategory("CategoryAttributeAppearance"),
  578. Bindable(true),
  579. DefaultValue(0.0),
  580. SRDescription("DescriptionAttributeCustomLabel_From"),
  581. TypeConverter(typeof(AxisLabelDateValueConverter))
  582. ]
  583. public double FromPosition
  584. {
  585. get
  586. {
  587. return _fromPosition;
  588. }
  589. set
  590. {
  591. _fromPosition = value;
  592. this.Invalidate();
  593. CallOnModifing();
  594. }
  595. }
  596. /// <summary>
  597. /// Gets or sets the starting position of the custom label in axis coordinates.
  598. /// </summary>
  599. [
  600. SRCategory("CategoryAttributeAppearance"),
  601. Bindable(true),
  602. DefaultValue(0.0),
  603. SRDescription("DescriptionAttributeCustomLabel_To"),
  604. TypeConverter(typeof(AxisLabelDateValueConverter))
  605. ]
  606. public double ToPosition
  607. {
  608. get
  609. {
  610. return _toPosition;
  611. }
  612. set
  613. {
  614. _toPosition = value;
  615. this.Invalidate();
  616. CallOnModifing();
  617. }
  618. }
  619. /// <summary>
  620. /// Gets or sets the text of the custom label.
  621. /// </summary>
  622. [
  623. SRCategory("CategoryAttributeAppearance"),
  624. Bindable(true),
  625. DefaultValue(""),
  626. SRDescription("DescriptionAttributeCustomLabel_Text")
  627. ]
  628. public string Text
  629. {
  630. get
  631. {
  632. return _text;
  633. }
  634. set
  635. {
  636. _text = value;
  637. this.Invalidate();
  638. CallOnModifing();
  639. }
  640. }
  641. /// <summary>
  642. /// Gets or sets the text color of the custom label.
  643. /// </summary>
  644. [
  645. SRCategory("CategoryAttributeAppearance"),
  646. Bindable(true),
  647. DefaultValue(typeof(Color), ""),
  648. SRDescription("DescriptionAttributeForeColor"),
  649. NotifyParentPropertyAttribute(true),
  650. TypeConverter(typeof(ColorConverter)),
  651. #if DESIGNER
  652. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  653. #endif
  654. ]
  655. public Color ForeColor
  656. {
  657. get
  658. {
  659. return _foreColor;
  660. }
  661. set
  662. {
  663. _foreColor = value;
  664. this.Invalidate();
  665. CallOnModifing();
  666. }
  667. }
  668. /// <summary>
  669. /// Gets or sets the color of the label mark line of the custom label.
  670. /// </summary>
  671. [
  672. SRCategory("CategoryAttributeAppearance"),
  673. Bindable(true),
  674. DefaultValue(typeof(Color), ""),
  675. SRDescription("DescriptionAttributeCustomLabel_MarkColor"),
  676. NotifyParentPropertyAttribute(true),
  677. TypeConverter(typeof(ColorConverter)),
  678. #if DESIGNER
  679. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  680. #endif
  681. ]
  682. public Color MarkColor
  683. {
  684. get
  685. {
  686. return _markColor;
  687. }
  688. set
  689. {
  690. _markColor = value;
  691. this.Invalidate();
  692. CallOnModifing();
  693. }
  694. }
  695. /// <summary>
  696. /// Gets or sets the row index of the custom label.
  697. /// </summary>
  698. [
  699. SRCategory("CategoryAttributeAppearance"),
  700. Bindable(true),
  701. DefaultValue(0),
  702. SRDescription("DescriptionAttributeCustomLabel_RowIndex")
  703. ]
  704. public int RowIndex
  705. {
  706. get
  707. {
  708. return this._labelRowIndex;
  709. }
  710. set
  711. {
  712. if(value < 0)
  713. {
  714. throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexIsNegative));
  715. }
  716. this._labelRowIndex = value;
  717. this.Invalidate();
  718. CallOnModifing();
  719. }
  720. }
  721. /// <summary>
  722. /// Gets or sets a property which define the marks for the labels in the second row.
  723. /// </summary>
  724. [
  725. SRCategory("CategoryAttributeAppearance"),
  726. Bindable(true),
  727. DefaultValue(LabelMarkStyle.None),
  728. SRDescription("DescriptionAttributeCustomLabel_LabelMark")
  729. ]
  730. public LabelMarkStyle LabelMark
  731. {
  732. get
  733. {
  734. return _labelMark;
  735. }
  736. set
  737. {
  738. _labelMark = value;
  739. this.Invalidate();
  740. CallOnModifing();
  741. }
  742. }
  743. #endregion
  744. }
  745. /// <summary>
  746. /// The LabelStyle class contains properties which define the visual appearance of
  747. /// the axis labels, their interval and position. This class is also
  748. /// responsible for calculating the position of all the labels and
  749. /// drawing them.
  750. /// </summary>
  751. [
  752. SRDescription("DescriptionAttributeLabel_Label"),
  753. DefaultProperty("Enabled"),
  754. ]
  755. public class LabelStyle : ChartElement
  756. {
  757. #region Fields
  758. // Reference to the Axis
  759. private Axis _axis = null;
  760. // Private data members, which store properties values
  761. private bool _enabled = true;
  762. internal double intervalOffset = double.NaN;
  763. internal double interval = double.NaN;
  764. internal DateTimeIntervalType intervalType = DateTimeIntervalType.NotSet;
  765. internal DateTimeIntervalType intervalOffsetType = DateTimeIntervalType.NotSet;
  766. private FontCache _fontCache = new FontCache();
  767. private Font _font;
  768. private Color _foreColor = Color.Black;
  769. internal int angle = 0;
  770. internal bool isStaggered = false;
  771. private bool _isEndLabelVisible = true;
  772. private bool _truncatedLabels = false;
  773. private string _format = "";
  774. #endregion
  775. #region Constructors
  776. /// <summary>
  777. /// Public default constructor.
  778. /// </summary>
  779. public LabelStyle()
  780. {
  781. _font = _fontCache.DefaultFont;
  782. }
  783. /// <summary>
  784. /// Public constructor.
  785. /// </summary>
  786. /// <param name="axis">Axis which owns the grid.</param>
  787. internal LabelStyle(Axis axis)
  788. : this()
  789. {
  790. _axis = axis;
  791. }
  792. #endregion
  793. #region Axis labels drawing methods
  794. /// <summary>
  795. /// Draws axis labels on the circular chart area.
  796. /// </summary>
  797. /// <param name="graph">Reference to the Chart Graphics object.</param>
  798. internal void PaintCircular( ChartGraphics graph )
  799. {
  800. // Label string drawing format
  801. using (StringFormat format = new StringFormat())
  802. {
  803. format.FormatFlags |= StringFormatFlags.LineLimit;
  804. format.Trimming = StringTrimming.EllipsisCharacter;
  805. // Labels are disabled for this axis
  806. if (!_axis.LabelStyle.Enabled)
  807. return;
  808. // Draw text with anti-aliasing
  809. /*
  810. if( (graph.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
  811. {
  812. graph.TextRenderingHint = TextRenderingHint.AntiAlias;
  813. }
  814. else
  815. {
  816. graph.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
  817. }
  818. */
  819. // Gets axis labels style
  820. CircularAxisLabelsStyle labelsStyle = this._axis.ChartArea.GetCircularAxisLabelsStyle();
  821. // Get list of circular axes with labels
  822. ArrayList circularAxes = this._axis.ChartArea.GetCircularAxisList();
  823. // Draw each axis label
  824. int index = 0;
  825. foreach (CircularChartAreaAxis circAxis in circularAxes)
  826. {
  827. if (circAxis.Title.Length > 0)
  828. {
  829. //******************************************************************
  830. //** Calculate label position corner position
  831. //******************************************************************
  832. PointF labelRelativePosition = new PointF(
  833. this._axis.ChartArea.circularCenter.X,
  834. this._axis.ChartArea.PlotAreaPosition.Y);
  835. // Adjust labels Y position
  836. labelRelativePosition.Y -= _axis.markSize + Axis.elementSpacing;
  837. // Convert to absolute
  838. PointF[] labelPosition = new PointF[] { graph.GetAbsolutePoint(labelRelativePosition) };
  839. // Get label rotation angle
  840. float labelAngle = circAxis.AxisPosition;
  841. ICircularChartType chartType = this._axis.ChartArea.GetCircularChartType();
  842. if (chartType != null && chartType.XAxisCrossingSupported())
  843. {
  844. if (!double.IsNaN(this._axis.ChartArea.AxisX.Crossing))
  845. {
  846. labelAngle += (float)this._axis.ChartArea.AxisX.Crossing;
  847. }
  848. }
  849. // Make sure angle is presented as a positive number
  850. while (labelAngle < 0)
  851. {
  852. labelAngle = 360f + labelAngle;
  853. }
  854. // Set graphics rotation matrix
  855. Matrix newMatrix = new Matrix();
  856. newMatrix.RotateAt(labelAngle, graph.GetAbsolutePoint(this._axis.ChartArea.circularCenter));
  857. newMatrix.TransformPoints(labelPosition);
  858. // Set text alignment
  859. format.LineAlignment = StringAlignment.Center;
  860. format.Alignment = StringAlignment.Near;
  861. if (labelsStyle != CircularAxisLabelsStyle.Radial)
  862. {
  863. if (labelAngle < 5f || labelAngle > 355f)
  864. {
  865. format.Alignment = StringAlignment.Center;
  866. format.LineAlignment = StringAlignment.Far;
  867. }
  868. if (labelAngle < 185f && labelAngle > 175f)
  869. {
  870. format.Alignment = StringAlignment.Center;
  871. format.LineAlignment = StringAlignment.Near;
  872. }
  873. if (labelAngle > 185f && labelAngle < 355f)
  874. {
  875. format.Alignment = StringAlignment.Far;
  876. }
  877. }
  878. else
  879. {
  880. if (labelAngle > 180f)
  881. {
  882. format.Alignment = StringAlignment.Far;
  883. }
  884. }
  885. // Set text rotation angle
  886. float textAngle = labelAngle;
  887. if (labelsStyle == CircularAxisLabelsStyle.Radial)
  888. {
  889. if (labelAngle > 180)
  890. {
  891. textAngle += 90f;
  892. }
  893. else
  894. {
  895. textAngle -= 90f;
  896. }
  897. }
  898. else if (labelsStyle == CircularAxisLabelsStyle.Circular)
  899. {
  900. format.Alignment = StringAlignment.Center;
  901. format.LineAlignment = StringAlignment.Far;
  902. }
  903. // Set text rotation matrix
  904. Matrix oldMatrix = graph.Transform;
  905. if (labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
  906. {
  907. Matrix textRotationMatrix = oldMatrix.Clone();
  908. textRotationMatrix.RotateAt(textAngle, labelPosition[0]);
  909. graph.Transform = textRotationMatrix;
  910. }
  911. // Get axis titl (label) color
  912. Color labelColor = _foreColor;
  913. if (!circAxis.TitleForeColor.IsEmpty)
  914. {
  915. labelColor = circAxis.TitleForeColor;
  916. }
  917. // Draw label
  918. using (Brush brush = new SolidBrush(labelColor))
  919. {
  920. graph.DrawString(
  921. circAxis.Title.Replace("\\n", "\n"),
  922. (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
  923. brush,
  924. labelPosition[0],
  925. format);
  926. }
  927. // Process selection region
  928. if (this._axis.Common.ProcessModeRegions)
  929. {
  930. SizeF size = graph.MeasureString(circAxis.Title.Replace("\\n", "\n"), (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont);
  931. RectangleF labelRect = GetLabelPosition(
  932. labelPosition[0],
  933. size,
  934. format);
  935. PointF[] points = new PointF[]
  936. {
  937. labelRect.Location,
  938. new PointF(labelRect.Right, labelRect.Y),
  939. new PointF(labelRect.Right, labelRect.Bottom),
  940. new PointF(labelRect.X, labelRect.Bottom)
  941. };
  942. using (GraphicsPath path = new GraphicsPath())
  943. {
  944. path.AddPolygon(points);
  945. path.CloseAllFigures();
  946. path.Transform(graph.Transform);
  947. this._axis.Common.HotRegionsList.AddHotRegion(
  948. path,
  949. false,
  950. ChartElementType.AxisLabels,
  951. circAxis.Title);
  952. }
  953. }
  954. // Restore graphics
  955. if(labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
  956. {
  957. graph.Transform = oldMatrix;
  958. }
  959. }
  960. ++index;
  961. }
  962. }
  963. }
  964. /// <summary>
  965. /// Gets rectangle position of the label.
  966. /// </summary>
  967. /// <param name="position">Original label position.</param>
  968. /// <param name="size">Label text size.</param>
  969. /// <param name="format">Label string format.</param>
  970. /// <returns>Label rectangle position.</returns>
  971. internal static RectangleF GetLabelPosition(
  972. PointF position,
  973. SizeF size,
  974. StringFormat format)
  975. {
  976. // Calculate label position rectangle
  977. RectangleF labelPosition = RectangleF.Empty;
  978. labelPosition.Width = size.Width;
  979. labelPosition.Height = size.Height;
  980. if(format.Alignment == StringAlignment.Far)
  981. {
  982. labelPosition.X = position.X - size.Width;
  983. }
  984. else if(format.Alignment == StringAlignment.Near)
  985. {
  986. labelPosition.X = position.X;
  987. }
  988. else if(format.Alignment == StringAlignment.Center)
  989. {
  990. labelPosition.X = position.X - size.Width/2F;
  991. }
  992. if(format.LineAlignment == StringAlignment.Far)
  993. {
  994. labelPosition.Y = position.Y - size.Height;
  995. }
  996. else if(format.LineAlignment == StringAlignment.Near)
  997. {
  998. labelPosition.Y = position.Y;
  999. }
  1000. else if(format.LineAlignment == StringAlignment.Center)
  1001. {
  1002. labelPosition.Y = position.Y - size.Height/2F;
  1003. }
  1004. return labelPosition;
  1005. }
  1006. /// <summary>
  1007. /// Draws axis labels.
  1008. /// </summary>
  1009. /// <param name="graph">Reference to the Chart Graphics object.</param>
  1010. /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
  1011. internal void Paint( ChartGraphics graph, bool backElements )
  1012. {
  1013. // Label string drawing format
  1014. using (StringFormat format = new StringFormat())
  1015. {
  1016. format.FormatFlags |= StringFormatFlags.LineLimit;
  1017. format.Trimming = StringTrimming.EllipsisCharacter;
  1018. // Labels are disabled for this axis
  1019. if (!_axis.LabelStyle.Enabled)
  1020. return;
  1021. // deliant fix-> VSTS #157848, #143286 - drawing custom label in empty axis
  1022. if (Double.IsNaN(_axis.ViewMinimum) || Double.IsNaN(_axis.ViewMaximum))
  1023. return;
  1024. // Draw labels in 3D space
  1025. if (this._axis.ChartArea.Area3DStyle.Enable3D && !this._axis.ChartArea.chartAreaIsCurcular)
  1026. {
  1027. this.Paint3D(graph, backElements);
  1028. return;
  1029. }
  1030. // Initialize all labels position rectangle
  1031. RectangleF rectLabels = _axis.ChartArea.Position.ToRectangleF();
  1032. float labelSize = _axis.labelSize;
  1033. if (_axis.AxisPosition == AxisPosition.Left)
  1034. {
  1035. rectLabels.Width = labelSize;
  1036. if (_axis.GetIsMarksNextToAxis())
  1037. rectLabels.X = (float)_axis.GetAxisPosition();
  1038. else
  1039. rectLabels.X = _axis.PlotAreaPosition.X;
  1040. rectLabels.X -= labelSize + _axis.markSize;
  1041. // Set label text alignment
  1042. format.Alignment = StringAlignment.Far;
  1043. format.LineAlignment = StringAlignment.Center;
  1044. }
  1045. else if (_axis.AxisPosition == AxisPosition.Right)
  1046. {
  1047. rectLabels.Width = labelSize;
  1048. if (_axis.GetIsMarksNextToAxis())
  1049. rectLabels.X = (float)_axis.GetAxisPosition();
  1050. else
  1051. rectLabels.X = _axis.PlotAreaPosition.Right;
  1052. rectLabels.X += _axis.markSize;
  1053. // Set label text alignment
  1054. format.Alignment = StringAlignment.Near;
  1055. format.LineAlignment = StringAlignment.Center;
  1056. }
  1057. else if (_axis.AxisPosition == AxisPosition.Top)
  1058. {
  1059. rectLabels.Height = labelSize;
  1060. if (_axis.GetIsMarksNextToAxis())
  1061. rectLabels.Y = (float)_axis.GetAxisPosition();
  1062. else
  1063. rectLabels.Y = _axis.PlotAreaPosition.Y;
  1064. rectLabels.Y -= labelSize + _axis.markSize;
  1065. // Set label text alignment
  1066. format.Alignment = StringAlignment.Center;
  1067. format.LineAlignment = StringAlignment.Far;
  1068. }
  1069. else if (_axis.AxisPosition == AxisPosition.Bottom)
  1070. {
  1071. rectLabels.Height = labelSize;
  1072. if (_axis.GetIsMarksNextToAxis())
  1073. rectLabels.Y = (float)_axis.GetAxisPosition();
  1074. else
  1075. rectLabels.Y = _axis.PlotAreaPosition.Bottom;
  1076. rectLabels.Y += _axis.markSize;
  1077. // Set label text alignment
  1078. format.Alignment = StringAlignment.Center;
  1079. format.LineAlignment = StringAlignment.Near;
  1080. }
  1081. // Calculate bounding rectangle
  1082. RectangleF boundaryRect = rectLabels;
  1083. if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
  1084. {
  1085. if (_axis.AxisPosition == AxisPosition.Left)
  1086. {
  1087. boundaryRect.X += _axis.totlaGroupingLabelsSize;
  1088. boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
  1089. }
  1090. else if (_axis.AxisPosition == AxisPosition.Right)
  1091. {
  1092. boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
  1093. }
  1094. else if (_axis.AxisPosition == AxisPosition.Top)
  1095. {
  1096. boundaryRect.Y += _axis.totlaGroupingLabelsSize;
  1097. boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
  1098. }
  1099. else if (_axis.AxisPosition == AxisPosition.Bottom)
  1100. {
  1101. boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
  1102. }
  1103. }
  1104. // Check if the AJAX zooming and scrolling mode is enabled.
  1105. // Labels are drawn slightly different in this case.
  1106. bool ajaxScrollingEnabled = false;
  1107. bool firstFrame = true;
  1108. bool lastFrame = true;
  1109. // Draw all labels from the collection
  1110. int labelIndex = 0;
  1111. foreach (CustomLabel label in this._axis.CustomLabels)
  1112. {
  1113. bool truncatedLeft = false;
  1114. bool truncatedRight = false;
  1115. double labelFrom = label.FromPosition;
  1116. double labelTo = label.ToPosition;
  1117. bool useRelativeCoordiantes = false;
  1118. double labelFromRelative = double.NaN;
  1119. double labelToRelative = double.NaN;
  1120. // Skip if label middle point is outside current scaleView
  1121. if (label.RowIndex == 0)
  1122. {
  1123. double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
  1124. decimal viewMin = (decimal)_axis.ViewMinimum;
  1125. decimal viewMax = (decimal)_axis.ViewMaximum;
  1126. if (ajaxScrollingEnabled)
  1127. {
  1128. // Skip very first and last labels if they are partialy outside the scaleView
  1129. if (firstFrame)
  1130. {
  1131. if ((decimal)label.FromPosition < (decimal)_axis.Minimum)
  1132. {
  1133. continue;
  1134. }
  1135. }
  1136. if (lastFrame)
  1137. {
  1138. if ((decimal)label.ToPosition > (decimal)_axis.Maximum)
  1139. {
  1140. continue;
  1141. }
  1142. }
  1143. // Skip label only if it is compleltly out of the scaleView
  1144. if ((decimal)label.ToPosition < viewMin ||
  1145. (decimal)label.FromPosition > viewMax)
  1146. {
  1147. continue;
  1148. }
  1149. // RecalculateAxesScale label index starting from the first frame.
  1150. // Index is used to determine position of the offset labels
  1151. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1152. {
  1153. // Reset index
  1154. labelIndex = 0;
  1155. // Get first series attached to this axis
  1156. Series axisSeries = null;
  1157. if (_axis.axisType == AxisName.X || _axis.axisType == AxisName.X2)
  1158. {
  1159. List<string> seriesArray = _axis.ChartArea.GetXAxesSeries((_axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, _axis.SubAxisName);
  1160. if (seriesArray.Count > 0)
  1161. {
  1162. axisSeries = _axis.Common.DataManager.Series[seriesArray[0]];
  1163. if (axisSeries != null && !axisSeries.IsXValueIndexed)
  1164. {
  1165. axisSeries = null;
  1166. }
  1167. }
  1168. }
  1169. // Set start position and iterate through label positions
  1170. // NOTE: Labels offset should not be taken in the account
  1171. double currentPosition = _axis.Minimum;
  1172. while (currentPosition < _axis.Maximum)
  1173. {
  1174. if (currentPosition >= middlePoint)
  1175. {
  1176. break;
  1177. }
  1178. currentPosition += ChartHelper.GetIntervalSize(currentPosition, _axis.LabelStyle.GetInterval(), _axis.LabelStyle.GetIntervalType(),
  1179. axisSeries, 0.0, DateTimeIntervalType.Number, true);
  1180. ++labelIndex;
  1181. }
  1182. }
  1183. }
  1184. else
  1185. {
  1186. // Skip label if label middle point is not in the scaleView
  1187. if ((decimal)middlePoint < viewMin ||
  1188. (decimal)middlePoint > viewMax)
  1189. {
  1190. continue;
  1191. }
  1192. }
  1193. // Make sure label To and From coordinates are processed by one scale segment based
  1194. // on the label middle point position.
  1195. if (_axis.ScaleSegments.Count > 0)
  1196. {
  1197. AxisScaleSegment scaleSegment = _axis.ScaleSegments.FindScaleSegmentForAxisValue(middlePoint);
  1198. _axis.ScaleSegments.AllowOutOfScaleValues = true;
  1199. _axis.ScaleSegments.EnforceSegment(scaleSegment);
  1200. }
  1201. // Use center point instead of the To/From if label takes all scaleView
  1202. // This is done to avoid issues with labels drawing with high
  1203. // zooming levels.
  1204. if ((decimal)label.FromPosition < viewMin &&
  1205. (decimal)label.ToPosition > viewMax)
  1206. {
  1207. // Indicates that chart relative coordinates should be used instead of axis values
  1208. useRelativeCoordiantes = true;
  1209. // Calculate label From/To in relative coordinates using
  1210. // label middle point and 100% width.
  1211. labelFromRelative = _axis.GetLinearPosition(middlePoint) - 50.0;
  1212. labelToRelative = labelFromRelative + 100.0;
  1213. }
  1214. }
  1215. else
  1216. {
  1217. // Skip labels completly outside the scaleView
  1218. if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
  1219. {
  1220. continue;
  1221. }
  1222. // Check if label is partially visible.
  1223. if (!ajaxScrollingEnabled &&
  1224. _axis.ScaleView.IsZoomed)
  1225. {
  1226. if (label.FromPosition < _axis.ViewMinimum)
  1227. {
  1228. truncatedLeft = true;
  1229. labelFrom = _axis.ViewMinimum;
  1230. }
  1231. if (label.ToPosition > _axis.ViewMaximum)
  1232. {
  1233. truncatedRight = true;
  1234. labelTo = _axis.ViewMaximum;
  1235. }
  1236. }
  1237. }
  1238. // Calculate single label position
  1239. RectangleF rect = rectLabels;
  1240. // Label is in the first row
  1241. if (label.RowIndex == 0)
  1242. {
  1243. if (_axis.AxisPosition == AxisPosition.Left)
  1244. {
  1245. rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
  1246. rect.Width = _axis.unRotatedLabelSize;
  1247. // Adjust label rectangle if offset labels are used
  1248. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1249. {
  1250. rect.Width /= 2F;
  1251. if (labelIndex % 2 != 0F)
  1252. {
  1253. rect.X += rect.Width;
  1254. }
  1255. }
  1256. }
  1257. else if (_axis.AxisPosition == AxisPosition.Right)
  1258. {
  1259. rect.Width = _axis.unRotatedLabelSize;
  1260. // Adjust label rectangle if offset labels are used
  1261. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1262. {
  1263. rect.Width /= 2F;
  1264. if (labelIndex % 2 != 0F)
  1265. {
  1266. rect.X += rect.Width;
  1267. }
  1268. }
  1269. }
  1270. else if (_axis.AxisPosition == AxisPosition.Top)
  1271. {
  1272. rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
  1273. rect.Height = _axis.unRotatedLabelSize;
  1274. // Adjust label rectangle if offset labels are used
  1275. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1276. {
  1277. rect.Height /= 2F;
  1278. if (labelIndex % 2 != 0F)
  1279. {
  1280. rect.Y += rect.Height;
  1281. }
  1282. }
  1283. }
  1284. else if (_axis.AxisPosition == AxisPosition.Bottom)
  1285. {
  1286. rect.Height = _axis.unRotatedLabelSize;
  1287. // Adjust label rectangle if offset labels are used
  1288. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1289. {
  1290. rect.Height /= 2F;
  1291. if (labelIndex % 2 != 0F)
  1292. {
  1293. rect.Y += rect.Height;
  1294. }
  1295. }
  1296. }
  1297. // Increase label index
  1298. ++labelIndex;
  1299. }
  1300. // Label is in the second row
  1301. else if (label.RowIndex > 0)
  1302. {
  1303. if (_axis.AxisPosition == AxisPosition.Left)
  1304. {
  1305. rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
  1306. for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
  1307. {
  1308. rect.X += _axis.groupingLabelSizes[index - 1];
  1309. }
  1310. rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
  1311. }
  1312. else if (_axis.AxisPosition == AxisPosition.Right)
  1313. {
  1314. rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
  1315. for (int index = 1; index < label.RowIndex; index++)
  1316. {
  1317. rect.X += _axis.groupingLabelSizes[index - 1];
  1318. }
  1319. rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
  1320. }
  1321. else if (_axis.AxisPosition == AxisPosition.Top)
  1322. {
  1323. rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
  1324. for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
  1325. {
  1326. rect.Y += _axis.groupingLabelSizes[index - 1];
  1327. }
  1328. rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
  1329. }
  1330. if (_axis.AxisPosition == AxisPosition.Bottom)
  1331. {
  1332. rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
  1333. for (int index = 1; index < label.RowIndex; index++)
  1334. {
  1335. rect.Y += _axis.groupingLabelSizes[index - 1];
  1336. }
  1337. rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
  1338. }
  1339. }
  1340. // Unknown label row value
  1341. else
  1342. {
  1343. throw (new InvalidOperationException(SR.ExceptionAxisLabelIndexIsNegative));
  1344. }
  1345. // Set label From and To coordinates
  1346. double fromPosition = _axis.GetLinearPosition(labelFrom);
  1347. double toPosition = _axis.GetLinearPosition(labelTo);
  1348. if (useRelativeCoordiantes)
  1349. {
  1350. useRelativeCoordiantes = false;
  1351. fromPosition = labelFromRelative;
  1352. toPosition = labelToRelative;
  1353. }
  1354. if (_axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom)
  1355. {
  1356. rect.X = (float)Math.Min(fromPosition, toPosition);
  1357. rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
  1358. // Adjust label To/From position if offset labels are used
  1359. if (label.RowIndex == 0 &&
  1360. ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
  1361. {
  1362. rect.X -= rect.Width / 2F;
  1363. rect.Width *= 2F;
  1364. }
  1365. }
  1366. else
  1367. {
  1368. rect.Y = (float)Math.Min(fromPosition, toPosition);
  1369. rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
  1370. // Adjust label To/From position if offset labels are used
  1371. if (label.RowIndex == 0 &&
  1372. ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
  1373. {
  1374. rect.Y -= rect.Height / 2F;
  1375. rect.Height *= 2F;
  1376. }
  1377. }
  1378. // Draw label
  1379. using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
  1380. {
  1381. graph.DrawLabelStringRel(_axis,
  1382. label.RowIndex,
  1383. label.LabelMark,
  1384. label.MarkColor,
  1385. label.Text,
  1386. label.Image,
  1387. label.ImageTransparentColor,
  1388. (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
  1389. brush,
  1390. rect,
  1391. format,
  1392. (_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle,
  1393. (!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
  1394. label,
  1395. truncatedLeft,
  1396. truncatedRight);
  1397. }
  1398. // Clear scale segment enforcement
  1399. _axis.ScaleSegments.EnforceSegment(null);
  1400. _axis.ScaleSegments.AllowOutOfScaleValues = false;
  1401. }
  1402. }
  1403. }
  1404. #endregion
  1405. #region 3D Axis labels drawing methods
  1406. /// <summary>
  1407. /// Get a rectangle between chart area position and plotting area on specified side.
  1408. /// Also sets axis labels string formatting for the specified labels position.
  1409. /// </summary>
  1410. /// <param name="area">Chart area object.</param>
  1411. /// <param name="position">Position in chart area.</param>
  1412. /// <param name="stringFormat">Axis labels string format.</param>
  1413. /// <returns>Axis labels rectangle.</returns>
  1414. private RectangleF GetAllLabelsRect(ChartArea area, AxisPosition position, StringFormat stringFormat)
  1415. {
  1416. // Find axis with same position
  1417. Axis labelsAxis = null;
  1418. foreach(Axis curAxis in area.Axes)
  1419. {
  1420. if(curAxis.AxisPosition == position)
  1421. {
  1422. labelsAxis = curAxis;
  1423. break;
  1424. }
  1425. }
  1426. if(labelsAxis == null)
  1427. {
  1428. return RectangleF.Empty;
  1429. }
  1430. // Calculate rect for different positions
  1431. RectangleF rectLabels = area.Position.ToRectangleF();
  1432. if( position == AxisPosition.Left )
  1433. {
  1434. rectLabels.Width = labelsAxis.labelSize;
  1435. if( labelsAxis.GetIsMarksNextToAxis() )
  1436. {
  1437. rectLabels.X = (float)labelsAxis.GetAxisPosition();
  1438. rectLabels.Width = (float)Math.Max(rectLabels.Width, rectLabels.X - labelsAxis.PlotAreaPosition.X);
  1439. }
  1440. else
  1441. {
  1442. rectLabels.X = labelsAxis.PlotAreaPosition.X;
  1443. }
  1444. rectLabels.X -= rectLabels.Width;
  1445. if(area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
  1446. {
  1447. rectLabels.X -= labelsAxis.markSize;
  1448. }
  1449. // Set label text alignment
  1450. stringFormat.Alignment = StringAlignment.Far;
  1451. stringFormat.LineAlignment = StringAlignment.Center;
  1452. }
  1453. else if( position == AxisPosition.Right )
  1454. {
  1455. rectLabels.Width = labelsAxis.labelSize;
  1456. if( labelsAxis.GetIsMarksNextToAxis() )
  1457. {
  1458. rectLabels.X = (float)labelsAxis.GetAxisPosition();
  1459. rectLabels.Width = (float)Math.Max(rectLabels.Width, labelsAxis.PlotAreaPosition.Right - rectLabels.X);
  1460. }
  1461. else
  1462. {
  1463. rectLabels.X = labelsAxis.PlotAreaPosition.Right;
  1464. }
  1465. if(!area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
  1466. {
  1467. rectLabels.X += labelsAxis.markSize;
  1468. }
  1469. // Set label text alignment
  1470. stringFormat.Alignment = StringAlignment.Near;
  1471. stringFormat.LineAlignment = StringAlignment.Center;
  1472. }
  1473. else if( position == AxisPosition.Top )
  1474. {
  1475. rectLabels.Height = labelsAxis.labelSize;
  1476. if( labelsAxis.GetIsMarksNextToAxis() )
  1477. {
  1478. rectLabels.Y = (float)labelsAxis.GetAxisPosition();
  1479. rectLabels.Height = (float)Math.Max(rectLabels.Height, rectLabels.Y - labelsAxis.PlotAreaPosition.Y);
  1480. }
  1481. else
  1482. {
  1483. rectLabels.Y = labelsAxis.PlotAreaPosition.Y;
  1484. }
  1485. rectLabels.Y -= rectLabels.Height;
  1486. if(area.Area3DStyle.WallWidth == 0)
  1487. {
  1488. rectLabels.Y -= labelsAxis.markSize;
  1489. }
  1490. // Set label text alignment
  1491. stringFormat.Alignment = StringAlignment.Center;
  1492. stringFormat.LineAlignment = StringAlignment.Far;
  1493. }
  1494. else if( position == AxisPosition.Bottom )
  1495. {
  1496. rectLabels.Height = labelsAxis.labelSize;
  1497. if( labelsAxis.GetIsMarksNextToAxis() )
  1498. {
  1499. rectLabels.Y = (float)labelsAxis.GetAxisPosition();
  1500. rectLabels.Height = (float)Math.Max(rectLabels.Height, labelsAxis.PlotAreaPosition.Bottom - rectLabels.Y);
  1501. }
  1502. else
  1503. {
  1504. rectLabels.Y = labelsAxis.PlotAreaPosition.Bottom;
  1505. }
  1506. rectLabels.Y += labelsAxis.markSize;
  1507. // Set label text alignment
  1508. stringFormat.Alignment = StringAlignment.Center;
  1509. stringFormat.LineAlignment = StringAlignment.Near;
  1510. }
  1511. return rectLabels;
  1512. }
  1513. /// <summary>
  1514. /// Gets position of axis labels.
  1515. /// Top and Bottom axis labels can be drawn on the sides (left or right)
  1516. /// of the plotting area. If angle between axis and it's projection is
  1517. /// between -25 and 25 degrees the axis are drawn at the bottom/top,
  1518. /// otherwise labels are moved on the left or right side.
  1519. /// </summary>
  1520. /// <param name="axis">Axis object.</param>
  1521. /// <returns>Position where axis labels should be drawn.</returns>
  1522. private AxisPosition GetLabelsPosition(Axis axis)
  1523. {
  1524. // Get angle between 2D axis and it's 3D projection.
  1525. double axisAngle = axis.GetAxisProjectionAngle();
  1526. // Pick the side to draw the labels on
  1527. if(axis.AxisPosition == AxisPosition.Bottom)
  1528. {
  1529. if(axisAngle <= -25 )
  1530. return AxisPosition.Right;
  1531. else if(axisAngle >= 25 )
  1532. return AxisPosition.Left;
  1533. }
  1534. else if(axis.AxisPosition == AxisPosition.Top)
  1535. {
  1536. if(axisAngle <= -25 )
  1537. return AxisPosition.Left;
  1538. else if(axisAngle >= 25 )
  1539. return AxisPosition.Right;
  1540. }
  1541. // Labels are on the same side as the axis
  1542. return axis.AxisPosition;
  1543. }
  1544. /// <summary>
  1545. /// Draws axis labels in 3D space.
  1546. /// </summary>
  1547. /// <param name="graph">Reference to the Chart Graphics object.</param>
  1548. /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
  1549. internal void Paint3D( ChartGraphics graph, bool backElements )
  1550. {
  1551. // Label string drawing format
  1552. using (StringFormat format = new StringFormat())
  1553. {
  1554. format.Trimming = StringTrimming.EllipsisCharacter;
  1555. // Calculate single pixel size in relative coordinates
  1556. SizeF pixelSize = graph.GetRelativeSize(new SizeF(1f, 1f));
  1557. //********************************************************************
  1558. //** Determine the side of the plotting area to draw the labels on.
  1559. //********************************************************************
  1560. AxisPosition labelsPosition = GetLabelsPosition(_axis);
  1561. //*****************************************************************
  1562. //** Set the labels Z position
  1563. //*****************************************************************
  1564. bool axisOnEdge;
  1565. float labelsZPosition = _axis.GetMarksZPosition(out axisOnEdge);
  1566. // Adjust Z position for the "bent" tick marks
  1567. bool adjustForWallWidth = false;
  1568. if (this._axis.AxisPosition == AxisPosition.Top &&
  1569. !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Top, backElements, false))
  1570. {
  1571. adjustForWallWidth = true;
  1572. }
  1573. if (this._axis.AxisPosition == AxisPosition.Left &&
  1574. !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Left, backElements, false))
  1575. {
  1576. adjustForWallWidth = true;
  1577. }
  1578. if (this._axis.AxisPosition == AxisPosition.Right &&
  1579. !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Right, backElements, false))
  1580. {
  1581. adjustForWallWidth = true;
  1582. }
  1583. if (adjustForWallWidth && this._axis.ChartArea.Area3DStyle.WallWidth > 0)
  1584. {
  1585. if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
  1586. {
  1587. labelsZPosition -= this._axis.ChartArea.areaSceneWallWidth.Width;
  1588. }
  1589. else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
  1590. {
  1591. labelsZPosition -= this._axis.MajorTickMark.Size + this._axis.ChartArea.areaSceneWallWidth.Width;
  1592. }
  1593. else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
  1594. {
  1595. labelsZPosition -= this._axis.MajorTickMark.Size / 2f + this._axis.ChartArea.areaSceneWallWidth.Width;
  1596. }
  1597. }
  1598. //*****************************************************************
  1599. //** Check if labels should be drawn as back or front element.
  1600. //*****************************************************************
  1601. bool labelsInsidePlotArea = (this._axis.GetIsMarksNextToAxis() && !axisOnEdge);
  1602. if (backElements == labelsInsidePlotArea)
  1603. {
  1604. // Skip drawing
  1605. return;
  1606. }
  1607. //********************************************************************
  1608. //** Initialize all labels position rectangle
  1609. //********************************************************************
  1610. RectangleF rectLabels = this.GetAllLabelsRect(this._axis.ChartArea, this._axis.AxisPosition, format);
  1611. //********************************************************************
  1612. //** Calculate bounding rectangle used to truncate labels on the
  1613. //** chart area boundary if TruncatedLabels property is set to true.
  1614. //********************************************************************
  1615. RectangleF boundaryRect = rectLabels;
  1616. if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
  1617. {
  1618. if (this._axis.AxisPosition == AxisPosition.Left)
  1619. {
  1620. boundaryRect.X += _axis.totlaGroupingLabelsSize;
  1621. boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
  1622. }
  1623. else if (this._axis.AxisPosition == AxisPosition.Right)
  1624. {
  1625. boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
  1626. }
  1627. else if (this._axis.AxisPosition == AxisPosition.Top)
  1628. {
  1629. boundaryRect.Y += _axis.totlaGroupingLabelsSize;
  1630. boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
  1631. }
  1632. else if (this._axis.AxisPosition == AxisPosition.Bottom)
  1633. {
  1634. boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
  1635. }
  1636. }
  1637. // Pre-calculated height of the first labels row
  1638. float firstLabelsRowHeight = -1f;
  1639. // For 3D axis labels the first row of labels
  1640. // has to be drawn after all other rows because
  1641. // of hot regions.
  1642. for (int selectionRow = 0; selectionRow <= this._axis.GetGroupLabelLevelCount(); selectionRow++)
  1643. {
  1644. //********************************************************************
  1645. //** Draw all labels from the collection
  1646. //********************************************************************
  1647. int labelIndex = 0;
  1648. foreach (CustomLabel label in this._axis.CustomLabels)
  1649. {
  1650. bool truncatedLeft = false;
  1651. bool truncatedRight = false;
  1652. double labelFrom = label.FromPosition;
  1653. double labelTo = label.ToPosition;
  1654. if (label.RowIndex != selectionRow)
  1655. {
  1656. continue;
  1657. }
  1658. // Skip if label middle point is outside current scaleView
  1659. if (label.RowIndex == 0)
  1660. {
  1661. double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
  1662. if ((decimal)middlePoint < (decimal)_axis.ViewMinimum ||
  1663. (decimal)middlePoint > (decimal)_axis.ViewMaximum)
  1664. {
  1665. continue;
  1666. }
  1667. }
  1668. else
  1669. {
  1670. // Skip labels completly outside the scaleView
  1671. if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
  1672. {
  1673. continue;
  1674. }
  1675. // Check if label is partially visible
  1676. if (_axis.ScaleView.IsZoomed)
  1677. {
  1678. if (label.FromPosition < _axis.ViewMinimum)
  1679. {
  1680. truncatedLeft = true;
  1681. labelFrom = _axis.ViewMinimum;
  1682. }
  1683. if (label.ToPosition > _axis.ViewMaximum)
  1684. {
  1685. truncatedRight = true;
  1686. labelTo = _axis.ViewMaximum;
  1687. }
  1688. }
  1689. }
  1690. // Calculate single label position
  1691. RectangleF rect = rectLabels;
  1692. // Label is in the first row
  1693. if (label.RowIndex == 0)
  1694. {
  1695. if (this._axis.AxisPosition == AxisPosition.Left)
  1696. {
  1697. if (!this._axis.GetIsMarksNextToAxis())
  1698. {
  1699. rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
  1700. rect.Width = _axis.unRotatedLabelSize;
  1701. }
  1702. // Adjust label rectangle if offset labels are used
  1703. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1704. {
  1705. rect.Width /= 2F;
  1706. if (labelIndex % 2 != 0F)
  1707. {
  1708. rect.X += rect.Width;
  1709. }
  1710. }
  1711. }
  1712. else if (this._axis.AxisPosition == AxisPosition.Right)
  1713. {
  1714. if (!this._axis.GetIsMarksNextToAxis())
  1715. {
  1716. rect.Width = _axis.unRotatedLabelSize;
  1717. }
  1718. // Adjust label rectangle if offset labels are used
  1719. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1720. {
  1721. rect.Width /= 2F;
  1722. if (labelIndex % 2 != 0F)
  1723. {
  1724. rect.X += rect.Width;
  1725. }
  1726. }
  1727. }
  1728. else if (this._axis.AxisPosition == AxisPosition.Top)
  1729. {
  1730. if (!this._axis.GetIsMarksNextToAxis())
  1731. {
  1732. rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
  1733. rect.Height = _axis.unRotatedLabelSize;
  1734. }
  1735. // Adjust label rectangle if offset labels are used
  1736. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1737. {
  1738. rect.Height /= 2F;
  1739. if (labelIndex % 2 != 0F)
  1740. {
  1741. rect.Y += rect.Height;
  1742. }
  1743. }
  1744. }
  1745. else if (this._axis.AxisPosition == AxisPosition.Bottom)
  1746. {
  1747. if (!this._axis.GetIsMarksNextToAxis())
  1748. {
  1749. rect.Height = _axis.unRotatedLabelSize;
  1750. }
  1751. // Adjust label rectangle if offset labels are used
  1752. if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
  1753. {
  1754. rect.Height /= 2F;
  1755. if (labelIndex % 2 != 0F)
  1756. {
  1757. rect.Y += rect.Height;
  1758. }
  1759. }
  1760. }
  1761. // Increase label index
  1762. ++labelIndex;
  1763. }
  1764. // Label is in the second row
  1765. else if (label.RowIndex > 0)
  1766. {
  1767. // Hide grouping labels (where index of row > 0) when they are displayed
  1768. // not on the same side as their axis. Fixes MS issue #64.
  1769. if (labelsPosition != this._axis.AxisPosition)
  1770. {
  1771. continue;
  1772. }
  1773. if (_axis.AxisPosition == AxisPosition.Left)
  1774. {
  1775. rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
  1776. for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
  1777. {
  1778. rect.X += _axis.groupingLabelSizes[index - 1];
  1779. }
  1780. rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
  1781. }
  1782. else if (_axis.AxisPosition == AxisPosition.Right)
  1783. {
  1784. rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
  1785. for (int index = 1; index < label.RowIndex; index++)
  1786. {
  1787. rect.X += _axis.groupingLabelSizes[index - 1];
  1788. }
  1789. rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
  1790. }
  1791. else if (_axis.AxisPosition == AxisPosition.Top)
  1792. {
  1793. rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
  1794. for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
  1795. {
  1796. rect.Y += _axis.groupingLabelSizes[index - 1];
  1797. }
  1798. rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
  1799. }
  1800. if (_axis.AxisPosition == AxisPosition.Bottom)
  1801. {
  1802. rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
  1803. for (int index = 1; index < label.RowIndex; index++)
  1804. {
  1805. rect.Y += _axis.groupingLabelSizes[index - 1];
  1806. }
  1807. rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
  1808. }
  1809. }
  1810. // Unknown label row value
  1811. else
  1812. {
  1813. throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexMustBe1Or2));
  1814. }
  1815. //********************************************************************
  1816. //** Set label From and To coordinates.
  1817. //********************************************************************
  1818. double fromPosition = _axis.GetLinearPosition(labelFrom);
  1819. double toPosition = _axis.GetLinearPosition(labelTo);
  1820. if (this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom)
  1821. {
  1822. rect.X = (float)Math.Min(fromPosition, toPosition);
  1823. rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
  1824. if (rect.Width < pixelSize.Width)
  1825. {
  1826. rect.Width = pixelSize.Width;
  1827. }
  1828. // Adjust label To/From position if offset labels are used
  1829. if (label.RowIndex == 0 &&
  1830. ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
  1831. {
  1832. rect.X -= rect.Width / 2F;
  1833. rect.Width *= 2F;
  1834. }
  1835. }
  1836. else
  1837. {
  1838. rect.Y = (float)Math.Min(fromPosition, toPosition);
  1839. rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
  1840. if (rect.Height < pixelSize.Height)
  1841. {
  1842. rect.Height = pixelSize.Height;
  1843. }
  1844. // Adjust label To/From position if offset labels are used
  1845. if (label.RowIndex == 0 &&
  1846. ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
  1847. {
  1848. rect.Y -= rect.Height / 2F;
  1849. rect.Height *= 2F;
  1850. }
  1851. }
  1852. // Save original rect
  1853. RectangleF initialRect = new RectangleF(rect.Location, rect.Size);
  1854. //********************************************************************
  1855. //** Transform and adjust label rectangle coordinates in 3D space.
  1856. //********************************************************************
  1857. Point3D[] rectPoints = new Point3D[3];
  1858. if (this._axis.AxisPosition == AxisPosition.Left)
  1859. {
  1860. rectPoints[0] = new Point3D(rect.Right, rect.Y, labelsZPosition);
  1861. rectPoints[1] = new Point3D(rect.Right, rect.Y + rect.Height / 2f, labelsZPosition);
  1862. rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
  1863. this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
  1864. rect.Y = rectPoints[0].Y;
  1865. rect.Height = rectPoints[2].Y - rect.Y;
  1866. rect.Width = rectPoints[1].X - rect.X;
  1867. }
  1868. else if (this._axis.AxisPosition == AxisPosition.Right)
  1869. {
  1870. rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
  1871. rectPoints[1] = new Point3D(rect.X, rect.Y + rect.Height / 2f, labelsZPosition);
  1872. rectPoints[2] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
  1873. this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
  1874. rect.Y = rectPoints[0].Y;
  1875. rect.Height = rectPoints[2].Y - rect.Y;
  1876. rect.Width = rect.Right - rectPoints[1].X;
  1877. rect.X = rectPoints[1].X;
  1878. }
  1879. else if (this._axis.AxisPosition == AxisPosition.Top)
  1880. {
  1881. // Transform 3 points of the rectangle
  1882. rectPoints[0] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
  1883. rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Bottom, labelsZPosition);
  1884. rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
  1885. this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
  1886. if (labelsPosition == AxisPosition.Top)
  1887. {
  1888. rect.X = rectPoints[0].X;
  1889. rect.Width = rectPoints[2].X - rect.X;
  1890. rect.Height = rectPoints[1].Y - rect.Y;
  1891. }
  1892. else if (labelsPosition == AxisPosition.Right)
  1893. {
  1894. RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
  1895. rect.Y = rectPoints[0].Y;
  1896. rect.Height = rectPoints[2].Y - rect.Y;
  1897. rect.X = rectPoints[1].X;
  1898. rect.Width = rightLabelsRect.Right - rect.X;
  1899. }
  1900. else if (labelsPosition == AxisPosition.Left)
  1901. {
  1902. RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
  1903. rect.Y = rectPoints[2].Y;
  1904. rect.Height = rectPoints[0].Y - rect.Y;
  1905. rect.X = rightLabelsRect.X;
  1906. rect.Width = rectPoints[1].X - rightLabelsRect.X;
  1907. }
  1908. }
  1909. else if (this._axis.AxisPosition == AxisPosition.Bottom)
  1910. {
  1911. // Transform 3 points of the rectangle
  1912. rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
  1913. rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Y, labelsZPosition);
  1914. rectPoints[2] = new Point3D(rect.Right, rect.Y, labelsZPosition);
  1915. this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
  1916. if (labelsPosition == AxisPosition.Bottom)
  1917. {
  1918. rect.X = rectPoints[0].X;
  1919. rect.Width = rectPoints[2].X - rect.X;
  1920. rect.Height = rect.Bottom - rectPoints[1].Y;
  1921. rect.Y = rectPoints[1].Y;
  1922. }
  1923. else if (labelsPosition == AxisPosition.Right)
  1924. {
  1925. RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
  1926. rect.Y = rectPoints[2].Y;
  1927. rect.Height = rectPoints[0].Y - rect.Y;
  1928. rect.X = rectPoints[1].X;
  1929. rect.Width = rightLabelsRect.Right - rect.X;
  1930. // Adjust label rect by shifting it down by quarter of the tick size
  1931. if (this._axis.autoLabelAngle == 0)
  1932. {
  1933. rect.Y += this._axis.markSize / 4f;
  1934. }
  1935. }
  1936. else if (labelsPosition == AxisPosition.Left)
  1937. {
  1938. RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
  1939. rect.Y = rectPoints[0].Y;
  1940. rect.Height = rectPoints[2].Y - rect.Y;
  1941. rect.X = rightLabelsRect.X;
  1942. rect.Width = rectPoints[1].X - rightLabelsRect.X;
  1943. // Adjust label rect by shifting it down by quarter of the tick size
  1944. if (this._axis.autoLabelAngle == 0)
  1945. {
  1946. rect.Y += this._axis.markSize / 4f;
  1947. }
  1948. }
  1949. }
  1950. // Find axis with same position
  1951. Axis labelsAxis = null;
  1952. foreach (Axis curAxis in this._axis.ChartArea.Axes)
  1953. {
  1954. if (curAxis.AxisPosition == labelsPosition)
  1955. {
  1956. labelsAxis = curAxis;
  1957. break;
  1958. }
  1959. }
  1960. //********************************************************************
  1961. //** Adjust font angles for Top and Bottom axis
  1962. //********************************************************************
  1963. int labelsFontAngle = (_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle;
  1964. if (labelsPosition != this._axis.AxisPosition)
  1965. {
  1966. if ((this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom) &&
  1967. (labelsFontAngle == 90 || labelsFontAngle == -90))
  1968. {
  1969. labelsFontAngle = 0;
  1970. }
  1971. else if (this._axis.AxisPosition == AxisPosition.Bottom)
  1972. {
  1973. if (labelsPosition == AxisPosition.Left && labelsFontAngle > 0)
  1974. {
  1975. labelsFontAngle = -labelsFontAngle;
  1976. }
  1977. else if (labelsPosition == AxisPosition.Right && labelsFontAngle < 0)
  1978. {
  1979. labelsFontAngle = -labelsFontAngle;
  1980. }
  1981. }
  1982. else if (this._axis.AxisPosition == AxisPosition.Top)
  1983. {
  1984. if (labelsPosition == AxisPosition.Left && labelsFontAngle < 0)
  1985. {
  1986. labelsFontAngle = -labelsFontAngle;
  1987. }
  1988. else if (labelsPosition == AxisPosition.Right && labelsFontAngle > 0)
  1989. {
  1990. labelsFontAngle = -labelsFontAngle;
  1991. }
  1992. }
  1993. }
  1994. //********************************************************************
  1995. //** NOTE: Code below improves chart labels readability in scenarios
  1996. //** described in MS issue #65.
  1997. //**
  1998. //** Prevent labels in the first row from overlapping the grouping
  1999. //** labels in the rows below. The solution only apply to the limited
  2000. //** use cases defined by the condition below.
  2001. //********************************************************************
  2002. StringFormatFlags oldFormatFlags = format.FormatFlags;
  2003. if (label.RowIndex == 0 &&
  2004. labelsFontAngle == 0 &&
  2005. _axis.groupingLabelSizes != null &&
  2006. _axis.groupingLabelSizes.Length > 0 &&
  2007. this._axis.AxisPosition == AxisPosition.Bottom &&
  2008. labelsPosition == AxisPosition.Bottom &&
  2009. !((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
  2010. {
  2011. if (firstLabelsRowHeight == -1f)
  2012. {
  2013. // Calculate first labels row max height
  2014. Point3D[] labelPositionPoints = new Point3D[1];
  2015. labelPositionPoints[0] = new Point3D(initialRect.X, initialRect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment, labelsZPosition);
  2016. this._axis.ChartArea.matrix3D.TransformPoints(labelPositionPoints);
  2017. float height = labelPositionPoints[0].Y - rect.Y;
  2018. firstLabelsRowHeight = (height > 0f) ? height : rect.Height;
  2019. }
  2020. // Resuse pre-calculated first labels row height
  2021. rect.Height = firstLabelsRowHeight;
  2022. // Change current string format to prevent strings to go out of the
  2023. // specified bounding rectangle
  2024. if ((format.FormatFlags & StringFormatFlags.LineLimit) == 0)
  2025. {
  2026. format.FormatFlags |= StringFormatFlags.LineLimit;
  2027. }
  2028. }
  2029. //********************************************************************
  2030. //** Draw label text.
  2031. //********************************************************************
  2032. using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
  2033. {
  2034. graph.DrawLabelStringRel(
  2035. labelsAxis,
  2036. label.RowIndex,
  2037. label.LabelMark,
  2038. label.MarkColor,
  2039. label.Text,
  2040. label.Image,
  2041. label.ImageTransparentColor,
  2042. (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
  2043. brush,
  2044. rect,
  2045. format,
  2046. labelsFontAngle,
  2047. (!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
  2048. label,
  2049. truncatedLeft,
  2050. truncatedRight);
  2051. }
  2052. // Restore old string format that was temporary modified
  2053. if (format.FormatFlags != oldFormatFlags)
  2054. {
  2055. format.FormatFlags = oldFormatFlags;
  2056. }
  2057. }
  2058. }
  2059. }
  2060. }
  2061. #endregion
  2062. #region Helper methods
  2063. /// <summary>
  2064. /// Sets the axis to which this object attached to.
  2065. /// </summary>
  2066. /// <returns>Axis object.</returns>
  2067. internal Axis Axis
  2068. {
  2069. set { _axis = value; }
  2070. }
  2071. /// <summary>
  2072. /// Invalidate chart picture
  2073. /// </summary>
  2074. internal override void Invalidate()
  2075. {
  2076. if(this._axis != null)
  2077. {
  2078. this._axis.Invalidate();
  2079. }
  2080. base.Invalidate();
  2081. }
  2082. #endregion
  2083. #region Label properties
  2084. /// <summary>
  2085. /// Gets or sets the interval offset of the label.
  2086. /// </summary>
  2087. [
  2088. SRCategory("CategoryAttributeData"),
  2089. Bindable(true),
  2090. SRDescription("DescriptionAttributeLabel_IntervalOffset"),
  2091. DefaultValue(Double.NaN),
  2092. RefreshPropertiesAttribute(RefreshProperties.All),
  2093. TypeConverter(typeof(AxisElementIntervalValueConverter))
  2094. ]
  2095. public double IntervalOffset
  2096. {
  2097. get
  2098. {
  2099. return intervalOffset;
  2100. }
  2101. set
  2102. {
  2103. intervalOffset = value;
  2104. this.Invalidate();
  2105. CallOnModifing();
  2106. }
  2107. }
  2108. /// <summary>
  2109. /// Gets the interval offset.
  2110. /// </summary>
  2111. /// <returns></returns>
  2112. internal double GetIntervalOffset()
  2113. {
  2114. if(double.IsNaN(intervalOffset) && this._axis != null)
  2115. {
  2116. return this._axis.IntervalOffset;
  2117. }
  2118. return intervalOffset;
  2119. }
  2120. /// <summary>
  2121. /// Gets or sets the unit of measurement of the label offset.
  2122. /// </summary>
  2123. [
  2124. SRCategory("CategoryAttributeData"),
  2125. Bindable(true),
  2126. DefaultValue(DateTimeIntervalType.NotSet),
  2127. SRDescription("DescriptionAttributeLabel_IntervalOffsetType"),
  2128. RefreshPropertiesAttribute(RefreshProperties.All),
  2129. ]
  2130. public DateTimeIntervalType IntervalOffsetType
  2131. {
  2132. get
  2133. {
  2134. return intervalOffsetType;
  2135. }
  2136. set
  2137. {
  2138. intervalOffsetType = value;
  2139. this.Invalidate();
  2140. CallOnModifing();
  2141. }
  2142. }
  2143. /// <summary>
  2144. /// Gets the type of the interval offset.
  2145. /// </summary>
  2146. /// <returns></returns>
  2147. internal DateTimeIntervalType GetIntervalOffsetType()
  2148. {
  2149. if(intervalOffsetType == DateTimeIntervalType.NotSet && this._axis != null)
  2150. {
  2151. return this._axis.IntervalOffsetType;
  2152. }
  2153. return intervalOffsetType;
  2154. }
  2155. /// <summary>
  2156. /// Gets or sets the interval size of the label.
  2157. /// </summary>
  2158. [
  2159. SRCategory("CategoryAttributeData"),
  2160. Bindable(true),
  2161. DefaultValue(Double.NaN),
  2162. SRDescription("DescriptionAttributeLabel_Interval"),
  2163. TypeConverter(typeof(AxisElementIntervalValueConverter)),
  2164. ]
  2165. public double Interval
  2166. {
  2167. get
  2168. {
  2169. return interval;
  2170. }
  2171. set
  2172. {
  2173. interval = value;
  2174. // Reset original property value fields
  2175. if (this._axis != null)
  2176. {
  2177. this._axis.tempLabelInterval = interval;
  2178. }
  2179. this.Invalidate();
  2180. CallOnModifing();
  2181. }
  2182. }
  2183. /// <summary>
  2184. /// Gets the interval.
  2185. /// </summary>
  2186. /// <returns></returns>
  2187. internal double GetInterval()
  2188. {
  2189. if(double.IsNaN(interval) && this._axis != null)
  2190. {
  2191. return this._axis.Interval;
  2192. }
  2193. return interval;
  2194. }
  2195. /// <summary>
  2196. /// Gets or sets the unit of measurement of the interval size of the label.
  2197. /// </summary>
  2198. [
  2199. SRCategory("CategoryAttributeData"),
  2200. Bindable(true),
  2201. DefaultValue(DateTimeIntervalType.NotSet),
  2202. SRDescription("DescriptionAttributeLabel_IntervalType"),
  2203. RefreshPropertiesAttribute(RefreshProperties.All)
  2204. ]
  2205. public DateTimeIntervalType IntervalType
  2206. {
  2207. get
  2208. {
  2209. return intervalType;
  2210. }
  2211. set
  2212. {
  2213. intervalType = value;
  2214. // Reset original property value fields
  2215. if (this._axis != null)
  2216. {
  2217. this._axis.tempLabelIntervalType = intervalType;
  2218. }
  2219. this.Invalidate();
  2220. CallOnModifing();
  2221. }
  2222. }
  2223. /// <summary>
  2224. /// Gets the type of the interval.
  2225. /// </summary>
  2226. /// <returns></returns>
  2227. internal DateTimeIntervalType GetIntervalType()
  2228. {
  2229. if(intervalType == DateTimeIntervalType.NotSet && this._axis != null)
  2230. {
  2231. return this._axis.IntervalType;
  2232. }
  2233. return intervalType;
  2234. }
  2235. /// <summary>
  2236. /// Gets or sets the font of the label.
  2237. /// </summary>
  2238. [
  2239. SRCategory("CategoryAttributeAppearance"),
  2240. Bindable(true),
  2241. DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
  2242. SRDescription("DescriptionAttributeLabel_Font")
  2243. ]
  2244. public Font Font
  2245. {
  2246. get
  2247. {
  2248. return _font;
  2249. }
  2250. set
  2251. {
  2252. // Turn off labels autofitting
  2253. if (this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
  2254. {
  2255. if(!this._axis.Common.Chart.serializing)
  2256. {
  2257. this._axis.IsLabelAutoFit = false;
  2258. }
  2259. }
  2260. _font = value;
  2261. this.Invalidate();
  2262. CallOnModifing();
  2263. }
  2264. }
  2265. /// <summary>
  2266. /// Gets or sets the fore color of the label.
  2267. /// </summary>
  2268. [
  2269. SRCategory("CategoryAttributeAppearance"),
  2270. Bindable(true),
  2271. DefaultValue(typeof(Color), "Black"),
  2272. SRDescription("DescriptionAttributeFontColor"),
  2273. NotifyParentPropertyAttribute(true),
  2274. TypeConverter(typeof(ColorConverter)),
  2275. #if DESIGNER
  2276. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  2277. #endif
  2278. ]
  2279. public Color ForeColor
  2280. {
  2281. get
  2282. {
  2283. return _foreColor;
  2284. }
  2285. set
  2286. {
  2287. _foreColor = value;
  2288. this.Invalidate();
  2289. CallOnModifing();
  2290. }
  2291. }
  2292. /// <summary>
  2293. /// Gets or sets a value that represents the angle at which font is drawn.
  2294. /// </summary>
  2295. [
  2296. SRCategory("CategoryAttributeAppearance"),
  2297. Bindable(true),
  2298. DefaultValue(0),
  2299. SRDescription("DescriptionAttributeLabel_FontAngle"),
  2300. RefreshPropertiesAttribute(RefreshProperties.All)
  2301. ]
  2302. public int Angle
  2303. {
  2304. get
  2305. {
  2306. return angle;
  2307. }
  2308. set
  2309. {
  2310. if(value < -90 || value > 90)
  2311. {
  2312. throw (new ArgumentOutOfRangeException("value", SR.ExceptionAxisLabelFontAngleInvalid));
  2313. }
  2314. // Turn of label offset if angle is not 0, 90 or -90
  2315. if(IsStaggered && value != 0 && value != -90 && value != 90)
  2316. {
  2317. IsStaggered = false;
  2318. }
  2319. // Turn off labels autofitting
  2320. if(this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
  2321. {
  2322. if (!this._axis.Common.Chart.serializing)
  2323. {
  2324. this._axis.IsLabelAutoFit = false;
  2325. }
  2326. }
  2327. angle = value;
  2328. this.Invalidate();
  2329. CallOnModifing();
  2330. }
  2331. }
  2332. /// <summary>
  2333. /// Gets or sets a property which specifies whether the labels are shown with offset.
  2334. /// </summary>
  2335. [
  2336. SRCategory("CategoryAttributeAppearance"),
  2337. Bindable(true),
  2338. DefaultValue(false),
  2339. SRDescription("DescriptionAttributeLabel_OffsetLabels"),
  2340. RefreshPropertiesAttribute(RefreshProperties.All)
  2341. ]
  2342. public bool IsStaggered
  2343. {
  2344. get
  2345. {
  2346. return isStaggered;
  2347. }
  2348. set
  2349. {
  2350. // Make sure that angle is 0, 90 or -90
  2351. if(value && (this.Angle != 0 || this.Angle != -90 || this.Angle != 90))
  2352. {
  2353. this.Angle = 0;
  2354. }
  2355. // Turn off labels autofitting
  2356. if (this._axis != null && this._axis.Common != null && this._axis.Common.Chart != null)
  2357. {
  2358. if (!this._axis.Common.Chart.serializing)
  2359. {
  2360. this._axis.IsLabelAutoFit = false;
  2361. }
  2362. }
  2363. isStaggered = value;
  2364. this.Invalidate();
  2365. CallOnModifing();
  2366. }
  2367. }
  2368. /// <summary>
  2369. /// Gets or sets a property which specifies whether the labels are shown at axis ends.
  2370. /// </summary>
  2371. [
  2372. SRCategory("CategoryAttributeAppearance"),
  2373. Bindable(true),
  2374. DefaultValue(true),
  2375. SRDescription("DescriptionAttributeLabel_ShowEndLabels"),
  2376. ]
  2377. public bool IsEndLabelVisible
  2378. {
  2379. get
  2380. {
  2381. return _isEndLabelVisible;
  2382. }
  2383. set
  2384. {
  2385. _isEndLabelVisible = value;
  2386. this.Invalidate();
  2387. CallOnModifing();
  2388. }
  2389. }
  2390. /// <summary>
  2391. /// Gets or sets a property which specifies whether the label can be truncated.
  2392. /// </summary>
  2393. [
  2394. SRCategory("CategoryAttributeAppearance"),
  2395. Bindable(true),
  2396. DefaultValue(false),
  2397. SRDescription("DescriptionAttributeLabel_TruncatedLabels"),
  2398. ]
  2399. public bool TruncatedLabels
  2400. {
  2401. get
  2402. {
  2403. return _truncatedLabels;
  2404. }
  2405. set
  2406. {
  2407. _truncatedLabels = value;
  2408. this.Invalidate();
  2409. CallOnModifing();
  2410. }
  2411. }
  2412. /// <summary>
  2413. /// Gets or sets the formatting string for the label text.
  2414. /// </summary>
  2415. [
  2416. SRCategory("CategoryAttributeAppearance"),
  2417. Bindable(true),
  2418. DefaultValue(""),
  2419. SRDescription("DescriptionAttributeLabel_Format"),
  2420. ]
  2421. public string Format
  2422. {
  2423. get
  2424. {
  2425. return _format;
  2426. }
  2427. set
  2428. {
  2429. _format = value;
  2430. this.Invalidate();
  2431. CallOnModifing();
  2432. }
  2433. }
  2434. /// <summary>
  2435. /// Gets or sets a property which indicates whether the label is enabled.
  2436. /// </summary>
  2437. [
  2438. SRCategory("CategoryAttributeAppearance"),
  2439. Bindable(true),
  2440. DefaultValue(true),
  2441. SRDescription("DescriptionAttributeLabel_Enabled"),
  2442. ]
  2443. public bool Enabled
  2444. {
  2445. get
  2446. {
  2447. return _enabled;
  2448. }
  2449. set
  2450. {
  2451. _enabled = value;
  2452. this.Invalidate();
  2453. CallOnModifing();
  2454. }
  2455. }
  2456. #endregion
  2457. #region IDisposable Members
  2458. /// <summary>
  2459. /// Releases unmanaged and - optionally - managed resources
  2460. /// </summary>
  2461. /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  2462. protected override void Dispose(bool disposing)
  2463. {
  2464. if (disposing)
  2465. {
  2466. //Free managed resources
  2467. if (_fontCache!=null)
  2468. {
  2469. _fontCache.Dispose();
  2470. _fontCache = null;
  2471. }
  2472. }
  2473. }
  2474. #endregion
  2475. }
  2476. }