GridTickMarks.cs 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979
  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: Axis tick marks and grid lines a very similar chart
  6. // elements and most of the functionality is located
  7. // in the Grid class. TickMark class is derived from
  8. // the Grid class and provides tick mark specific
  9. // functionality.
  10. //
  11. using System;
  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. namespace FastReport.DataVisualization.Charting
  19. {
  20. #region Tick marks style enumeration
  21. /// <summary>
  22. /// An enumeration of tick mark styles.
  23. /// </summary>
  24. public enum TickMarkStyle
  25. {
  26. /// <summary>
  27. /// Tickmarks are disabled.
  28. /// </summary>
  29. None,
  30. /// <summary>
  31. /// Tickmarks are located outside of the chart area.
  32. /// </summary>
  33. OutsideArea,
  34. /// <summary>
  35. /// Tickmarks are located inside of the chart area.
  36. /// </summary>
  37. InsideArea,
  38. /// <summary>
  39. /// Tickmarks are set across the axis line.
  40. /// </summary>
  41. AcrossAxis
  42. };
  43. #endregion
  44. /// <summary>
  45. /// The TickMark class represents axis tick marks which are drawn next to
  46. /// the axis line. TickMark shares many common properties with the Grid
  47. /// class. This class also contains methods for tick marks drawing.
  48. /// </summary>
  49. [
  50. DefaultProperty("Enabled"),
  51. SRDescription("DescriptionAttributeTickMark_TickMark"),
  52. ]
  53. public class TickMark : Grid
  54. {
  55. #region Private fields and Constructors
  56. // Tick marks style
  57. private TickMarkStyle _style = TickMarkStyle.OutsideArea;
  58. // Tick marks size
  59. private float _size = 1;
  60. /// <summary>
  61. /// Public default constructor
  62. /// </summary>
  63. public TickMark() : base(null, true)
  64. {
  65. }
  66. /// <summary>
  67. /// Public constructor
  68. /// </summary>
  69. /// <param name="axis">Axis which owns the grid or tick mark.</param>
  70. /// <param name="major">Major axis element.</param>
  71. internal TickMark(Axis axis, bool major) : base(axis, major)
  72. {
  73. }
  74. #endregion
  75. #region Tick marks painting method
  76. /// <summary>
  77. /// Draws and hit test for TickMarks.
  78. /// </summary>
  79. /// <param name="graph">Reference to the Chart Graphics object.</param>
  80. /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
  81. internal void Paint( ChartGraphics graph, bool backElements )
  82. {
  83. PointF first = PointF.Empty; // The First point of a tick mark
  84. PointF second = PointF.Empty; // The Second point of a tick mark
  85. float axisPosition; // Axis position.
  86. // Tick Marks are disabled
  87. if( !this.enabled )
  88. {
  89. return;
  90. }
  91. // ****************************************************************
  92. // This code creates auto interval for auto tick marks and
  93. // gridlines. If type is not date there are always four tickmarks
  94. // or gridlines between major gridlines and tickmarks. For date
  95. // type interval is calculated using CalcInterval function.
  96. // ****************************************************************
  97. double oldInterval = this.interval;
  98. DateTimeIntervalType oldIntervalType = this.intervalType;
  99. double oldIntervalOffset = this.intervalOffset;
  100. DateTimeIntervalType oldIntervalOffsetType = this.intervalOffsetType;
  101. if( !this.majorGridTick && ( this.interval == 0 || double.IsNaN(this.interval) ) )
  102. {
  103. // Number type
  104. if (this.Axis.majorGrid.GetIntervalType() == DateTimeIntervalType.Auto)
  105. {
  106. this.interval = this.Axis.majorGrid.GetInterval() / Grid.NumberOfIntervals;
  107. }
  108. // Date type
  109. else
  110. {
  111. DateTimeIntervalType localIntervalType = this.Axis.majorGrid.GetIntervalType();
  112. this.interval = Axis.CalcInterval(
  113. this.Axis.ViewMinimum,
  114. this.Axis.ViewMinimum + (this.Axis.ViewMaximum - this.Axis.ViewMinimum) / Grid.NumberOfDateTimeIntervals,
  115. true,
  116. out localIntervalType,
  117. ChartValueType.DateTime );
  118. this.intervalType = localIntervalType;
  119. this.intervalOffsetType = this.Axis.majorGrid.GetIntervalOffsetType();
  120. this.intervalOffset = this.Axis.majorGrid.GetIntervalOffset();
  121. }
  122. }
  123. if( _style == TickMarkStyle.None )
  124. {
  125. return;
  126. }
  127. // Check if custom tick marks should be drawn from custom labels
  128. if (Axis.IsCustomTickMarks())
  129. {
  130. PaintCustom(graph, backElements);
  131. return;
  132. }
  133. // Get first series attached to this axis
  134. Series axisSeries = null;
  135. if (Axis.axisType == AxisName.X || Axis.axisType == AxisName.X2)
  136. {
  137. List<string> seriesArray = Axis.ChartArea.GetXAxesSeries((Axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, Axis.SubAxisName);
  138. if(seriesArray.Count > 0)
  139. {
  140. axisSeries = Axis.Common.DataManager.Series[seriesArray[0]];
  141. if(axisSeries != null && !axisSeries.IsXValueIndexed)
  142. {
  143. axisSeries = null;
  144. }
  145. }
  146. }
  147. // Current position for tick mark is minimum
  148. double current = Axis.ViewMinimum;
  149. // Get offse type
  150. DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
  151. // ***********************************
  152. // Check if the AJAX zooming and scrolling mode is enabled.
  153. // ***********************************
  154. // Adjust start position depending on the interval type
  155. if (!Axis.ChartArea.chartAreaIsCurcular ||
  156. Axis.axisType == AxisName.Y ||
  157. Axis.axisType == AxisName.Y2)
  158. {
  159. current = ChartHelper.AlignIntervalStart(current, this.GetInterval(), this.GetIntervalType(), axisSeries, this.majorGridTick);
  160. }
  161. // The Current position is start position, not minimum
  162. if (GetIntervalOffset() != 0 && !double.IsNaN(GetIntervalOffset()) && axisSeries == null)
  163. {
  164. current += ChartHelper.GetIntervalSize(current, GetIntervalOffset(),
  165. offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
  166. }
  167. // Too many tick marks
  168. if ((Axis.ViewMaximum - Axis.ViewMinimum) / ChartHelper.GetIntervalSize(current, this.GetInterval(), this.GetIntervalType(), axisSeries, 0, DateTimeIntervalType.Number, true) > ChartHelper.MaxNumOfGridlines)
  169. {
  170. return;
  171. }
  172. // If Maximum, minimum and interval don’t have
  173. // proper value do not draw tick marks.
  174. if (Axis.ViewMaximum <= Axis.ViewMinimum)
  175. {
  176. return;
  177. }
  178. // Axis scroll bar will increase size of the Outside and Cross style tick marks
  179. float scrollBarSize = 0;
  180. if (this.Axis.ScrollBar.IsVisible &&
  181. this.Axis.ScrollBar.IsPositionedInside &&
  182. (this.Axis.IsAxisOnAreaEdge || !this.Axis.IsMarksNextToAxis))
  183. {
  184. scrollBarSize = (float)this.Axis.ScrollBar.GetScrollBarRelativeSize();
  185. }
  186. // Left tickmarks
  187. if (Axis.AxisPosition == AxisPosition.Left)
  188. {
  189. // The tick marks will follow axis or they will
  190. // be always on the border of the chart area.
  191. if (Axis.GetIsMarksNextToAxis())
  192. axisPosition = (float)Axis.GetAxisPosition();
  193. else
  194. axisPosition = Axis.PlotAreaPosition.X;
  195. if( _style == TickMarkStyle.InsideArea )
  196. {
  197. first.X = axisPosition;
  198. second.X = axisPosition + _size;
  199. }
  200. else if( _style == TickMarkStyle.OutsideArea )
  201. {
  202. first.X = axisPosition - _size - scrollBarSize;
  203. second.X = axisPosition;
  204. }
  205. else if( _style == TickMarkStyle.AcrossAxis )
  206. {
  207. first.X = axisPosition - _size/2 - scrollBarSize;
  208. second.X = axisPosition + _size/2;
  209. }
  210. }
  211. // Right tickmarks
  212. else if (Axis.AxisPosition == AxisPosition.Right)
  213. {
  214. // The tick marks will follow axis or they will
  215. // be always on the border of the chart area.
  216. if (Axis.GetIsMarksNextToAxis())
  217. axisPosition = (float)Axis.GetAxisPosition();
  218. else
  219. axisPosition = Axis.PlotAreaPosition.Right;
  220. if( _style == TickMarkStyle.InsideArea )
  221. {
  222. first.X = axisPosition - _size;
  223. second.X = axisPosition;
  224. }
  225. else if( _style == TickMarkStyle.OutsideArea )
  226. {
  227. first.X = axisPosition;
  228. second.X = axisPosition + _size + scrollBarSize;
  229. }
  230. else if( _style == TickMarkStyle.AcrossAxis )
  231. {
  232. first.X = axisPosition - _size/2;
  233. second.X = axisPosition + _size/2 + scrollBarSize;
  234. }
  235. }
  236. // Top tickmarks
  237. else if (Axis.AxisPosition == AxisPosition.Top)
  238. {
  239. // The tick marks will follow axis or they will
  240. // be always on the border of the chart area.
  241. if (Axis.GetIsMarksNextToAxis())
  242. axisPosition = (float)Axis.GetAxisPosition();
  243. else
  244. axisPosition = Axis.PlotAreaPosition.Y;
  245. if( _style == TickMarkStyle.InsideArea )
  246. {
  247. first.Y = axisPosition;
  248. second.Y = axisPosition + _size;
  249. }
  250. else if( _style == TickMarkStyle.OutsideArea )
  251. {
  252. first.Y = axisPosition - _size - scrollBarSize;
  253. second.Y = axisPosition;
  254. }
  255. else if( _style == TickMarkStyle.AcrossAxis )
  256. {
  257. first.Y = axisPosition - _size/2 - scrollBarSize;
  258. second.Y = axisPosition + _size/2;
  259. }
  260. }
  261. // Bottom tickmarks
  262. else if (Axis.AxisPosition == AxisPosition.Bottom)
  263. {
  264. // The tick marks will follow axis or they will
  265. // be always on the border of the chart area.
  266. if (Axis.GetIsMarksNextToAxis())
  267. axisPosition = (float)Axis.GetAxisPosition();
  268. else
  269. axisPosition = Axis.PlotAreaPosition.Bottom;
  270. if( _style == TickMarkStyle.InsideArea )
  271. {
  272. first.Y = axisPosition - _size;
  273. second.Y = axisPosition;
  274. }
  275. else if( _style == TickMarkStyle.OutsideArea )
  276. {
  277. first.Y = axisPosition;
  278. second.Y = axisPosition + _size + scrollBarSize;
  279. }
  280. else if( _style == TickMarkStyle.AcrossAxis )
  281. {
  282. first.Y = axisPosition - _size/2;
  283. second.Y = axisPosition + _size/2 + scrollBarSize;
  284. }
  285. }
  286. // Loop for drawing grid tick marks
  287. int counter = 0;
  288. int logStep = 1;
  289. double oldCurrent = current;
  290. double interval = 0;
  291. while (current <= Axis.ViewMaximum)
  292. {
  293. double logInterval = 0;
  294. // Take an interval between gridlines. Interval
  295. // depends on interval type.
  296. if (this.majorGridTick || this.Axis.IsLogarithmic == false)
  297. {
  298. // Take an interval between tickmarks. Interval
  299. // depends on interval type.
  300. interval = ChartHelper.GetIntervalSize(current, this.GetInterval(), this.GetIntervalType(), axisSeries, this.GetIntervalOffset(), offsetType, true);
  301. }
  302. // Code for linear minor gridlines and tickmarks
  303. // if scale is logarithmic.
  304. else
  305. {
  306. // This code is used only for logarithmic scale and minor tick marks or
  307. // gridlines which have linear minor scale in logarithmic major scale.
  308. // This code is used to find minimum value for the interval. For example
  309. // if logarithmic base is 2 and interval is between 4 and 8; current value
  310. // is 5.6; this method will return linearised value for 4. This code works
  311. // like Math.Floor for logarithmic scale.
  312. double logMinimum = this.GetLogMinimum( current, axisSeries );
  313. if( oldCurrent != logMinimum )
  314. {
  315. oldCurrent = logMinimum;
  316. logStep = 1;
  317. }
  318. // Find interval for logarithmic linearised scale
  319. logInterval = Math.Log(1 + this.interval * logStep, Axis.logarithmBase);
  320. current = oldCurrent;
  321. interval = logInterval;
  322. logStep++;
  323. // Reset current position if major interval is passed.
  324. if( this.GetLogMinimum( current + logInterval, axisSeries ) != logMinimum )
  325. {
  326. current += logInterval;
  327. continue;
  328. }
  329. }
  330. // For indexed series do not draw the last tickmark
  331. if (current == Axis.ViewMaximum && axisSeries != null)
  332. {
  333. current += interval;
  334. continue;
  335. }
  336. // Check interval size
  337. if( interval == 0 )
  338. {
  339. throw (new InvalidOperationException(SR.ExceptionTickMarksIntervalIsZero));
  340. }
  341. // Check if we do not exceed max number of elements
  342. if (counter++ > ChartHelper.MaxNumOfGridlines)
  343. {
  344. break;
  345. }
  346. // Do not draw the very first tick mark for circular chart area
  347. if (this.Axis != null && this.Axis.ChartArea != null)
  348. {
  349. if (this.Axis.ChartArea.chartAreaIsCurcular &&
  350. ((this.Axis.IsReversed == false && current == Axis.ViewMinimum) ||
  351. (this.Axis.IsReversed == true && current == Axis.ViewMaximum)))
  352. {
  353. current += interval;
  354. continue;
  355. }
  356. }
  357. if (!this.majorGridTick && this.Axis.IsLogarithmic)
  358. {
  359. current += logInterval;
  360. if (current > Axis.ViewMaximum)
  361. {
  362. break;
  363. }
  364. }
  365. if ((decimal)current >= (decimal)Axis.ViewMinimum)
  366. {
  367. // Left tickmarks
  368. if (Axis.AxisPosition == AxisPosition.Left)
  369. {
  370. first.Y = (float)Axis.GetLinearPosition(current);
  371. second.Y = first.Y;
  372. }
  373. // Right tickmarks
  374. else if (Axis.AxisPosition == AxisPosition.Right)
  375. {
  376. first.Y = (float)Axis.GetLinearPosition(current);
  377. second.Y = first.Y;
  378. }
  379. // Top tickmarks
  380. else if (Axis.AxisPosition == AxisPosition.Top)
  381. {
  382. first.X = (float)Axis.GetLinearPosition(current);
  383. second.X = first.X;
  384. }
  385. // Bottom tickmarks
  386. else if (Axis.AxisPosition == AxisPosition.Bottom)
  387. {
  388. first.X = (float)Axis.GetLinearPosition(current);
  389. second.X = first.X;
  390. }
  391. if (Axis.Common.ProcessModeRegions)
  392. {
  393. if (this.Axis.ChartArea.chartAreaIsCurcular)
  394. {
  395. RectangleF rect = new RectangleF( first.X - 0.5f, first.Y - 0.5f, Math.Abs( second.X - first.X ) + 1, Math.Abs( second.Y - first.Y ) + 1 );
  396. using (GraphicsPath path = new GraphicsPath())
  397. {
  398. path.AddRectangle(graph.GetAbsoluteRectangle(rect));
  399. path.Transform(graph.Transform);
  400. this.Axis.Common.HotRegionsList.AddHotRegion(
  401. path,
  402. false,
  403. ChartElementType.TickMarks,
  404. this);
  405. }
  406. }
  407. else if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
  408. {
  409. RectangleF rect = new RectangleF( first.X - 0.5f, first.Y - 0.5f, Math.Abs( second.X - first.X ) + 1, Math.Abs( second.Y - first.Y ) + 1 );
  410. Axis.Common.HotRegionsList.AddHotRegion(rect, this, ChartElementType.TickMarks, true);
  411. }
  412. else
  413. {
  414. if (!Axis.Common.ProcessModePaint) //if ProcessModePaint is true it will be called later
  415. Draw3DTickLine(graph, first, second, backElements);
  416. }
  417. }
  418. if (Axis.Common.ProcessModePaint)
  419. {
  420. // Draw grid line
  421. if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
  422. {
  423. graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
  424. }
  425. else
  426. {
  427. Draw3DTickLine(graph, first, second, backElements);
  428. }
  429. }
  430. }
  431. // Move position
  432. if (this.majorGridTick || this.Axis.IsLogarithmic == false)
  433. {
  434. current += interval;
  435. }
  436. }
  437. // Used for auto interval for auto tick marks and
  438. // gridlines
  439. if( !this.majorGridTick )
  440. {
  441. this.interval = oldInterval;
  442. this.intervalType = oldIntervalType;
  443. this.intervalOffset = oldIntervalOffset;
  444. this.intervalOffsetType = oldIntervalOffsetType;
  445. }
  446. }
  447. /// <summary>
  448. /// This method returns linearized logarithmic value
  449. /// which is minimum for range with interval 1.
  450. /// </summary>
  451. /// <param name="current">Current value</param>
  452. /// <param name="axisSeries">First series attached to axis.</param>
  453. /// <returns>Returns Minimum for the range which contains current value</returns>
  454. private double GetLogMinimum( double current, Series axisSeries )
  455. {
  456. double viewMinimum = Axis.ViewMinimum;
  457. DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
  458. if( GetIntervalOffset() != 0 && axisSeries == null)
  459. {
  460. viewMinimum += ChartHelper.GetIntervalSize(viewMinimum, GetIntervalOffset(),
  461. offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
  462. }
  463. return viewMinimum + Math.Floor( ( current - viewMinimum ));
  464. }
  465. /// <summary>
  466. /// Draws and hit test for custom TickMarks from the custom labels collection.
  467. /// </summary>
  468. /// <param name="graph">Reference to the Chart Graphics object.</param>
  469. /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
  470. internal void PaintCustom( ChartGraphics graph, bool backElements )
  471. {
  472. PointF first = PointF.Empty; // The First point of a tick mark
  473. PointF second = PointF.Empty; // The Second point of a tick mark
  474. float axisPosition; // Axis position.
  475. // Axis scroll bar will increase size of the Outside and Cross style tick marks
  476. float scrollBarSize = 0;
  477. if (this.Axis.ScrollBar.IsVisible && this.Axis.ScrollBar.IsPositionedInside && this.Axis.IsAxisOnAreaEdge)
  478. {
  479. scrollBarSize = (float)this.Axis.ScrollBar.GetScrollBarRelativeSize();
  480. }
  481. // Left tickmarks
  482. if (Axis.AxisPosition == AxisPosition.Left)
  483. {
  484. // The tick marks will follow axis or they will
  485. // be always on the border of the chart area.
  486. if (Axis.GetIsMarksNextToAxis())
  487. axisPosition = (float)Axis.GetAxisPosition();
  488. else
  489. axisPosition = Axis.PlotAreaPosition.X;
  490. if( _style == TickMarkStyle.InsideArea )
  491. {
  492. first.X = axisPosition;
  493. second.X = axisPosition + _size;
  494. }
  495. else if( _style == TickMarkStyle.OutsideArea )
  496. {
  497. first.X = axisPosition - _size - scrollBarSize;
  498. second.X = axisPosition;
  499. }
  500. else if( _style == TickMarkStyle.AcrossAxis )
  501. {
  502. first.X = axisPosition - _size/2 - scrollBarSize;
  503. second.X = axisPosition + _size/2;
  504. }
  505. }
  506. // Right tickmarks
  507. else if (Axis.AxisPosition == AxisPosition.Right)
  508. {
  509. // The tick marks will follow axis or they will
  510. // be always on the border of the chart area.
  511. if (Axis.GetIsMarksNextToAxis())
  512. axisPosition = (float)Axis.GetAxisPosition();
  513. else
  514. axisPosition = Axis.PlotAreaPosition.Right;
  515. if( _style == TickMarkStyle.InsideArea )
  516. {
  517. first.X = axisPosition - _size;
  518. second.X = axisPosition;
  519. }
  520. else if( _style == TickMarkStyle.OutsideArea )
  521. {
  522. first.X = axisPosition;
  523. second.X = axisPosition + _size + scrollBarSize;
  524. }
  525. else if( _style == TickMarkStyle.AcrossAxis )
  526. {
  527. first.X = axisPosition - _size/2;
  528. second.X = axisPosition + _size/2 + scrollBarSize;
  529. }
  530. }
  531. // Top tickmarks
  532. else if (Axis.AxisPosition == AxisPosition.Top)
  533. {
  534. // The tick marks will follow axis or they will
  535. // be always on the border of the chart area.
  536. if (Axis.GetIsMarksNextToAxis())
  537. axisPosition = (float)Axis.GetAxisPosition();
  538. else
  539. axisPosition = Axis.PlotAreaPosition.Y;
  540. if( _style == TickMarkStyle.InsideArea )
  541. {
  542. first.Y = axisPosition;
  543. second.Y = axisPosition + _size;
  544. }
  545. else if( _style == TickMarkStyle.OutsideArea )
  546. {
  547. first.Y = axisPosition - _size - scrollBarSize;
  548. second.Y = axisPosition;
  549. }
  550. else if( _style == TickMarkStyle.AcrossAxis )
  551. {
  552. first.Y = axisPosition - _size/2 - scrollBarSize;
  553. second.Y = axisPosition + _size/2;
  554. }
  555. }
  556. // Bottom tickmarks
  557. else if (Axis.AxisPosition == AxisPosition.Bottom)
  558. {
  559. // The tick marks will follow axis or they will
  560. // be always on the border of the chart area.
  561. if (Axis.GetIsMarksNextToAxis())
  562. axisPosition = (float)Axis.GetAxisPosition();
  563. else
  564. axisPosition = Axis.PlotAreaPosition.Bottom;
  565. if( _style == TickMarkStyle.InsideArea )
  566. {
  567. first.Y = axisPosition - _size;
  568. second.Y = axisPosition;
  569. }
  570. else if( _style == TickMarkStyle.OutsideArea )
  571. {
  572. first.Y = axisPosition;
  573. second.Y = axisPosition + _size + scrollBarSize;
  574. }
  575. else if( _style == TickMarkStyle.AcrossAxis )
  576. {
  577. first.Y = axisPosition - _size/2;
  578. second.Y = axisPosition + _size/2 + scrollBarSize;
  579. }
  580. }
  581. // Loop through all custom labels
  582. foreach (CustomLabel label in Axis.CustomLabels)
  583. {
  584. if((label.GridTicks & GridTickTypes.TickMark) == GridTickTypes.TickMark)
  585. {
  586. double position = (label.ToPosition + label.FromPosition) / 2.0;
  587. if (position >= Axis.ViewMinimum && position <= Axis.ViewMaximum)
  588. {
  589. // Left tickmarks
  590. if (Axis.AxisPosition == AxisPosition.Left)
  591. {
  592. first.Y = (float)Axis.GetLinearPosition(position);
  593. second.Y = first.Y;
  594. }
  595. // Right tickmarks
  596. else if (Axis.AxisPosition == AxisPosition.Right)
  597. {
  598. first.Y = (float)Axis.GetLinearPosition(position);
  599. second.Y = first.Y;
  600. }
  601. // Top tickmarks
  602. else if (Axis.AxisPosition == AxisPosition.Top)
  603. {
  604. first.X = (float)Axis.GetLinearPosition(position);
  605. second.X = first.X;
  606. }
  607. // Bottom tickmarks
  608. else if (Axis.AxisPosition == AxisPosition.Bottom)
  609. {
  610. first.X = (float)Axis.GetLinearPosition(position);
  611. second.X = first.X;
  612. }
  613. if (Axis.Common.ProcessModeRegions)
  614. {
  615. if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
  616. {
  617. RectangleF rect = new RectangleF( first.X - 0.5f, first.Y - 0.5f, Math.Abs( second.X - first.X ) + 1, Math.Abs( second.Y - first.Y ) + 1 );
  618. Axis.Common.HotRegionsList.AddHotRegion(rect, this, ChartElementType.TickMarks, true);
  619. }
  620. else
  621. {
  622. Draw3DTickLine(graph, first, second, backElements);
  623. }
  624. }
  625. if (Axis.Common.ProcessModePaint)
  626. {
  627. // Draw grid line
  628. if (!this.Axis.ChartArea.Area3DStyle.Enable3D || this.Axis.ChartArea.chartAreaIsCurcular)
  629. {
  630. graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
  631. }
  632. else
  633. {
  634. Draw3DTickLine(graph, first, second, backElements);
  635. }
  636. }
  637. }
  638. }
  639. }
  640. }
  641. /// <summary>
  642. /// Draws tick mark line in 3D space.
  643. /// </summary>
  644. /// <param name="graph">Reference to the Chart Graphics object.</param>
  645. /// <param name="point1">First line point.</param>
  646. /// <param name="point2">Second line point.</param>
  647. /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
  648. internal void Draw3DTickLine(
  649. ChartGraphics graph,
  650. PointF point1,
  651. PointF point2,
  652. bool backElements
  653. )
  654. {
  655. ChartArea area = this.Axis.ChartArea;
  656. //*****************************************************************
  657. //** Set the tick marks line depth
  658. //*****************************************************************
  659. bool axisOnEdge;
  660. float wallZPosition = Axis.GetMarksZPosition(out axisOnEdge);
  661. //*****************************************************************
  662. //** Check if tick mark should be drawn as back or front element
  663. //*****************************************************************
  664. // Check if axis tick marks are drawn inside plotting area
  665. bool tickMarksOnEdge = axisOnEdge;
  666. if(tickMarksOnEdge &&
  667. this.Axis.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
  668. this.Axis.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea ||
  669. this.Axis.MinorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
  670. this.Axis.MinorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
  671. {
  672. tickMarksOnEdge = false;
  673. }
  674. SurfaceNames surfaceName = (wallZPosition == 0f) ? SurfaceNames.Back : SurfaceNames.Front;
  675. if( !area.ShouldDrawOnSurface(surfaceName, backElements, tickMarksOnEdge) )
  676. {
  677. // Skip drawing
  678. return;
  679. }
  680. //*****************************************************************
  681. //** Add area scene wall width to the length of the tick mark
  682. //*****************************************************************
  683. if (Axis.AxisPosition == AxisPosition.Bottom &&
  684. (!Axis.GetIsMarksNextToAxis() || axisOnEdge) &&
  685. area.IsBottomSceneWallVisible())
  686. {
  687. point2.Y += area.areaSceneWallWidth.Height;
  688. }
  689. else if (Axis.AxisPosition == AxisPosition.Left &&
  690. (!Axis.GetIsMarksNextToAxis() || axisOnEdge) &&
  691. area.IsSideSceneWallOnLeft())
  692. {
  693. point1.X -= area.areaSceneWallWidth.Width;
  694. }
  695. else if (Axis.AxisPosition == AxisPosition.Right &&
  696. (!Axis.GetIsMarksNextToAxis() || axisOnEdge) &&
  697. !area.IsSideSceneWallOnLeft())
  698. {
  699. point2.X += area.areaSceneWallWidth.Width;
  700. }
  701. else if (Axis.AxisPosition == AxisPosition.Top &&
  702. (!Axis.GetIsMarksNextToAxis() || axisOnEdge))
  703. {
  704. point1.Y -= area.areaSceneWallWidth.Height;
  705. }
  706. //*****************************************************************
  707. //** Adjust grid line direction for the Top axis
  708. //*****************************************************************
  709. Point3D point3 = null, point4 = null;
  710. if(axisOnEdge && area.areaSceneWallWidth.Width != 0f)
  711. {
  712. if (Axis.AxisPosition == AxisPosition.Top)
  713. {
  714. // Always use plot area position to draw tick mark
  715. float axisPosition = Axis.PlotAreaPosition.Y;
  716. if( _style == TickMarkStyle.InsideArea )
  717. {
  718. point1.Y = axisPosition;
  719. point2.Y = axisPosition + _size;
  720. point3 = new Point3D(point1.X, point1.Y, - area.areaSceneWallWidth.Width);
  721. point4 = new Point3D(point1.X, point1.Y, 0f);
  722. }
  723. else if( _style == TickMarkStyle.OutsideArea )
  724. {
  725. point1.Y = axisPosition;
  726. point2.Y = axisPosition;
  727. point3 = new Point3D(point1.X, axisPosition, wallZPosition);
  728. point4 = new Point3D(point1.X, point1.Y, - _size - area.areaSceneWallWidth.Width);
  729. }
  730. else if( _style == TickMarkStyle.AcrossAxis )
  731. {
  732. point1.Y = axisPosition;
  733. point2.Y = axisPosition + _size/2;
  734. point3 = new Point3D(point1.X, axisPosition, wallZPosition);
  735. point4 = new Point3D(point1.X, point1.Y, - _size/2 - area.areaSceneWallWidth.Width);
  736. }
  737. // Do not show "bent" tick marks on the top surface
  738. if(area.ShouldDrawOnSurface(SurfaceNames.Top, backElements, false))
  739. {
  740. point3 = null;
  741. point4 = null;
  742. }
  743. }
  744. //*****************************************************************
  745. //** Adjust grid line direction for the Left axis
  746. //*****************************************************************
  747. if (Axis.AxisPosition == AxisPosition.Left && !area.IsSideSceneWallOnLeft())
  748. {
  749. // Always use plot area position to draw tick mark
  750. float axisPosition = Axis.PlotAreaPosition.X;
  751. if( _style == TickMarkStyle.InsideArea )
  752. {
  753. point1.X = axisPosition;
  754. point2.X = axisPosition + _size;
  755. point3 = new Point3D(point1.X, point1.Y, - area.areaSceneWallWidth.Width);
  756. point4 = new Point3D(point1.X, point1.Y, 0f);
  757. }
  758. else if( _style == TickMarkStyle.OutsideArea )
  759. {
  760. point1.X = axisPosition;
  761. point2.X = axisPosition;
  762. point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
  763. point4 = new Point3D(axisPosition, point1.Y, - _size - area.areaSceneWallWidth.Width);
  764. }
  765. else if( _style == TickMarkStyle.AcrossAxis )
  766. {
  767. point1.X = axisPosition;
  768. point2.X = axisPosition + _size/2;
  769. point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
  770. point4 = new Point3D(axisPosition, point1.Y, - _size/2 - area.areaSceneWallWidth.Width);
  771. }
  772. // Do not show "bent" tick marks on the left surface
  773. if(area.ShouldDrawOnSurface(SurfaceNames.Left, backElements, false))
  774. {
  775. point3 = null;
  776. point4 = null;
  777. }
  778. }
  779. //*****************************************************************
  780. //** Adjust grid line direction for the Right axis
  781. //*****************************************************************
  782. else if (Axis.AxisPosition == AxisPosition.Right && area.IsSideSceneWallOnLeft())
  783. {
  784. // Always use plot area position to draw tick mark
  785. float axisPosition = Axis.PlotAreaPosition.Right;
  786. if( _style == TickMarkStyle.InsideArea )
  787. {
  788. point1.X = axisPosition - _size;
  789. point2.X = axisPosition;
  790. point3 = new Point3D(point2.X, point2.Y, - area.areaSceneWallWidth.Width);
  791. point4 = new Point3D(point2.X, point2.Y, 0f);
  792. }
  793. else if( _style == TickMarkStyle.OutsideArea )
  794. {
  795. point1.X = axisPosition;
  796. point2.X = axisPosition;
  797. point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
  798. point4 = new Point3D(axisPosition, point1.Y, - _size - area.areaSceneWallWidth.Width);
  799. }
  800. else if( _style == TickMarkStyle.AcrossAxis )
  801. {
  802. point1.X = axisPosition - _size/2;
  803. point2.X = axisPosition;
  804. point3 = new Point3D(axisPosition, point1.Y, wallZPosition);
  805. point4 = new Point3D(axisPosition, point1.Y, - _size/2 - area.areaSceneWallWidth.Width);
  806. }
  807. // Do not show "bent" tick marks on the right surface
  808. if(area.ShouldDrawOnSurface(SurfaceNames.Right, backElements, false))
  809. {
  810. point3 = null;
  811. point4 = null;
  812. }
  813. }
  814. }
  815. //*****************************************************************
  816. //** Draw tick mark (first line)
  817. //*****************************************************************
  818. graph.Draw3DLine(
  819. area.matrix3D,
  820. borderColor, borderWidth, borderDashStyle,
  821. new Point3D(point1.X, point1.Y, wallZPosition),
  822. new Point3D(point2.X, point2.Y, wallZPosition),
  823. Axis.Common,
  824. this,
  825. ChartElementType.TickMarks
  826. );
  827. //*****************************************************************
  828. //** Draw tick mark (second line)
  829. //*****************************************************************
  830. if(point3 != null && point4 != null)
  831. {
  832. graph.Draw3DLine(
  833. area.matrix3D,
  834. borderColor, borderWidth, borderDashStyle,
  835. point3,
  836. point4,
  837. Axis.Common,
  838. this,
  839. ChartElementType.TickMarks
  840. );
  841. }
  842. }
  843. #endregion
  844. #region TickMark properties
  845. /// <summary>
  846. /// Tick mark style.
  847. /// </summary>
  848. [
  849. SRCategory("CategoryAttributeAppearance"),
  850. Bindable(true),
  851. DefaultValue(TickMarkStyle.OutsideArea),
  852. SRDescription("DescriptionAttributeTickMark_Style")
  853. ]
  854. public TickMarkStyle TickMarkStyle
  855. {
  856. get
  857. {
  858. return _style;
  859. }
  860. set
  861. {
  862. _style = value;
  863. this.Invalidate();
  864. if(Axis != null)
  865. Axis.CallOnModifing();
  866. }
  867. }
  868. /// <summary>
  869. /// Tick mark size.
  870. /// </summary>
  871. [
  872. SRCategory("CategoryAttributeAppearance"),
  873. Bindable(true),
  874. DefaultValue(1.0F),
  875. SRDescription("DescriptionAttributeTickMark_Size")
  876. ]
  877. public float Size
  878. {
  879. get
  880. {
  881. return _size;
  882. }
  883. set
  884. {
  885. _size = value;
  886. this.Invalidate();
  887. if (Axis != null)
  888. Axis.CallOnModifing();
  889. }
  890. }
  891. #endregion
  892. }
  893. /// <summary>
  894. /// The Grid class represents axis grid lines which are drawn in the
  895. /// plotting area. It contains grid interval and visual appearance
  896. /// properties. This class also contains methods for grid lines drawing.
  897. /// </summary>
  898. [
  899. DefaultProperty("Enabled"),
  900. SRDescription("DescriptionAttributeGrid_Grid")
  901. ]
  902. public class Grid
  903. {
  904. #region Grid fields and Constructors
  905. // Reference to the Axis object
  906. private Axis _axis = null;
  907. // Flags indicate that interval properties where changed
  908. internal bool intervalOffsetChanged = false;
  909. internal bool intervalChanged = false;
  910. internal bool intervalTypeChanged = false;
  911. internal bool intervalOffsetTypeChanged = false;
  912. internal bool enabledChanged = false;
  913. // Data members, which store properties values
  914. internal double intervalOffset = 0;
  915. internal double interval = 0;
  916. internal DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
  917. internal DateTimeIntervalType intervalOffsetType = DateTimeIntervalType.Auto;
  918. internal Color borderColor = Color.Black;
  919. internal int borderWidth = 1;
  920. internal ChartDashStyle borderDashStyle = ChartDashStyle.Solid;
  921. internal bool enabled = true;
  922. // Indicates that object describes Major Tick Mark or Grid Line
  923. internal bool majorGridTick = false;
  924. // Common number of intervals on the numeric and date-time axis
  925. internal const double NumberOfIntervals = 5.0;
  926. internal const double NumberOfDateTimeIntervals = 4.0;
  927. /// <summary>
  928. /// Public default constructor.
  929. /// </summary>
  930. public Grid()
  931. {
  932. }
  933. /// <summary>
  934. /// Public constructor.
  935. /// </summary>
  936. /// <param name="axis">Axis which owns the grid.</param>
  937. /// <param name="major">Major axis element.</param>
  938. internal Grid(Axis axis, bool major)
  939. {
  940. Initialize(axis, major);
  941. }
  942. /// <summary>
  943. /// Initializes the object.
  944. /// </summary>
  945. /// <param name="axis">Axis which owns the grid.</param>
  946. /// <param name="major">Major axis element.</param>
  947. internal void Initialize(Axis axis, bool major)
  948. {
  949. // Minor elements are disabled by default
  950. if(!this.enabledChanged &&
  951. this._axis == null &&
  952. !major)
  953. {
  954. enabled = false;
  955. }
  956. // If object was first created and populated with data and then added into the axis
  957. // we need to remember changed values.
  958. // NOTE: Fixes issue #6237
  959. if(this._axis == null)
  960. {
  961. TickMark tickMark = this as TickMark;
  962. if(this.interval != 0)
  963. {
  964. if (tickMark != null)
  965. {
  966. if(major)
  967. {
  968. axis.tempMajorTickMarkInterval = this.interval;
  969. }
  970. else
  971. {
  972. axis.tempMinorTickMarkInterval = this.interval;
  973. }
  974. }
  975. else
  976. {
  977. if(major)
  978. {
  979. axis.tempMajorGridInterval = this.interval;
  980. }
  981. else
  982. {
  983. axis.tempMinorGridInterval = this.interval;
  984. }
  985. }
  986. }
  987. if(this.intervalType != DateTimeIntervalType.Auto)
  988. {
  989. if(tickMark != null)
  990. {
  991. if(major)
  992. {
  993. axis.tempTickMarkIntervalType = this.intervalType;
  994. }
  995. }
  996. else
  997. {
  998. if(major)
  999. {
  1000. axis.tempGridIntervalType = this.intervalType;
  1001. }
  1002. }
  1003. }
  1004. }
  1005. // Set axis object reference
  1006. this._axis = axis;
  1007. // Set a flag if this object represent minor or major tick
  1008. this.majorGridTick = major;
  1009. // internal double interval = 0;
  1010. // internal DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
  1011. }
  1012. #endregion
  1013. #region Grid helper functions
  1014. /// <summary>
  1015. /// Gets axes to which this object attached to
  1016. /// </summary>
  1017. /// <returns>Axis object.</returns>
  1018. internal Axis GetAxis()
  1019. {
  1020. return _axis;
  1021. }
  1022. /// <summary>
  1023. /// Invalidate chart area the axis belong to.
  1024. /// </summary>
  1025. internal void Invalidate()
  1026. {
  1027. if(this._axis != null)
  1028. {
  1029. this._axis.Invalidate();
  1030. }
  1031. }
  1032. #endregion
  1033. #region Grid lines drawing functions
  1034. /// <summary>
  1035. /// Draws grid lines.
  1036. /// </summary>
  1037. /// <param name="graph">Reference to the Chart Graphics object.</param>
  1038. internal void Paint( ChartGraphics graph )
  1039. {
  1040. // Grids are disabled
  1041. if( !this.enabled )
  1042. {
  1043. return;
  1044. }
  1045. // Check if custom grid lines should be drawn from custom labels
  1046. if(_axis.IsCustomGridLines())
  1047. {
  1048. PaintCustom( graph );
  1049. return;
  1050. }
  1051. double gridInterval; // Grid interval
  1052. double current; // Current position
  1053. // Get first series attached to this axis
  1054. Series axisSeries = null;
  1055. if(_axis.axisType == AxisName.X || _axis.axisType == AxisName.X2)
  1056. {
  1057. List<string> seriesArray = _axis.ChartArea.GetXAxesSeries((_axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, _axis.SubAxisName);
  1058. if(seriesArray.Count > 0)
  1059. {
  1060. axisSeries = _axis.Common.DataManager.Series[seriesArray[0]];
  1061. if(axisSeries != null && !axisSeries.IsXValueIndexed)
  1062. {
  1063. axisSeries = null;
  1064. }
  1065. }
  1066. }
  1067. // ****************************************************************
  1068. // This code creates auto interval for auto tick marks and
  1069. // gridlines. If type is not date there are always four tickmarks
  1070. // or gridlines between major gridlines and tickmarks. For date
  1071. // type interval is calculated using CalcInterval function.
  1072. // ****************************************************************
  1073. double oldInterval = this.interval;
  1074. DateTimeIntervalType oldIntervalType = this.intervalType;
  1075. double oldIntervalOffset = this.intervalOffset;
  1076. DateTimeIntervalType oldIntervalOffsetType = this.intervalOffsetType;
  1077. if( !this.majorGridTick && ( this.interval == 0 || double.IsNaN(this.interval) ) )
  1078. {
  1079. // Number type
  1080. if( this._axis.majorGrid.GetIntervalType() == DateTimeIntervalType.Auto )
  1081. {
  1082. this.interval = this._axis.majorGrid.GetInterval() / Grid.NumberOfIntervals;
  1083. }
  1084. // Date type
  1085. else
  1086. {
  1087. DateTimeIntervalType localIntervalType = this._axis.majorGrid.GetIntervalType();
  1088. this.interval = _axis.CalcInterval(
  1089. this._axis.minimum,
  1090. this._axis.minimum + (this._axis.maximum - this._axis.minimum) / Grid.NumberOfDateTimeIntervals,
  1091. true,
  1092. out localIntervalType,
  1093. ChartValueType.DateTime);
  1094. this.intervalType = localIntervalType;
  1095. this.intervalOffsetType = this._axis.majorGrid.GetIntervalOffsetType();
  1096. this.intervalOffset = this._axis.majorGrid.GetIntervalOffset();
  1097. }
  1098. }
  1099. // Current position for grid lines is minimum
  1100. current = _axis.ViewMinimum;
  1101. // ***********************************
  1102. // Check if the AJAX zooming and scrolling mode is enabled.
  1103. // ***********************************
  1104. // Adjust start position depending on the interval type
  1105. if(!_axis.ChartArea.chartAreaIsCurcular ||
  1106. _axis.axisType == AxisName.Y ||
  1107. _axis.axisType == AxisName.Y2 )
  1108. {
  1109. current = ChartHelper.AlignIntervalStart(current, this.GetInterval(), this.GetIntervalType(), axisSeries, this.majorGridTick);
  1110. }
  1111. // The Current position is start position, not minimum
  1112. DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
  1113. if (GetIntervalOffset() != 0 && !double.IsNaN(GetIntervalOffset()) && axisSeries == null)
  1114. {
  1115. current += ChartHelper.GetIntervalSize(current, GetIntervalOffset(), offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
  1116. }
  1117. // Too many gridlines
  1118. if( ( _axis.ViewMaximum - _axis.ViewMinimum ) / ChartHelper.GetIntervalSize( current, this.GetInterval(), this.GetIntervalType(), axisSeries, 0, DateTimeIntervalType.Number, true ) > ChartHelper.MaxNumOfGridlines )
  1119. return;
  1120. // If Maximum, minimum and interval don’t have
  1121. // proper value do not draw grid lines.
  1122. if( _axis.ViewMaximum <= _axis.ViewMinimum )
  1123. return;
  1124. if( this.GetInterval() <= 0 )
  1125. return;
  1126. // Loop for drawing grid lines
  1127. int counter = 0;
  1128. int logStep = 1;
  1129. double oldCurrent = current;
  1130. decimal viewMaximum = (decimal)_axis.ViewMaximum;
  1131. while( (decimal)current <= viewMaximum )
  1132. {
  1133. // Take an interval between gridlines. Interval
  1134. // depends on interval type.
  1135. if( this.majorGridTick || this._axis.IsLogarithmic == false )
  1136. {
  1137. double autoInterval = this.GetInterval();
  1138. gridInterval = ChartHelper.GetIntervalSize(current, autoInterval, this.GetIntervalType(), axisSeries, this.GetIntervalOffset(), offsetType, true);
  1139. // Check interval size
  1140. if (gridInterval == 0)
  1141. {
  1142. throw (new InvalidOperationException(SR.ExceptionTickMarksIntervalIsZero));
  1143. }
  1144. // Draw between min & max values only
  1145. if((decimal)current >= (decimal)_axis.ViewMinimum)
  1146. {
  1147. DrawGrid( graph, current );
  1148. }
  1149. // Move position
  1150. current += gridInterval;
  1151. }
  1152. // Code for linear minor gridlines and tickmarks
  1153. // if scale is logarithmic.
  1154. else
  1155. {
  1156. // This code is used only for logarithmic scale and minor tick marks or
  1157. // gridlines which have linear minor scale in logarithmic major scale.
  1158. // This code is used to find minimum value for the interval. For example
  1159. // if logarithmic base is 2 and interval is between 4 and 8; current value
  1160. // is 5.6; this method will return linearised value for 4. This code works
  1161. // like Math.Floor for logarithmic scale.
  1162. double logMinimum = this.GetLogMinimum( current, axisSeries );
  1163. if( oldCurrent != logMinimum )
  1164. {
  1165. oldCurrent = logMinimum;
  1166. logStep = 1;
  1167. }
  1168. // Find interval for logarithmic linearised scale
  1169. double logInterval = Math.Log( 1 + this.interval * logStep, _axis.logarithmBase );
  1170. current = oldCurrent;
  1171. // Move position
  1172. current += logInterval;
  1173. logStep++;
  1174. // Reset current position if major interval is passed.
  1175. if( this.GetLogMinimum( current, axisSeries ) != logMinimum )
  1176. {
  1177. continue;
  1178. }
  1179. // Check interval size
  1180. if (logInterval == 0)
  1181. {
  1182. throw (new InvalidOperationException(SR.ExceptionTickMarksIntervalIsZero));
  1183. }
  1184. // Draw between min & max values only
  1185. if( (decimal)current >= (decimal)_axis.ViewMinimum && (decimal)current <= (decimal)_axis.ViewMaximum )
  1186. {
  1187. DrawGrid( graph, current );
  1188. }
  1189. }
  1190. // Check if we do not exceed max number of elements
  1191. if (counter++ > ChartHelper.MaxNumOfGridlines)
  1192. {
  1193. break;
  1194. }
  1195. }
  1196. // Used for auto interval for auto tick marks and
  1197. // gridlines
  1198. if( !this.majorGridTick )
  1199. {
  1200. this.interval = oldInterval;
  1201. this.intervalType = oldIntervalType;
  1202. this.intervalOffset = oldIntervalOffset;
  1203. this.intervalOffsetType = oldIntervalOffsetType;
  1204. }
  1205. }
  1206. /// <summary>
  1207. /// This method returns linearized logarithmic value
  1208. /// which is minimum for range with interval 1.
  1209. /// </summary>
  1210. /// <param name="current">Current value</param>
  1211. /// <param name="axisSeries">First series attached to axis.</param>
  1212. /// <returns>Returns Minimum for the range which contains current value</returns>
  1213. private double GetLogMinimum( double current, Series axisSeries )
  1214. {
  1215. double viewMinimum = _axis.ViewMinimum;
  1216. DateTimeIntervalType offsetType = (GetIntervalOffsetType() == DateTimeIntervalType.Auto) ? GetIntervalType() : GetIntervalOffsetType();
  1217. if( GetIntervalOffset() != 0 && axisSeries == null)
  1218. {
  1219. viewMinimum += ChartHelper.GetIntervalSize(viewMinimum, GetIntervalOffset(),
  1220. offsetType, axisSeries, 0, DateTimeIntervalType.Number, true, false);
  1221. }
  1222. return viewMinimum + Math.Floor( ( current - viewMinimum ));
  1223. }
  1224. /// <summary>
  1225. /// Draw the grid line
  1226. /// </summary>
  1227. /// <param name="graph">Chart Graphics object</param>
  1228. /// <param name="current">Current position of the gridline</param>
  1229. private void DrawGrid( ChartGraphics graph, double current )
  1230. {
  1231. // Common elements
  1232. CommonElements common = this._axis.Common;
  1233. PointF first = PointF.Empty; // The First point of a grid line
  1234. PointF second = PointF.Empty; // The Second point of a grid line
  1235. RectangleF plotArea; // Plot area position
  1236. plotArea = _axis.PlotAreaPosition.ToRectangleF();
  1237. // Horizontal gridlines
  1238. if( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right )
  1239. {
  1240. first.X = plotArea.X;
  1241. second.X = plotArea.Right;
  1242. first.Y = (float)_axis.GetLinearPosition( current );
  1243. second.Y = first.Y;
  1244. }
  1245. // Vertical gridlines
  1246. if( _axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom )
  1247. {
  1248. first.Y = plotArea.Y;
  1249. second.Y = plotArea.Bottom;
  1250. first.X = (float)_axis.GetLinearPosition( current );
  1251. second.X = first.X;
  1252. }
  1253. if( common.ProcessModeRegions )
  1254. {
  1255. if( this._axis.ChartArea.Area3DStyle.Enable3D && !this._axis.ChartArea.chartAreaIsCurcular)
  1256. {
  1257. if(!common.ProcessModePaint) //if ProcessModePaint is true it will be called later
  1258. graph.Draw3DGridLine(this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), common, this );
  1259. }
  1260. else if(!this._axis.ChartArea.chartAreaIsCurcular)
  1261. {
  1262. using (GraphicsPath path = new GraphicsPath())
  1263. {
  1264. if (Math.Abs(first.X - second.X) > Math.Abs(first.Y - second.Y))
  1265. {
  1266. path.AddLine(first.X, first.Y - 1, second.X, second.Y - 1);
  1267. path.AddLine(second.X, second.Y + 1, first.X, first.Y + 1);
  1268. path.CloseAllFigures();
  1269. }
  1270. else
  1271. {
  1272. path.AddLine(first.X - 1, first.Y, second.X - 1, second.Y);
  1273. path.AddLine(second.X + 1, second.Y, first.X + 1, first.Y);
  1274. path.CloseAllFigures();
  1275. }
  1276. common.HotRegionsList.AddHotRegion(path, true, ChartElementType.Gridlines, this);
  1277. }
  1278. }
  1279. }
  1280. if( common.ProcessModePaint )
  1281. {
  1282. // Check if grid lines should be drawn for circular chart area
  1283. if(_axis.ChartArea.chartAreaIsCurcular)
  1284. {
  1285. if(_axis.axisType == AxisName.Y)
  1286. {
  1287. _axis.DrawCircularLine( this, graph, borderColor, borderWidth, borderDashStyle, first.Y );
  1288. }
  1289. if(_axis.axisType == AxisName.X)
  1290. {
  1291. ICircularChartType chartType = this._axis.ChartArea.GetCircularChartType();
  1292. if(chartType != null && chartType.RadialGridLinesSupported())
  1293. {
  1294. _axis.DrawRadialLine( this, graph, borderColor, borderWidth, borderDashStyle, current );
  1295. }
  1296. }
  1297. }
  1298. else if(!this._axis.ChartArea.Area3DStyle.Enable3D || this._axis.ChartArea.chartAreaIsCurcular)
  1299. {
  1300. graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
  1301. }
  1302. else
  1303. {
  1304. graph.Draw3DGridLine( this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), _axis.Common, this );
  1305. }
  1306. }
  1307. }
  1308. /// <summary>
  1309. /// Draws custom grid lines from custom labels.
  1310. /// </summary>
  1311. /// <param name="graph">Reference to the Chart Graphics object.</param>
  1312. internal void PaintCustom( ChartGraphics graph )
  1313. {
  1314. // Common Elements
  1315. CommonElements common = this._axis.Common;
  1316. PointF first = PointF.Empty; // The First point of a grid line
  1317. PointF second = PointF.Empty; // The Second point of a grid line
  1318. RectangleF plotArea = _axis.PlotAreaPosition.ToRectangleF(); // Plot area position
  1319. // Loop through all custom labels
  1320. foreach(CustomLabel label in _axis.CustomLabels)
  1321. {
  1322. if((label.GridTicks & GridTickTypes.Gridline) == GridTickTypes.Gridline)
  1323. {
  1324. double position = (label.ToPosition + label.FromPosition) / 2.0;
  1325. if(position >= _axis.ViewMinimum && position <= _axis.ViewMaximum)
  1326. {
  1327. // Horizontal gridlines
  1328. if( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right )
  1329. {
  1330. first.X = plotArea.X;
  1331. second.X = plotArea.Right;
  1332. first.Y = (float)_axis.GetLinearPosition( position );
  1333. second.Y = first.Y;
  1334. }
  1335. // Vertical gridlines
  1336. if( _axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom )
  1337. {
  1338. first.Y = plotArea.Y;
  1339. second.Y = plotArea.Bottom;
  1340. first.X = (float)_axis.GetLinearPosition( position );
  1341. second.X = first.X;
  1342. }
  1343. if( common.ProcessModeRegions )
  1344. {
  1345. if( !this._axis.ChartArea.Area3DStyle.Enable3D || this._axis.ChartArea.chartAreaIsCurcular )
  1346. {
  1347. using (GraphicsPath path = new GraphicsPath())
  1348. {
  1349. if (Math.Abs(first.X - second.X) > Math.Abs(first.Y - second.Y))
  1350. {
  1351. path.AddLine(first.X, first.Y - 1, second.X, second.Y - 1);
  1352. path.AddLine(second.X, second.Y + 1, first.X, first.Y + 1);
  1353. path.CloseAllFigures();
  1354. }
  1355. else
  1356. {
  1357. path.AddLine(first.X - 1, first.Y, second.X - 1, second.Y);
  1358. path.AddLine(second.X + 1, second.Y, first.X + 1, first.Y);
  1359. path.CloseAllFigures();
  1360. }
  1361. common.HotRegionsList.AddHotRegion(path, true, ChartElementType.Gridlines, this);
  1362. }
  1363. }
  1364. else
  1365. {
  1366. graph.Draw3DGridLine(this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), common, this );
  1367. }
  1368. }
  1369. if( common.ProcessModePaint )
  1370. {
  1371. if(!this._axis.ChartArea.Area3DStyle.Enable3D || this._axis.ChartArea.chartAreaIsCurcular)
  1372. {
  1373. graph.DrawLineRel( borderColor, borderWidth, borderDashStyle, first, second );
  1374. }
  1375. else
  1376. {
  1377. graph.Draw3DGridLine(this._axis.ChartArea, borderColor, borderWidth, borderDashStyle, first, second, ( _axis.AxisPosition == AxisPosition.Left || _axis.AxisPosition == AxisPosition.Right ), _axis.Common, this );
  1378. }
  1379. }
  1380. }
  1381. }
  1382. }
  1383. }
  1384. #endregion
  1385. #region Grid properties
  1386. /// <summary>
  1387. /// Gets or sets grid or tick mark interval offset.
  1388. /// </summary>
  1389. [
  1390. SRCategory("CategoryAttributeData"),
  1391. Bindable(true),
  1392. SRDescription("DescriptionAttributeIntervalOffset3"),
  1393. TypeConverter(typeof(AxisElementIntervalValueConverter))
  1394. ]
  1395. public double IntervalOffset
  1396. {
  1397. get
  1398. {
  1399. return intervalOffset;
  1400. }
  1401. set
  1402. {
  1403. intervalOffset = value;
  1404. intervalOffsetChanged = true;
  1405. this.Invalidate();
  1406. if (Axis != null)
  1407. Axis.CallOnModifing();
  1408. }
  1409. }
  1410. /// <summary>
  1411. /// Determines if Enabled property should be serialized.
  1412. /// </summary>
  1413. /// <returns></returns>
  1414. internal bool ShouldSerializeIntervalOffset()
  1415. {
  1416. if (this.majorGridTick)
  1417. {
  1418. return !double.IsNaN(intervalOffset);
  1419. }
  1420. return intervalOffset != 0d;
  1421. }
  1422. /// <summary>
  1423. /// Gets the interval offset.
  1424. /// </summary>
  1425. /// <returns></returns>
  1426. internal double GetIntervalOffset()
  1427. {
  1428. if(this.majorGridTick && double.IsNaN(intervalOffset) && this._axis != null)
  1429. {
  1430. return this._axis.IntervalOffset;
  1431. }
  1432. return intervalOffset;
  1433. }
  1434. /// <summary>
  1435. /// Gets or sets the unit of measurement of grid or tick mark offset.
  1436. /// </summary>
  1437. [
  1438. SRCategory("CategoryAttributeData"),
  1439. Bindable(true),
  1440. SRDescription("DescriptionAttributeIntervalOffsetType6"),
  1441. RefreshPropertiesAttribute(RefreshProperties.All)
  1442. ]
  1443. public DateTimeIntervalType IntervalOffsetType
  1444. {
  1445. get
  1446. {
  1447. return intervalOffsetType;
  1448. }
  1449. set
  1450. {
  1451. intervalOffsetType = value;
  1452. intervalOffsetTypeChanged = true;
  1453. this.Invalidate();
  1454. }
  1455. }
  1456. /// <summary>
  1457. /// Determines if IntervalOffsetType property should be serialized.
  1458. /// </summary>
  1459. /// <returns></returns>
  1460. internal bool ShouldSerializeIntervalOffsetType()
  1461. {
  1462. if (this.majorGridTick)
  1463. {
  1464. return intervalOffsetType != DateTimeIntervalType.NotSet;
  1465. }
  1466. return intervalOffsetType != DateTimeIntervalType.Auto;
  1467. }
  1468. /// <summary>
  1469. /// Gets the type of the interval offset.
  1470. /// </summary>
  1471. /// <returns></returns>
  1472. internal DateTimeIntervalType GetIntervalOffsetType()
  1473. {
  1474. if(this.majorGridTick && intervalOffsetType == DateTimeIntervalType.NotSet && this._axis != null)
  1475. {
  1476. return this._axis.IntervalOffsetType;
  1477. }
  1478. return intervalOffsetType;
  1479. }
  1480. /// <summary>
  1481. /// Gets or sets grid or tick mark interval size.
  1482. /// </summary>
  1483. [
  1484. SRCategory("CategoryAttributeData"),
  1485. Bindable(true),
  1486. SRDescription("DescriptionAttributeInterval6"),
  1487. TypeConverter(typeof(AxisElementIntervalValueConverter)),
  1488. RefreshProperties(RefreshProperties.All),
  1489. ]
  1490. public double Interval
  1491. {
  1492. get
  1493. {
  1494. return interval;
  1495. }
  1496. set
  1497. {
  1498. // Validation
  1499. if (value < 0.0)
  1500. throw (new ArgumentException(SR.ExceptionTickMarksIntervalIsNegative, "value"));
  1501. interval = value;
  1502. intervalChanged = true;
  1503. // Enable minor elements
  1504. if (!this.majorGridTick && value != 0.0 && !Double.IsNaN(value))
  1505. {
  1506. // Prevent grids enabling during the serialization
  1507. if (this._axis != null)
  1508. {
  1509. if (this._axis.Chart != null && this._axis.Chart.serializing != false)
  1510. {
  1511. this.Enabled = true;
  1512. }
  1513. }
  1514. }
  1515. // Reset original property value fields
  1516. if (this._axis != null)
  1517. {
  1518. if (this is TickMark)
  1519. {
  1520. if (this.majorGridTick)
  1521. {
  1522. this._axis.tempMajorTickMarkInterval = interval;
  1523. }
  1524. else
  1525. {
  1526. this._axis.tempMinorTickMarkInterval = interval;
  1527. }
  1528. }
  1529. else
  1530. {
  1531. if (this.majorGridTick)
  1532. {
  1533. this._axis.tempMajorGridInterval = interval;
  1534. }
  1535. else
  1536. {
  1537. this._axis.tempMinorGridInterval = interval;
  1538. }
  1539. }
  1540. }
  1541. this.Invalidate();
  1542. if (Axis != null)
  1543. Axis.CallOnModifing();
  1544. }
  1545. }
  1546. /// <summary>
  1547. /// Determines if IntervalOffsetType property should be serialized.
  1548. /// </summary>
  1549. /// <returns></returns>
  1550. internal bool ShouldSerializeInterval()
  1551. {
  1552. if (this.majorGridTick)
  1553. {
  1554. return !double.IsNaN(interval);
  1555. }
  1556. return interval != 0d;
  1557. }
  1558. /// <summary>
  1559. /// Gets the interval.
  1560. /// </summary>
  1561. /// <returns></returns>
  1562. internal double GetInterval()
  1563. {
  1564. if(this.majorGridTick && double.IsNaN(interval) && this._axis != null)
  1565. {
  1566. return this._axis.Interval;
  1567. }
  1568. return interval;
  1569. }
  1570. /// <summary>
  1571. /// Gets or sets the unit of measurement of grid or tick mark interval.
  1572. /// </summary>
  1573. [
  1574. SRCategory("CategoryAttributeData"),
  1575. Bindable(true),
  1576. SRDescription("DescriptionAttributeIntervalType3"),
  1577. RefreshPropertiesAttribute(RefreshProperties.All)
  1578. ]
  1579. public DateTimeIntervalType IntervalType
  1580. {
  1581. get
  1582. {
  1583. return intervalType;
  1584. }
  1585. set
  1586. {
  1587. intervalType = value;
  1588. intervalTypeChanged = true;
  1589. // Reset original property value fields
  1590. if (this._axis != null)
  1591. {
  1592. if (this is TickMark)
  1593. {
  1594. this._axis.tempTickMarkIntervalType = intervalType;
  1595. }
  1596. else
  1597. {
  1598. this._axis.tempGridIntervalType = intervalType;
  1599. }
  1600. }
  1601. this.Invalidate();
  1602. if (Axis != null)
  1603. Axis.CallOnModifing();
  1604. }
  1605. }
  1606. /// <summary>
  1607. /// Determines if IntervalOffsetType property should be serialized.
  1608. /// </summary>
  1609. /// <returns></returns>
  1610. internal bool ShouldSerializeIntervalType()
  1611. {
  1612. if (this.majorGridTick)
  1613. {
  1614. return intervalType != DateTimeIntervalType.NotSet;
  1615. }
  1616. return intervalType != DateTimeIntervalType.Auto;
  1617. }
  1618. /// <summary>
  1619. /// Gets the type of the interval.
  1620. /// </summary>
  1621. /// <returns></returns>
  1622. internal DateTimeIntervalType GetIntervalType()
  1623. {
  1624. if(this.majorGridTick && intervalType == DateTimeIntervalType.NotSet && this._axis != null)
  1625. {
  1626. // Return default value during serialization
  1627. return this._axis.IntervalType;
  1628. }
  1629. return intervalType;
  1630. }
  1631. /// <summary>
  1632. /// Gets or sets grid or tick mark line color.
  1633. /// </summary>
  1634. [
  1635. SRCategory("CategoryAttributeAppearance"),
  1636. Bindable(true),
  1637. DefaultValue(typeof(Color), "Black"),
  1638. SRDescription("DescriptionAttributeLineColor"),
  1639. TypeConverter(typeof(ColorConverter)),
  1640. #if DESIGNER
  1641. Editor(typeof(ChartColorEditor), typeof(UITypeEditor))
  1642. #endif
  1643. ]
  1644. public Color LineColor
  1645. {
  1646. get
  1647. {
  1648. return borderColor;
  1649. }
  1650. set
  1651. {
  1652. borderColor = value;
  1653. this.Invalidate();
  1654. if (Axis != null)
  1655. Axis.CallOnModifing();
  1656. }
  1657. }
  1658. /// <summary>
  1659. /// Gets or sets grid or tick mark line style.
  1660. /// </summary>
  1661. [
  1662. SRCategory("CategoryAttributeAppearance"),
  1663. Bindable(true),
  1664. DefaultValue(ChartDashStyle.Solid),
  1665. SRDescription("DescriptionAttributeLineDashStyle")
  1666. ]
  1667. public ChartDashStyle LineDashStyle
  1668. {
  1669. get
  1670. {
  1671. return borderDashStyle;
  1672. }
  1673. set
  1674. {
  1675. borderDashStyle = value;
  1676. this.Invalidate();
  1677. if (Axis != null)
  1678. Axis.CallOnModifing();
  1679. }
  1680. }
  1681. /// <summary>
  1682. /// Gets or sets grid or tick mark line width.
  1683. /// </summary>
  1684. [
  1685. SRCategory("CategoryAttributeAppearance"),
  1686. Bindable(true),
  1687. DefaultValue(1),
  1688. SRDescription("DescriptionAttributeLineWidth")
  1689. ]
  1690. public int LineWidth
  1691. {
  1692. get
  1693. {
  1694. return borderWidth;
  1695. }
  1696. set
  1697. {
  1698. borderWidth = value;
  1699. this.Invalidate();
  1700. if (Axis != null)
  1701. Axis.CallOnModifing();
  1702. }
  1703. }
  1704. /// <summary>
  1705. /// Gets or sets a flag which indicates if the grid or tick mark is enabled.
  1706. /// </summary>
  1707. [
  1708. SRCategory("CategoryAttributeAppearance"),
  1709. Bindable(true),
  1710. SRDescription("DescriptionAttributeEnabled5")
  1711. ]
  1712. public bool Enabled
  1713. {
  1714. get
  1715. {
  1716. //// Never serialize this property for minor elements
  1717. //// "Disabled" property should be serialized instead.
  1718. //if(this.axis != null && this.axis.IsSerializing())
  1719. //{
  1720. // if(!this.majorGridTick)
  1721. // {
  1722. // // Return default value to prevent serialization
  1723. // return true;
  1724. // }
  1725. //}
  1726. return enabled;
  1727. }
  1728. set
  1729. {
  1730. enabled = value;
  1731. enabledChanged = true;
  1732. this.Invalidate();
  1733. if (Axis != null)
  1734. Axis.CallOnModifing();
  1735. }
  1736. }
  1737. /// <summary>
  1738. /// Determines if Enabled property should be serialized.
  1739. /// </summary>
  1740. /// <returns></returns>
  1741. internal bool ShouldSerializeEnabled()
  1742. {
  1743. if (this.majorGridTick)
  1744. {
  1745. return !this.Enabled;
  1746. }
  1747. return this.Enabled;
  1748. }
  1749. /// <summary>
  1750. /// Gets or sets the reference to the Axis object
  1751. /// </summary>
  1752. internal Axis Axis
  1753. {
  1754. get { return _axis; }
  1755. set { _axis = value; }
  1756. }
  1757. #endregion
  1758. }
  1759. }