AxisConverters.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  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: Converters for the Axis object properties.
  6. //
  7. using System;
  8. using System.Collections;
  9. using System.ComponentModel;
  10. using System.Globalization;
  11. using System.Reflection;
  12. namespace FastReport.DataVisualization.Charting
  13. {
  14. /// <summary>
  15. /// Converts labels, grid and ticks start position to support dates format
  16. /// </summary>
  17. internal class AxisLabelDateValueConverter : DoubleConverter
  18. {
  19. #region Converter methods
  20. /// <summary>
  21. /// Convert Min and Max values to string if step type is set to one of the DateTime type
  22. /// </summary>
  23. /// <param name="context">Descriptor context.</param>
  24. /// <param name="culture">Culture information.</param>
  25. /// <param name="value">Value to convert.</param>
  26. /// <param name="destinationType">Convertion destination type.</param>
  27. /// <returns>Converted object.</returns>
  28. public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  29. {
  30. if (context != null && context.Instance != null)
  31. {
  32. // Convert to string
  33. if (destinationType == typeof(string))
  34. {
  35. DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
  36. double interval = 0;
  37. // Get IntervalType property using reflection
  38. PropertyInfo propertyInfo = context.Instance.GetType().GetProperty("IntervalType");
  39. if(propertyInfo != null)
  40. {
  41. intervalType = (DateTimeIntervalType)propertyInfo.GetValue(context.Instance, null);
  42. }
  43. // Get Interval property using reflection
  44. propertyInfo = context.Instance.GetType().GetProperty("Interval");
  45. if(propertyInfo != null)
  46. {
  47. interval = (double)propertyInfo.GetValue(context.Instance, null);
  48. }
  49. // Try to get interval information from the axis
  50. if(intervalType == DateTimeIntervalType.Auto)
  51. {
  52. // Get object's axis
  53. Axis axis = null;
  54. if(context.Instance is Axis)
  55. {
  56. axis = (Axis)context.Instance;
  57. }
  58. else
  59. {
  60. MethodInfo methodInfo = context.Instance.GetType().GetMethod("GetAxis");
  61. if(methodInfo != null)
  62. {
  63. // Get axis object
  64. axis = (Axis)methodInfo.Invoke(context.Instance, null);
  65. }
  66. }
  67. // Get axis value type
  68. if(axis != null)
  69. {
  70. intervalType = axis.GetAxisIntervalType();
  71. }
  72. }
  73. // Convert value to date/time string
  74. if(context.Instance.GetType() != typeof(StripLine) || interval == 0)
  75. {
  76. if(intervalType != DateTimeIntervalType.Number && intervalType != DateTimeIntervalType.Auto)
  77. {
  78. // Covert value to date/time
  79. if(intervalType < DateTimeIntervalType.Hours)
  80. {
  81. return DateTime.FromOADate((double)value).ToShortDateString();
  82. }
  83. return DateTime.FromOADate((double)value).ToString("g", System.Globalization.CultureInfo.CurrentCulture);
  84. }
  85. }
  86. }
  87. }
  88. return base.ConvertTo(context, culture, value, destinationType);
  89. }
  90. /// <summary>
  91. /// Convert Min and Max values from string if step type is set to one of the DateTime type
  92. /// </summary>
  93. /// <param name="context">Descriptor context.</param>
  94. /// <param name="culture">Culture information.</param>
  95. /// <param name="value">Value to convert from.</param>
  96. /// <returns>Converted object.</returns>
  97. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  98. {
  99. object result = null;
  100. bool convertFromDate = false;
  101. string stringValue = value as string;
  102. // If context interface provided check if we are dealing with DateTime values
  103. if (context != null && context.Instance != null)
  104. {
  105. DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
  106. // Get intervalType property using reflection
  107. PropertyInfo propertyInfo = context.Instance.GetType().GetProperty("intervalType");
  108. if(propertyInfo != null)
  109. {
  110. intervalType = (DateTimeIntervalType)propertyInfo.GetValue(context.Instance, null);
  111. }
  112. // Try to get interval information from the axis
  113. if(intervalType == DateTimeIntervalType.Auto)
  114. {
  115. // Get object's axis
  116. Axis axis = null;
  117. if(context.Instance is Axis)
  118. {
  119. axis = (Axis)context.Instance;
  120. }
  121. else
  122. {
  123. MethodInfo methodInfo = context.Instance.GetType().GetMethod("GetAxis");
  124. if(methodInfo != null)
  125. {
  126. // Get axis object
  127. axis = (Axis)methodInfo.Invoke(context.Instance, null);
  128. }
  129. }
  130. // Get axis value type
  131. if(axis != null)
  132. {
  133. intervalType = axis.GetAxisIntervalType();
  134. }
  135. }
  136. if (stringValue != null && intervalType != DateTimeIntervalType.Number && intervalType != DateTimeIntervalType.Auto)
  137. {
  138. convertFromDate = true;
  139. }
  140. }
  141. // Try to convert from double string
  142. try
  143. {
  144. result = base.ConvertFrom(context, culture, value);
  145. }
  146. catch (ArgumentException)
  147. {
  148. result = null;
  149. }
  150. catch (NotSupportedException)
  151. {
  152. result = null;
  153. }
  154. // Try to convert from date/time string
  155. if (stringValue != null && (convertFromDate || result == null))
  156. {
  157. DateTime valueAsDate;
  158. bool parseSucceed = DateTime.TryParse(stringValue, CultureInfo.InvariantCulture, DateTimeStyles.None, out valueAsDate);
  159. if (parseSucceed)
  160. {
  161. // Succeded converting from date format
  162. return valueAsDate.ToOADate();
  163. }
  164. }
  165. // Call base converter
  166. return base.ConvertFrom(context, culture, value);
  167. }
  168. #endregion
  169. }
  170. /// <summary>
  171. /// Converts crossing property of the axis.
  172. /// Possible values: double, date, "Auto", "Min", "Max"
  173. /// </summary>
  174. internal class AxisCrossingValueConverter : AxisMinMaxValueConverter
  175. {
  176. #region Converter methods
  177. /// <summary>
  178. /// Standart values supported - return true.
  179. /// </summary>
  180. /// <param name="context">Descriptor context.</param>
  181. /// <returns>Standard values supported.</returns>
  182. public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
  183. {
  184. return true;
  185. }
  186. /// <summary>
  187. /// Standart values are not exclusive - return false
  188. /// </summary>
  189. /// <param name="context">Descriptor context.</param>
  190. /// <returns>Non exclusive standard values.</returns>
  191. public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
  192. {
  193. return false;
  194. }
  195. /// <summary>
  196. /// Fill in the list of standart values.
  197. /// </summary>
  198. /// <param name="context">Descriptor context.</param>
  199. /// <returns>Standart values collection.</returns>
  200. public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
  201. {
  202. ArrayList values = new ArrayList();
  203. values.Add(Double.NaN);
  204. values.Add(Double.MinValue);
  205. values.Add(Double.MaxValue);
  206. return new StandardValuesCollection(values);
  207. }
  208. /// <summary>
  209. /// Convert crossing value to string.
  210. /// </summary>
  211. /// <param name="context">Descriptor context.</param>
  212. /// <param name="culture">Culture information.</param>
  213. /// <param name="value">Value to convert.</param>
  214. /// <param name="destinationType">Convertion destination type.</param>
  215. /// <returns>Converted object.</returns>
  216. public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  217. {
  218. double doubleValue = (double)value;
  219. if (destinationType == typeof(string))
  220. {
  221. if(Double.IsNaN(doubleValue))
  222. {
  223. return Constants.AutoValue;
  224. }
  225. else if(doubleValue == Double.MinValue)
  226. {
  227. return Constants.MinValue;
  228. }
  229. else if(doubleValue == Double.MaxValue)
  230. {
  231. return Constants.MaxValue;
  232. }
  233. }
  234. // Call base class
  235. return base.ConvertTo(context, culture, value, destinationType);
  236. }
  237. /// <summary>
  238. /// Convert crossing values from string
  239. /// </summary>
  240. /// <param name="context">Descriptor context.</param>
  241. /// <param name="culture">Culture information.</param>
  242. /// <param name="value">Value to convert from.</param>
  243. /// <returns>Converted object.</returns>
  244. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  245. {
  246. // If converting from string value
  247. string crossingValue = value as string;
  248. if (crossingValue != null)
  249. {
  250. if (String.Compare(crossingValue, Constants.AutoValue, StringComparison.OrdinalIgnoreCase) == 0)
  251. {
  252. return Double.NaN;
  253. }
  254. else if (String.Compare(crossingValue, Constants.MinValue, StringComparison.OrdinalIgnoreCase) == 0)
  255. {
  256. return Double.MinValue;
  257. }
  258. else if (String.Compare(crossingValue, Constants.MaxValue, StringComparison.OrdinalIgnoreCase) == 0)
  259. {
  260. return Double.MaxValue;
  261. }
  262. }
  263. // Call base converter
  264. return base.ConvertFrom(context, culture, value);
  265. }
  266. #endregion
  267. }
  268. /// <summary>
  269. /// Converts min and max properties of the axis depending on the values type
  270. /// </summary>
  271. internal class AxisMinMaxValueConverter : DoubleConverter
  272. {
  273. #region Converter methods
  274. /// <summary>
  275. /// Convert Min and Max values to string if step type is set to one of the DateTime type
  276. /// </summary>
  277. /// <param name="context">Descriptor context.</param>
  278. /// <param name="culture">Culture information.</param>
  279. /// <param name="value">Value to convert.</param>
  280. /// <param name="destinationType">Convertion destination type.</param>
  281. /// <returns>Converted object.</returns>
  282. public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  283. {
  284. if (context != null && context.Instance != null && context.Instance is Axis)
  285. {
  286. Axis axis = (Axis)context.Instance;
  287. if (destinationType == typeof(string))
  288. {
  289. string strValue = DoubleDateNanValueConverter.ConvertDateTimeToString(
  290. (double)value,
  291. axis.GetAxisValuesType(),
  292. axis.InternalIntervalType);
  293. if (strValue != null)
  294. return strValue;
  295. }
  296. }
  297. return base.ConvertTo(context, culture, value, destinationType);
  298. }
  299. /// <summary>
  300. /// Convert Min and Max values from string if step type is set to one of the DateTime type
  301. /// </summary>
  302. /// <param name="context">Descriptor context.</param>
  303. /// <param name="culture">Culture information.</param>
  304. /// <param name="value">Value to convert from.</param>
  305. /// <returns>Converted object.</returns>
  306. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  307. {
  308. object result = null;
  309. bool convertFromDate = false;
  310. string stringValue = value as string;
  311. // If context interface provided check if we are dealing with DateTime values
  312. if (context != null && context.Instance != null && context.Instance is Axis)
  313. {
  314. Axis axis = (Axis)context.Instance;
  315. if (stringValue != null)
  316. {
  317. if (axis.InternalIntervalType == DateTimeIntervalType.Auto)
  318. {
  319. if (axis.GetAxisValuesType() == ChartValueType.DateTime ||
  320. axis.GetAxisValuesType() == ChartValueType.Date ||
  321. axis.GetAxisValuesType() == ChartValueType.Time ||
  322. axis.GetAxisValuesType() == ChartValueType.DateTimeOffset)
  323. {
  324. convertFromDate = true;
  325. }
  326. }
  327. else
  328. {
  329. if (axis.InternalIntervalType != DateTimeIntervalType.Number)
  330. {
  331. convertFromDate = true;
  332. }
  333. }
  334. }
  335. }
  336. // Try to convert from double string
  337. try
  338. {
  339. result = base.ConvertFrom(context, culture, value);
  340. }
  341. catch (ArgumentException)
  342. {
  343. result = null;
  344. }
  345. catch (NotSupportedException)
  346. {
  347. result = null;
  348. }
  349. // Try to convert from date/time string
  350. if (stringValue != null && (convertFromDate || result == null))
  351. {
  352. DateTime valueAsDate;
  353. bool parseSucceed = DateTime.TryParse(stringValue, CultureInfo.CurrentCulture, DateTimeStyles.None, out valueAsDate);
  354. if (parseSucceed)
  355. {
  356. return valueAsDate.ToOADate();
  357. }
  358. }
  359. // Call base converter
  360. return base.ConvertFrom(context, culture, value);
  361. }
  362. #endregion
  363. }
  364. /// <summary>
  365. /// Converts maximum and minimum property of the axis.
  366. /// Possible values: double, date, "Auto",
  367. /// </summary>
  368. internal class AxisMinMaxAutoValueConverter : AxisMinMaxValueConverter
  369. {
  370. #region Converter methods
  371. /// <summary>
  372. /// Standart values supported - return true
  373. /// </summary>
  374. /// <param name="context">Descriptor context.</param>
  375. /// <returns>Standard values supported.</returns>
  376. public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
  377. {
  378. return true;
  379. }
  380. /// <summary>
  381. /// Standart values are not exclusive - return false
  382. /// </summary>
  383. /// <param name="context">Descriptor context.</param>
  384. /// <returns>Non exclusive standard values.</returns>
  385. public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
  386. {
  387. return false;
  388. }
  389. /// <summary>
  390. /// Fill in the list of data series names.
  391. /// </summary>
  392. /// <param name="context">Descriptor context.</param>
  393. public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
  394. {
  395. ArrayList values = new ArrayList();
  396. values.Add(Double.NaN);
  397. return new StandardValuesCollection(values);
  398. }
  399. /// <summary>
  400. /// Convert minimum or maximum value to string
  401. /// </summary>
  402. /// <param name="context">Descriptor context.</param>
  403. /// <param name="culture">Culture information.</param>
  404. /// <param name="value">Value to convert.</param>
  405. /// <param name="destinationType">Convertion destination type.</param>
  406. /// <returns>Converted object.</returns>
  407. public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  408. {
  409. double doubleValue = (double)value;
  410. if (destinationType == typeof(string))
  411. {
  412. if(Double.IsNaN(doubleValue))
  413. {
  414. return Constants.AutoValue;
  415. }
  416. }
  417. // Call base class
  418. return base.ConvertTo(context, culture, value, destinationType);
  419. }
  420. /// <summary>
  421. /// Convert minimum or maximum values from string
  422. /// </summary>
  423. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  424. {
  425. // If converting from string value
  426. string crossingValue = value as string;
  427. if (crossingValue != null)
  428. {
  429. if (String.Compare(crossingValue, Constants.AutoValue, StringComparison.OrdinalIgnoreCase) == 0)
  430. {
  431. return Double.NaN;
  432. }
  433. }
  434. // Call base converter
  435. return base.ConvertFrom(context, culture, value);
  436. }
  437. #endregion
  438. }
  439. /// <summary>
  440. /// Converts title angle property of the strip line
  441. /// Possible values: 0, 90, 180, 270
  442. /// </summary>
  443. internal class StripLineTitleAngleConverter : Int32Converter
  444. {
  445. #region Converter methods
  446. /// <summary>
  447. /// Standart values supported - return true
  448. /// </summary>
  449. /// <param name="context">Descriptor context.</param>
  450. /// <returns>Standard values supported.</returns>
  451. public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
  452. {
  453. return true;
  454. }
  455. /// <summary>
  456. /// Standart values are not exclusive - return false
  457. /// </summary>
  458. /// <param name="context">Descriptor context.</param>
  459. /// <returns>Non exclusive standard values.</returns>
  460. public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
  461. {
  462. return true;
  463. }
  464. /// <summary>
  465. /// Fill in the list of data series names.
  466. /// </summary>
  467. /// <param name="context">Descriptor context.</param>
  468. public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
  469. {
  470. ArrayList values = new ArrayList();
  471. values.Add(0);
  472. values.Add(90);
  473. values.Add(180);
  474. values.Add(270);
  475. return new StandardValuesCollection(values);
  476. }
  477. #endregion
  478. }
  479. /// <summary>
  480. /// Converts Interval and IntervalOffset properties of the axis
  481. /// </summary>
  482. internal class AxisIntervalValueConverter : DoubleConverter
  483. {
  484. #region Converter methods
  485. /// <summary>
  486. /// Inicates that "NotSet" option is available
  487. /// </summary>
  488. internal bool hideNotSet = true;
  489. /// <summary>
  490. /// Standart values supported - return true.
  491. /// </summary>
  492. /// <param name="context">Descriptor context.</param>
  493. /// <returns>Standard values supported.</returns>
  494. public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
  495. {
  496. return true;
  497. }
  498. /// <summary>
  499. /// Standart values are not exclusive - return false
  500. /// </summary>
  501. /// <param name="context">Descriptor context.</param>
  502. /// <returns>Non exclusive standard values.</returns>
  503. public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
  504. {
  505. return false;
  506. }
  507. /// <summary>
  508. /// Fill in the list of standart values.
  509. /// </summary>
  510. /// <param name="context">Descriptor context.</param>
  511. /// <returns>Standart values collection.</returns>
  512. public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
  513. {
  514. ArrayList values = new ArrayList();
  515. if(!hideNotSet)
  516. {
  517. values.Add(Double.NaN);
  518. }
  519. values.Add(0.0);
  520. return new StandardValuesCollection(values);
  521. }
  522. /// <summary>
  523. /// Convert crossing value to string.
  524. /// </summary>
  525. /// <param name="context">Descriptor context.</param>
  526. /// <param name="culture">Culture information.</param>
  527. /// <param name="value">Value to convert.</param>
  528. /// <param name="destinationType">Convertion destination type.</param>
  529. /// <returns>Converted object.</returns>
  530. public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
  531. {
  532. double doubleValue = (double)value;
  533. if (destinationType == typeof(string))
  534. {
  535. if(Double.IsNaN(doubleValue))
  536. {
  537. return Constants.NotSetValue;
  538. }
  539. else if(doubleValue == 0.0)
  540. {
  541. return Constants.AutoValue;
  542. }
  543. }
  544. // Call base class
  545. return base.ConvertTo(context, culture, value, destinationType);
  546. }
  547. /// <summary>
  548. /// Convert crossing values from string
  549. /// </summary>
  550. /// <param name="context">Descriptor context.</param>
  551. /// <param name="culture">Culture information.</param>
  552. /// <param name="value">Value to convert from.</param>
  553. /// <returns>Converted object.</returns>
  554. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  555. {
  556. // If converting from string value
  557. string crossingValue = value as string;
  558. if (crossingValue != null)
  559. {
  560. if (String.Compare(crossingValue, Constants.AutoValue, StringComparison.OrdinalIgnoreCase) == 0)
  561. {
  562. return 0.0;
  563. }
  564. else if (String.Compare(crossingValue, Constants.NotSetValue, StringComparison.OrdinalIgnoreCase) == 0)
  565. {
  566. return Double.NaN;
  567. }
  568. }
  569. // Call base converter
  570. return base.ConvertFrom(context, culture, value);
  571. }
  572. #endregion
  573. }
  574. /// <summary>
  575. /// Converts Interval and IntervalOffset properties of the label style, tick marks and grids
  576. /// </summary>
  577. internal class AxisElementIntervalValueConverter : AxisIntervalValueConverter
  578. {
  579. /// <summary>
  580. /// Show the NotSet option for interval
  581. /// </summary>
  582. public AxisElementIntervalValueConverter()
  583. {
  584. base.hideNotSet = false;
  585. }
  586. }
  587. }